mirror of
https://github.com/overte-org/overte.git
synced 2025-08-11 14:42:03 +02:00
compute priority of avatar and sort before update
This commit is contained in:
parent
09707217ec
commit
e363423992
3 changed files with 69 additions and 27 deletions
|
@ -127,6 +127,7 @@ Avatar::Avatar(RigPointer rig) :
|
||||||
_nameRectGeometryID = geometryCache->allocateID();
|
_nameRectGeometryID = geometryCache->allocateID();
|
||||||
_leftPointerGeometryID = geometryCache->allocateID();
|
_leftPointerGeometryID = geometryCache->allocateID();
|
||||||
_rightPointerGeometryID = geometryCache->allocateID();
|
_rightPointerGeometryID = geometryCache->allocateID();
|
||||||
|
_lastRenderUpdateTime = usecTimestampNow();
|
||||||
}
|
}
|
||||||
|
|
||||||
Avatar::~Avatar() {
|
Avatar::~Avatar() {
|
||||||
|
@ -320,10 +321,6 @@ void Avatar::simulate(float deltaTime, bool inView) {
|
||||||
PROFILE_RANGE(simulation, "updateJoints");
|
PROFILE_RANGE(simulation, "updateJoints");
|
||||||
uint64_t start = usecTimestampNow();
|
uint64_t start = usecTimestampNow();
|
||||||
if (inView) {
|
if (inView) {
|
||||||
// adebug BOOKMARK: can avoid copying duplicate joint data
|
|
||||||
// - can avoid some work when transform not changed (see SkeletonModel::simulate() and Model::setTranslation())
|
|
||||||
// - can maybe use _hasNewFoo instead of AvatarData::_jointDataVersion
|
|
||||||
// - can maybe avoid stuff if blendShapes haven't changed
|
|
||||||
_skeletonModel->getRig()->copyJointsFromJointData(_jointData);
|
_skeletonModel->getRig()->copyJointsFromJointData(_jointData);
|
||||||
_skeletonModel->simulate(deltaTime, _hasNewJointData);
|
_skeletonModel->simulate(deltaTime, _hasNewJointData);
|
||||||
locationChanged(); // joints changed, so if there are any children, update them.
|
locationChanged(); // joints changed, so if there are any children, update them.
|
||||||
|
|
|
@ -177,6 +177,9 @@ public:
|
||||||
glm::vec3 getUncachedRightPalmPosition() const;
|
glm::vec3 getUncachedRightPalmPosition() const;
|
||||||
glm::quat getUncachedRightPalmRotation() const;
|
glm::quat getUncachedRightPalmRotation() const;
|
||||||
|
|
||||||
|
uint64_t getLastRenderUpdateTime() const { return _lastRenderUpdateTime; }
|
||||||
|
void setLastRenderUpdateTime(uint64_t time) { _lastRenderUpdateTime = time; }
|
||||||
|
|
||||||
Q_INVOKABLE void setShouldDie();
|
Q_INVOKABLE void setShouldDie();
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
|
@ -259,6 +262,7 @@ protected:
|
||||||
void ensureInScene(AvatarSharedPointer self);
|
void ensureInScene(AvatarSharedPointer self);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
uint64_t _lastRenderUpdateTime { 0 };
|
||||||
int _leftPointerGeometryID { 0 };
|
int _leftPointerGeometryID { 0 };
|
||||||
int _rightPointerGeometryID { 0 };
|
int _rightPointerGeometryID { 0 };
|
||||||
int _nameRectGeometryID { 0 };
|
int _nameRectGeometryID { 0 };
|
||||||
|
|
|
@ -132,53 +132,94 @@ void AvatarManager::updateMyAvatar(float deltaTime) {
|
||||||
|
|
||||||
Q_LOGGING_CATEGORY(trace_simulation_avatar, "trace.simulation.avatar");
|
Q_LOGGING_CATEGORY(trace_simulation_avatar, "trace.simulation.avatar");
|
||||||
|
|
||||||
|
class AvatarPriority {
|
||||||
|
public:
|
||||||
|
AvatarPriority(AvatarSharedPointer a, float p) : avatar(a), priority(p) {}
|
||||||
|
AvatarSharedPointer avatar;
|
||||||
|
float priority;
|
||||||
|
// NOTE: we invert the less-than operator to sort high priorities to front
|
||||||
|
bool operator<(const AvatarPriority& other) const { return priority > other.priority; }
|
||||||
|
};
|
||||||
|
|
||||||
void AvatarManager::updateOtherAvatars(float deltaTime) {
|
void AvatarManager::updateOtherAvatars(float deltaTime) {
|
||||||
// lock the hash for read to check the size
|
// lock the hash for read to check the size
|
||||||
QReadLocker lock(&_hashLock);
|
QReadLocker lock(&_hashLock);
|
||||||
|
|
||||||
if (_avatarHash.size() < 2 && _avatarFades.isEmpty()) {
|
if (_avatarHash.size() < 2 && _avatarFades.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
lock.unlock();
|
lock.unlock();
|
||||||
|
|
||||||
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
|
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
|
||||||
PerformanceWarning warn(showWarnings, "Application::updateAvatars()");
|
PerformanceWarning warn(showWarnings, "Application::updateAvatars()");
|
||||||
|
|
||||||
PerformanceTimer perfTimer("otherAvatars");
|
PerformanceTimer perfTimer("otherAvatars");
|
||||||
render::PendingChanges pendingChanges;
|
|
||||||
|
|
||||||
// simulate avatars
|
auto avatarMap = getHashCopy();
|
||||||
auto hashCopy = getHashCopy();
|
QList<AvatarSharedPointer> avatarList = avatarMap.values();
|
||||||
|
uint64_t now = usecTimestampNow();
|
||||||
|
ViewFrustum cameraView;
|
||||||
|
qApp->copyDisplayViewFrustum(cameraView);
|
||||||
|
glm::vec3 frustumCenter = cameraView.getPosition();
|
||||||
|
|
||||||
uint64_t start = usecTimestampNow();
|
const float OUT_OF_VIEW_PENALTY = -10.0;
|
||||||
AvatarHash::iterator avatarIterator = hashCopy.begin();
|
|
||||||
while (avatarIterator != hashCopy.end()) {
|
|
||||||
auto avatar = std::static_pointer_cast<Avatar>(avatarIterator.value());
|
|
||||||
|
|
||||||
|
std::priority_queue<AvatarPriority> sortedAvatars;
|
||||||
|
for (int32_t i = 0; i < avatarList.size(); ++i) {
|
||||||
|
const auto& avatar = std::static_pointer_cast<Avatar>(avatarList.at(i));
|
||||||
if (avatar == _myAvatar || !avatar->isInitialized()) {
|
if (avatar == _myAvatar || !avatar->isInitialized()) {
|
||||||
// DO NOT update _myAvatar! Its update has already been done earlier in the main loop.
|
// DO NOT update _myAvatar! Its update has already been done earlier in the main loop.
|
||||||
// DO NOT update or fade out uninitialized Avatars
|
// DO NOT update or fade out uninitialized Avatars
|
||||||
++avatarIterator;
|
continue;
|
||||||
} else if (avatar->shouldDie()) {
|
|
||||||
removeAvatar(avatarIterator.key());
|
|
||||||
++avatarIterator;
|
|
||||||
} else {
|
|
||||||
avatar->ensureInScene(avatar);
|
|
||||||
const bool inView = true; // HACK
|
|
||||||
avatar->simulate(deltaTime, inView);
|
|
||||||
++avatarIterator;
|
|
||||||
|
|
||||||
avatar->updateRenderItem(pendingChanges);
|
|
||||||
}
|
}
|
||||||
|
if (avatar->shouldDie()) {
|
||||||
|
removeAvatar(avatar->getID());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// priority = weighted linear combination of:
|
||||||
|
// (a) apparentSize
|
||||||
|
// (b) proximity to center of view, and
|
||||||
|
// (c) time since last update
|
||||||
|
glm::vec3 avatarPosition = avatar->getPosition();
|
||||||
|
glm::vec3 offset = avatarPosition - frustumCenter;
|
||||||
|
float distance = glm::length(offset) + 0.001f; // add 1mm to avoid divide by zero
|
||||||
|
float radius = avatar->getBoundingRadius();
|
||||||
|
const glm::vec3& forward = cameraView.getDirection();
|
||||||
|
float apparentSize = radius / distance;
|
||||||
|
float cosineAngle = glm::length(offset - glm::dot(offset, forward) * forward) / distance;
|
||||||
|
float age = (float)(now - avatar->getLastRenderUpdateTime()) / (float)(USECS_PER_SECOND);
|
||||||
|
float priority = 2.0f * apparentSize + 0.25f * cosineAngle + age;
|
||||||
|
|
||||||
|
// decrement priority of avatars outside keyhole
|
||||||
|
if (distance > cameraView.getCenterRadius()) {
|
||||||
|
if (!cameraView.sphereIntersectsFrustum(avatarPosition, radius)) {
|
||||||
|
priority += OUT_OF_VIEW_PENALTY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sortedAvatars.push(AvatarPriority(avatar, priority));
|
||||||
|
}
|
||||||
|
|
||||||
|
render::PendingChanges pendingChanges;
|
||||||
|
const uint64_t AVATAR_RENDER_UPDATE_TIME_BUDGET = 2 * USECS_PER_MSEC;
|
||||||
|
uint64_t expiry = now + AVATAR_RENDER_UPDATE_TIME_BUDGET;
|
||||||
|
while (!sortedAvatars.empty()) {
|
||||||
|
const AvatarPriority& sortData = sortedAvatars.top();
|
||||||
|
const auto& avatar = std::static_pointer_cast<Avatar>(sortData.avatar);
|
||||||
|
avatar->ensureInScene(avatar);
|
||||||
|
const bool inView = sortData.priority > 0.5f * OUT_OF_VIEW_PENALTY;
|
||||||
|
avatar->simulate(deltaTime, inView);
|
||||||
|
if (expiry > usecTimestampNow()) {
|
||||||
|
avatar->updateRenderItem(pendingChanges);
|
||||||
|
avatar->setLastRenderUpdateTime(now);
|
||||||
|
}
|
||||||
|
sortedAvatars.pop();
|
||||||
}
|
}
|
||||||
qApp->getMain3DScene()->enqueuePendingChanges(pendingChanges);
|
qApp->getMain3DScene()->enqueuePendingChanges(pendingChanges);
|
||||||
|
|
||||||
// simulate avatar fades
|
|
||||||
simulateAvatarFades(deltaTime);
|
simulateAvatarFades(deltaTime);
|
||||||
|
|
||||||
PROFILE_COUNTER(simulation_avatar, "NumAvatarsPerSec",
|
//PROFILE_COUNTER(simulation_avatar, "NumAvatarsPerSec",
|
||||||
{ { "NumAvatarsPerSec", (float)(size() * USECS_PER_SECOND) / (float)(usecTimestampNow() - start) } });
|
// { { "NumAvatarsPerSec", (float)((size() - sortedAvatars.size()) * USECS_PER_SECOND) / (float)(usecTimestampNow() - now) } });
|
||||||
PROFILE_COUNTER(simulation_avatar, "NumJointsPerSec", { { "NumJointsPerSec", Avatar::getNumJointsProcessedPerSecond() } });
|
PROFILE_COUNTER(simulation_avatar, "NumJointsPerSec", { { "NumJointsPerSec", Avatar::getNumJointsProcessedPerSecond() } });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue