mirror of
https://github.com/overte-org/overte.git
synced 2025-08-07 02:04:26 +02:00
organize PrioritySortUtil differently
This commit is contained in:
parent
99b4283cbc
commit
55cc945c78
2 changed files with 94 additions and 72 deletions
|
@ -19,18 +19,18 @@
|
||||||
#include <QThreadPool>
|
#include <QThreadPool>
|
||||||
|
|
||||||
#include <shared/QtHelpers.h>
|
#include <shared/QtHelpers.h>
|
||||||
#include <ColorUtils.h>
|
|
||||||
#include <AbstractScriptingServicesInterface.h>
|
#include <AbstractScriptingServicesInterface.h>
|
||||||
#include <AbstractViewStateInterface.h>
|
#include <AbstractViewStateInterface.h>
|
||||||
|
#include <AddressManager.h>
|
||||||
|
#include <ColorUtils.h>
|
||||||
#include <Model.h>
|
#include <Model.h>
|
||||||
#include <NetworkAccessManager.h>
|
#include <NetworkAccessManager.h>
|
||||||
#include <PerfStat.h>
|
#include <PerfStat.h>
|
||||||
|
#include <PrioritySortUtil.h>
|
||||||
|
#include <Rig.h>
|
||||||
#include <SceneScriptingInterface.h>
|
#include <SceneScriptingInterface.h>
|
||||||
#include <ScriptEngine.h>
|
#include <ScriptEngine.h>
|
||||||
#include <AddressManager.h>
|
|
||||||
#include <Rig.h>
|
|
||||||
#include <EntitySimulation.h>
|
#include <EntitySimulation.h>
|
||||||
#include <AddressManager.h>
|
|
||||||
#include <ZoneRenderer.h>
|
#include <ZoneRenderer.h>
|
||||||
|
|
||||||
#include "EntitiesRendererLogging.h"
|
#include "EntitiesRendererLogging.h"
|
||||||
|
@ -38,22 +38,6 @@
|
||||||
|
|
||||||
#include "RenderableWebEntityItem.h"
|
#include "RenderableWebEntityItem.h"
|
||||||
|
|
||||||
// implement these methods BEFORE including PrioritySortUtil.h
|
|
||||||
namespace PrioritySortUtil {
|
|
||||||
glm::vec3 getObjectPosition(const EntityRendererPointer& object) {
|
|
||||||
return object->getEntity()->getPosition();
|
|
||||||
}
|
|
||||||
|
|
||||||
float getObjectRadius(const EntityRendererPointer& object) {
|
|
||||||
return 0.5f * object->getEntity()->getQueryAACube().getScale();
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t getObjectAge(const EntityRendererPointer& object) {
|
|
||||||
return object->getUpdateTime();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#include <PrioritySortUtil.h>
|
|
||||||
|
|
||||||
size_t std::hash<EntityItemID>::operator()(const EntityItemID& id) const { return qHash(id); }
|
size_t std::hash<EntityItemID>::operator()(const EntityItemID& id) const { return qHash(id); }
|
||||||
std::function<bool()> EntityTreeRenderer::_entitiesShouldFadeFunction;
|
std::function<bool()> EntityTreeRenderer::_entitiesShouldFadeFunction;
|
||||||
|
|
||||||
|
@ -353,17 +337,30 @@ void EntityTreeRenderer::updateChangedEntities(const render::ScenePointer& scene
|
||||||
} else {
|
} else {
|
||||||
// we expect the cost to updating all renderables to exceed available time budget
|
// we expect the cost to updating all renderables to exceed available time budget
|
||||||
// so we first sort by priority and update in order until out of time
|
// so we first sort by priority and update in order until out of time
|
||||||
|
|
||||||
|
// as per the instructions in PriortySortUtil we first derive from PrioritySortUtil::Prioritizable
|
||||||
|
class PrioritizableRenderer: public PrioritySortUtil::Prioritizable {
|
||||||
|
public:
|
||||||
|
PrioritizableRenderer(const EntityRendererPointer& renderer) : _renderer(renderer) { }
|
||||||
|
glm::vec3 getPosition() const override { return _renderer->getEntity()->getPosition(); }
|
||||||
|
float getRadius() const override { return 0.5f * _renderer->getEntity()->getQueryAACube().getScale(); }
|
||||||
|
uint64_t getTimestamp() const override { return _renderer->getUpdateTime(); }
|
||||||
|
private:
|
||||||
|
const EntityRendererPointer& _renderer;
|
||||||
|
};
|
||||||
|
|
||||||
|
// prioritize and sort the renderables
|
||||||
uint64_t sortStart = usecTimestampNow();
|
uint64_t sortStart = usecTimestampNow();
|
||||||
using SortableRenderer = PrioritySortUtil::Sortable<EntityRendererPointer>;
|
using SortableRenderer = PrioritySortUtil::Sortable<EntityRendererPointer>;
|
||||||
std::priority_queue< SortableRenderer > sortedRenderables;
|
std::priority_queue< SortableRenderer > sortedRenderables;
|
||||||
{
|
{
|
||||||
PROFILE_RANGE_EX(simulation_physics, "SortRenderables", 0xffff00ff, (uint64_t)_renderablesToUpdate.size());
|
PROFILE_RANGE_EX(simulation_physics, "SortRenderables", 0xffff00ff, (uint64_t)_renderablesToUpdate.size());
|
||||||
PrioritySortUtil::PriorityCalculator<EntityRendererPointer> priorityCalculator(view);
|
PrioritySortUtil::Prioritizer<EntityRendererPointer> prioritizer(view);
|
||||||
std::unordered_map<EntityItemID, EntityRendererPointer>::iterator itr = _renderablesToUpdate.begin();
|
std::unordered_map<EntityItemID, EntityRendererPointer>::iterator itr = _renderablesToUpdate.begin();
|
||||||
while (itr != _renderablesToUpdate.end()) {
|
while (itr != _renderablesToUpdate.end()) {
|
||||||
float priority = priorityCalculator.computePriority(itr->second);
|
float priority = prioritizer.computePriority(PrioritizableRenderer(itr->second));
|
||||||
SortableRenderer entry(itr->second, priority);
|
//SortableRenderer entry(itr->second, priority);
|
||||||
sortedRenderables.push(entry);
|
sortedRenderables.push(SortableRenderer(itr->second, priority));
|
||||||
++itr;
|
++itr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -380,10 +377,11 @@ void EntityTreeRenderer::updateChangedEntities(const render::ScenePointer& scene
|
||||||
}
|
}
|
||||||
uint64_t expiry = updateStart + timeBudget;
|
uint64_t expiry = updateStart + timeBudget;
|
||||||
|
|
||||||
|
// process the sorted renderables
|
||||||
std::unordered_map<EntityItemID, EntityRendererPointer>::iterator itr;
|
std::unordered_map<EntityItemID, EntityRendererPointer>::iterator itr;
|
||||||
size_t numSorted = sortedRenderables.size();
|
size_t numSorted = sortedRenderables.size();
|
||||||
while (!sortedRenderables.empty() && usecTimestampNow() < expiry) {
|
while (!sortedRenderables.empty() && usecTimestampNow() < expiry) {
|
||||||
const EntityRendererPointer& renderer = sortedRenderables.top().getObject();
|
const EntityRendererPointer& renderer = sortedRenderables.top().getThing();
|
||||||
renderer->updateInScene(scene, transaction);
|
renderer->updateInScene(scene, transaction);
|
||||||
_renderablesToUpdate.erase(renderer->getEntity()->getID());
|
_renderablesToUpdate.erase(renderer->getEntity()->getID());
|
||||||
sortedRenderables.pop();
|
sortedRenderables.pop();
|
||||||
|
|
|
@ -14,59 +14,82 @@
|
||||||
#include <glm/glm.hpp>
|
#include <glm/glm.hpp>
|
||||||
#include "ViewFrustum.h"
|
#include "ViewFrustum.h"
|
||||||
|
|
||||||
namespace PrioritySortUtil {
|
/* PrioritySortUtil is a helper for sorting 3D things relative to a ViewFrustum. To use:
|
||||||
// PrioritySortUtil is a helper template for sorting 3D objects relative to a ViewFrustum.
|
|
||||||
// To use this utility:
|
|
||||||
//
|
|
||||||
// (1) Declare and implement the following methods for your "object" type T:
|
|
||||||
//
|
|
||||||
// glm::vec3 PrioritySortUtil<typename T>::getObjectPosition(const T&);
|
|
||||||
// float PrioritySortUtil<typename T>::getObjectRadius(const T&);
|
|
||||||
// uint64_t PrioritySortUtil<typename T>::getObjectAge(const T&);
|
|
||||||
//
|
|
||||||
// (2) Below the implementation in (1):
|
|
||||||
//
|
|
||||||
// #include <PrioritySortUtil.h>
|
|
||||||
//
|
|
||||||
// (3) Create a PriorityCalculator instance:
|
|
||||||
//
|
|
||||||
// PrioritySortUtil::PriorityCalculator<T> calculator(viewFrustum);
|
|
||||||
//
|
|
||||||
// (4) Loop over your objects and insert the into a priority_queue:
|
|
||||||
//
|
|
||||||
// std::priority_queue< PrioritySortUtil::Sortable<T> > sortedObjects;
|
|
||||||
// for (T obj in objects) {
|
|
||||||
// float priority = calculator.computePriority(obj);
|
|
||||||
// PrioritySortUtil::Sortable<T> entry(obj, priority);
|
|
||||||
// sortedObjects.push(entry);
|
|
||||||
// }
|
|
||||||
|
|
||||||
template <typename T>
|
(1) Derive a class from pure-virtual PrioritySortUtil::Prioritizable
|
||||||
class Sortable {
|
that wraps the Thing you want to prioritize and sort:
|
||||||
public:
|
|
||||||
Sortable(const T& object, float sortPriority) : _object(object), _priority(sortPriority) {}
|
class PrioritizableThing : public PrioritySortUtil::Prioritizable {
|
||||||
const T& getObject() const { return _object; }
|
public:
|
||||||
void setPriority(float priority) { _priority = priority; }
|
PrioritizableThing(const Thing& thing) : _thing(thing) {}
|
||||||
bool operator<(const Sortable& other) const { return _priority < other._priority; }
|
glm::vec3 getPosition() const override { return _thing.getPosition(); }
|
||||||
private:
|
float getRadius() const const override { return _thing.getBoundingRadius(); }
|
||||||
T _object;
|
uint64_t getTimestamp() const override { return _thing.getLastUpdated(); }
|
||||||
float _priority;
|
private:
|
||||||
};
|
// Yes really: the data member is a const reference!
|
||||||
|
// PrioritizableThing only needs enough scope to compute a priority.
|
||||||
|
const Thing& _thing;
|
||||||
|
}
|
||||||
|
|
||||||
|
(2) Loop over your things and insert each into a priority_queue:
|
||||||
|
|
||||||
|
PrioritySortUtil::Prioritizer prioritizer(viewFrustum);
|
||||||
|
std::priority_queue< PrioritySortUtil::Sortable<Thing> > sortedThings;
|
||||||
|
for (thing in things) {
|
||||||
|
float priority = prioritizer.computePriority(PrioritySortUtil::PrioritizableThing(thing));
|
||||||
|
sortedThings.push(PrioritySortUtil::Sortable<Thing> entry(thing, priority));
|
||||||
|
}
|
||||||
|
|
||||||
|
(4) Loop over your priority queue and do timeboxed work:
|
||||||
|
|
||||||
|
uint64_t cutoffTime = usecTimestampNow() + TIME_BUDGET;
|
||||||
|
while (!sortedThings.empty()) {
|
||||||
|
const Thing& thing = sortedThings.top();
|
||||||
|
// ...do work on thing...
|
||||||
|
sortedThings.pop();
|
||||||
|
if (usecTimestampNow() > cutoffTime) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace PrioritySortUtil {
|
||||||
|
|
||||||
constexpr float DEFAULT_ANGULAR_COEF { 1.0f };
|
constexpr float DEFAULT_ANGULAR_COEF { 1.0f };
|
||||||
constexpr float DEFAULT_CENTER_COEF { 0.5f };
|
constexpr float DEFAULT_CENTER_COEF { 0.5f };
|
||||||
constexpr float DEFAULT_AGE_COEF { 0.25f / (float)(USECS_PER_SECOND) };
|
constexpr float DEFAULT_AGE_COEF { 0.25f / (float)(USECS_PER_SECOND) };
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
class PriorityCalculator {
|
class Sortable {
|
||||||
public:
|
public:
|
||||||
PriorityCalculator() = delete;
|
Sortable(const T& thing, float sortPriority) : _thing(thing), _priority(sortPriority) {}
|
||||||
|
const T& getThing() const { return _thing; }
|
||||||
|
void setPriority(float priority) { _priority = priority; }
|
||||||
|
bool operator<(const Sortable& other) const { return _priority < other._priority; }
|
||||||
|
private:
|
||||||
|
T _thing;
|
||||||
|
float _priority;
|
||||||
|
};
|
||||||
|
|
||||||
PriorityCalculator(const ViewFrustum& view) : _view(view) {
|
// Prioritizable isn't a template because templates can't have pure-virtual methods.
|
||||||
|
class Prioritizable {
|
||||||
|
public:
|
||||||
|
virtual glm::vec3 getPosition() const = 0;
|
||||||
|
virtual float getRadius() const = 0;
|
||||||
|
virtual uint64_t getTimestamp() const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
class Prioritizer {
|
||||||
|
public:
|
||||||
|
Prioritizer() = delete;
|
||||||
|
|
||||||
|
Prioritizer(const ViewFrustum& view) : _view(view) {
|
||||||
cacheView();
|
cacheView();
|
||||||
}
|
}
|
||||||
|
|
||||||
PriorityCalculator(const ViewFrustum& view, float angularWeight, float centerWeight, float ageWeight)
|
Prioritizer(const ViewFrustum& view, float angularWeight, float centerWeight, float ageWeight)
|
||||||
: _view(view), _angularWeight(angularWeight), _centerWeight(centerWeight), _ageWeight(ageWeight)
|
: _view(view), _angularWeight(angularWeight), _centerWeight(centerWeight), _ageWeight(ageWeight)
|
||||||
{
|
{
|
||||||
cacheView();
|
cacheView();
|
||||||
|
@ -80,21 +103,21 @@ namespace PrioritySortUtil {
|
||||||
_ageWeight = ageWeight;
|
_ageWeight = ageWeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
float computePriority(T& object) const {
|
float computePriority(const Prioritizable& prioritizableThing) const {
|
||||||
// priority = weighted linear combination of multiple values:
|
// priority = weighted linear combination of multiple values:
|
||||||
// (a) angular size
|
// (a) angular size
|
||||||
// (b) proximity to center of view
|
// (b) proximity to center of view
|
||||||
// (c) time since last update
|
// (c) time since last update
|
||||||
// where the relative "weights" are tuned to scale the contributing values into units of "priority".
|
// where the relative "weights" are tuned to scale the contributing values into units of "priority".
|
||||||
|
|
||||||
glm::vec3 position = PrioritySortUtil::getObjectPosition(object);
|
glm::vec3 position = prioritizableThing.getPosition();
|
||||||
glm::vec3 offset = position - _viewPosition;
|
glm::vec3 offset = position - _viewPosition;
|
||||||
float distance = glm::length(offset) + 0.001f; // add 1mm to avoid divide by zero
|
float distance = glm::length(offset) + 0.001f; // add 1mm to avoid divide by zero
|
||||||
float radius = PrioritySortUtil::getObjectRadius(object);
|
float radius = prioritizableThing.getRadius();
|
||||||
|
|
||||||
float priority = _angularWeight * (radius / distance)
|
float priority = _angularWeight * (radius / distance)
|
||||||
+ _centerWeight * (glm::dot(offset, _viewForward) / distance)
|
+ _centerWeight * (glm::dot(offset, _viewForward) / distance)
|
||||||
+ _ageWeight * (float)(usecTimestampNow() - PrioritySortUtil::getObjectAge(object));
|
+ _ageWeight * (float)(usecTimestampNow() - prioritizableThing.getTimestamp());
|
||||||
|
|
||||||
// decrement priority of things outside keyhole
|
// decrement priority of things outside keyhole
|
||||||
if (distance - radius > _viewRadius) {
|
if (distance - radius > _viewRadius) {
|
||||||
|
@ -108,7 +131,7 @@ namespace PrioritySortUtil {
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void cacheView() {
|
void cacheView() {
|
||||||
// assuming we'll prioritize many objects: cache these values
|
// assuming we'll prioritize many things: cache these values
|
||||||
_viewPosition = _view.getPosition();
|
_viewPosition = _view.getPosition();
|
||||||
_viewForward = _view.getDirection();
|
_viewForward = _view.getDirection();
|
||||||
_viewRadius = _view.getCenterRadius();
|
_viewRadius = _view.getCenterRadius();
|
||||||
|
@ -122,6 +145,7 @@ namespace PrioritySortUtil {
|
||||||
float _centerWeight { DEFAULT_CENTER_COEF };
|
float _centerWeight { DEFAULT_CENTER_COEF };
|
||||||
float _ageWeight { DEFAULT_AGE_COEF };
|
float _ageWeight { DEFAULT_AGE_COEF };
|
||||||
};
|
};
|
||||||
}
|
} // namespace PrioritySortUtil
|
||||||
|
|
||||||
#endif // hifi_PrioritySortUtil_h
|
#endif // hifi_PrioritySortUtil_h
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue