fix avatar scale animation and avatar render debug

This commit is contained in:
Andrew Meadows 2017-04-06 09:40:24 -07:00
parent 40e223cb82
commit 662c34c266
8 changed files with 117 additions and 70 deletions

View file

@ -192,6 +192,7 @@ void Avatar::animateScaleChanges(float deltaTime) {
_isAnimatingScale = false;
}
setScale(glm::vec3(animatedScale)); // avatar scale is uniform
_hasNewJointData = true;
// TODO: rebuilding the shape constantly is somehwat expensive.
// We should only rebuild after significant change.
@ -200,8 +201,12 @@ void Avatar::animateScaleChanges(float deltaTime) {
}
void Avatar::setTargetScale(float targetScale) {
AvatarData::setTargetScale(targetScale);
_isAnimatingScale = true;
float newValue = glm::clamp(targetScale, MIN_AVATAR_SCALE, MAX_AVATAR_SCALE);
if (_targetScale != newValue) {
_targetScale = newValue;
_scaleChanged = usecTimestampNow();
_isAnimatingScale = true;
}
}
void Avatar::updateAvatarEntities() {

View file

@ -285,6 +285,7 @@ protected:
void addToScene(AvatarSharedPointer self);
void ensureInScene(AvatarSharedPointer self);
bool isInScene() const { return render::Item::isValidID(_renderItemID); }
// Some rate tracking support
RateCounter<> _simulationRate;

View file

@ -100,15 +100,16 @@ void AvatarManager::init() {
_avatarHash.insert(MY_AVATAR_KEY, _myAvatar);
}
_shouldRender = DependencyManager::get<SceneScriptingInterface>()->shouldRenderAvatars();
connect(DependencyManager::get<SceneScriptingInterface>().data(), &SceneScriptingInterface::shouldRenderAvatarsChanged,
this, &AvatarManager::updateAvatarRenderStatus, Qt::QueuedConnection);
render::ScenePointer scene = qApp->getMain3DScene();
render::Transaction transaction;
if (DependencyManager::get<SceneScriptingInterface>()->shouldRenderAvatars()) {
if (_shouldRender) {
render::ScenePointer scene = qApp->getMain3DScene();
render::Transaction transaction;
_myAvatar->addToScene(_myAvatar, scene, transaction);
scene->enqueueTransaction(transaction);
}
scene->enqueueTransaction(transaction);
}
void AvatarManager::updateMyAvatar(float deltaTime) {
@ -181,30 +182,24 @@ void AvatarManager::updateOtherAvatars(float deltaTime) {
// DO NOT update or fade out uninitialized Avatars
return true; // ignore it
}
if (avatar->shouldDie()) {
removeAvatar(avatar->getID());
return true; // ignore it
}
if (avatar->isDead()) {
return true; // ignore it
}
return false;
});
render::Transaction transaction;
uint64_t startTime = usecTimestampNow();
const uint64_t UPDATE_BUDGET = 2000; // usec
uint64_t updateExpiry = startTime + UPDATE_BUDGET;
int numAvatarsUpdated = 0;
int numAVatarsNotUpdated = 0;
render::Transaction transaction;
while (!sortedAvatars.empty()) {
const AvatarPriority& sortData = sortedAvatars.top();
const auto& avatar = std::static_pointer_cast<Avatar>(sortData.avatar);
// for ALL avatars...
avatar->ensureInScene(avatar);
if (_shouldRender) {
avatar->ensureInScene(avatar);
}
if (!avatar->getMotionState()) {
ShapeInfo shapeInfo;
avatar->computeShapeInfo(shapeInfo);
@ -218,6 +213,10 @@ void AvatarManager::updateOtherAvatars(float deltaTime) {
}
}
avatar->animateScaleChanges(deltaTime);
if (avatar->shouldDie()) {
avatar->die();
removeAvatar(avatar->getID());
}
const float OUT_OF_VIEW_THRESHOLD = 0.5f * AvatarData::OUT_OF_VIEW_PENALTY;
uint64_t now = usecTimestampNow();
@ -259,10 +258,21 @@ void AvatarManager::updateOtherAvatars(float deltaTime) {
sortedAvatars.pop();
}
if (_shouldRender) {
QVector<AvatarSharedPointer>::iterator itr = _avatarsToFade.begin();
while (itr != _avatarsToFade.end() && usecTimestampNow() > updateExpiry) {
auto avatar = std::static_pointer_cast<Avatar>(*itr);
avatar->animateScaleChanges(deltaTime);
avatar->simulate(deltaTime, true);
avatar->updateRenderItem(transaction);
++itr;
}
qApp->getMain3DScene()->enqueueTransaction(transaction);
}
_avatarSimulationTime = (float)(usecTimestampNow() - startTime) / (float)USECS_PER_MSEC;
_numAvatarsUpdated = numAvatarsUpdated;
_numAvatarsNotUpdated = numAVatarsNotUpdated;
qApp->getMain3DScene()->enqueueTransaction(transaction);
simulateAvatarFades(deltaTime);
}
@ -277,38 +287,68 @@ void AvatarManager::postUpdate(float deltaTime) {
}
void AvatarManager::simulateAvatarFades(float deltaTime) {
QVector<AvatarSharedPointer>::iterator fadingIterator = _avatarsToFade.begin();
QVector<AvatarSharedPointer>::iterator itr = _avatarsToFade.begin();
const float SHRINK_RATE = 0.15f;
const float MIN_FADE_SCALE = MIN_AVATAR_SCALE;
render::ScenePointer scene = qApp->getMain3DScene();
render::Transaction transaction;
while (fadingIterator != _avatarsToFade.end()) {
auto avatar = std::static_pointer_cast<Avatar>(*fadingIterator);
while (itr != _avatarsToFade.end()) {
auto avatar = std::static_pointer_cast<Avatar>(*itr);
avatar->setTargetScale(avatar->getUniformScale() * SHRINK_RATE);
avatar->animateScaleChanges(deltaTime);
if (avatar->getTargetScale() <= MIN_FADE_SCALE) {
avatar->removeFromScene(*fadingIterator, scene, transaction);
// fading to zero is such a rare event we push unique transaction for each one
removeAvatar(avatar->getID());
if (avatar->isInScene()) {
render::ScenePointer scene = qApp->getMain3DScene();
render::Transaction transaction;
avatar->removeFromScene(*itr, scene, transaction);
scene->enqueueTransaction(transaction);
}
// only remove from _avatarsToFade if we're sure its motionState has been removed from PhysicsEngine
if (_motionStatesToRemoveFromPhysics.empty()) {
fadingIterator = _avatarsToFade.erase(fadingIterator);
itr = _avatarsToFade.erase(itr);
} else {
++fadingIterator;
++itr;
}
} else {
const bool inView = true; // HACK
avatar->simulate(deltaTime, inView);
++fadingIterator;
++itr;
}
}
scene->enqueueTransaction(transaction);
}
AvatarSharedPointer AvatarManager::newSharedAvatar() {
std::shared_ptr<Avatar> avatar = std::make_shared<Avatar>(std::make_shared<Rig>());
avatar->addToScene(avatar);
return avatar;
return std::make_shared<Avatar>(std::make_shared<Rig>());
}
void AvatarManager::processAvatarDataPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer sendingNode) {
PerformanceTimer perfTimer("receiveAvatar");
// enumerate over all of the avatars in this packet
// only add them if mixerWeakPointer points to something (meaning that mixer is still around)
while (message->getBytesLeftToRead()) {
AvatarSharedPointer avatarData = parseAvatarData(message, sendingNode);
if (avatarData) {
auto avatar = std::static_pointer_cast<Avatar>(avatarData);
if (avatar->isInScene()) {
if (!_shouldRender) {
// rare transition so we process pending changes immediately
render::ScenePointer scene = qApp->getMain3DScene();
render::Transaction transaction;
avatar->removeFromScene(avatar, scene, transaction);
scene->enqueueTransaction(transaction);
}
} else if (_shouldRender) {
// very rare transition so we process pending changes immediately
render::ScenePointer scene = qApp->getMain3DScene();
render::Transaction transaction;
avatar->addToScene(avatar, scene, transaction);
scene->enqueueTransaction(transaction);
}
}
}
}
void AvatarManager::handleRemovedAvatar(const AvatarSharedPointer& removedAvatar, KillAvatarReason removalReason) {
@ -458,26 +498,23 @@ void AvatarManager::handleCollisionEvents(const CollisionEvents& collisionEvents
}
void AvatarManager::updateAvatarRenderStatus(bool shouldRenderAvatars) {
if (DependencyManager::get<SceneScriptingInterface>()->shouldRenderAvatars()) {
_shouldRender = shouldRenderAvatars;
render::ScenePointer scene = qApp->getMain3DScene();
render::Transaction transaction;
if (_shouldRender) {
for (auto avatarData : _avatarHash) {
auto avatar = std::static_pointer_cast<Avatar>(avatarData);
render::ScenePointer scene = qApp->getMain3DScene();
render::Transaction transaction;
avatar->addToScene(avatar, scene, transaction);
scene->enqueueTransaction(transaction);
}
} else {
for (auto avatarData : _avatarHash) {
auto avatar = std::static_pointer_cast<Avatar>(avatarData);
render::ScenePointer scene = qApp->getMain3DScene();
render::Transaction transaction;
avatar->removeFromScene(avatar, scene, transaction);
scene->enqueueTransaction(transaction);
}
}
scene->enqueueTransaction(transaction);
}
AvatarSharedPointer AvatarManager::getAvatarBySessionID(const QUuid& sessionID) const {
if (sessionID == AVATAR_SELF_ID || sessionID == _myAvatar->getSessionUUID()) {
return _myAvatar;

View file

@ -91,6 +91,9 @@ public slots:
void setShouldShowReceiveStats(bool shouldShowReceiveStats) { _shouldShowReceiveStats = shouldShowReceiveStats; }
void updateAvatarRenderStatus(bool shouldRenderAvatars);
protected slots:
void processAvatarDataPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer sendingNode) override;
private:
explicit AvatarManager(QObject* parent = 0);
explicit AvatarManager(const AvatarManager& other);
@ -100,12 +103,6 @@ private:
AvatarSharedPointer newSharedAvatar() override;
void handleRemovedAvatar(const AvatarSharedPointer& removedAvatar, KillAvatarReason removalReason = KillAvatarReason::NoReason) override;
/* TODO: maintain these lists
QVector<AvatarSharedPointer> _avatarsToRemoveFromScene;
QVector<AvatarSharedPointer> _avatarsToAddToScene;
QVector<AvatarSharedPointer> _avatarsToRemoveFromPhysicsEngine;
QVector<AvatarSharedPointer> _avatarsToAddToPhysicsEngine;
*/
QVector<AvatarSharedPointer> _avatarsToFade;
SetOfAvatarMotionStates _motionStatesThatMightUpdate;
@ -125,6 +122,7 @@ private:
int _numAvatarsUpdated { 0 };
int _numAvatarsNotUpdated { 0 };
float _avatarSimulationTime { 0.0f };
bool _shouldRender { true };
};
Q_DECLARE_METATYPE(AvatarManager::LocalLight)

View file

@ -54,6 +54,7 @@
#include "DebugDraw.h"
#include "EntityEditPacketSender.h"
#include "MovingEntitiesOperator.h"
#include "SceneScriptingInterface.h"
using namespace std;
@ -1634,7 +1635,7 @@ void MyAvatar::postUpdate(float deltaTime) {
Avatar::postUpdate(deltaTime);
render::ScenePointer scene = qApp->getMain3DScene();
if (_skeletonModel->initWhenReady(scene)) {
if (DependencyManager::get<SceneScriptingInterface>()->shouldRenderAvatars() && _skeletonModel->initWhenReady(scene)) {
initHeadBones();
_skeletonModel->setCauterizeBoneSet(_headBoneSet);
_fstAnimGraphOverrideUrl = _skeletonModel->getGeometry()->getAnimGraphOverrideUrl();

View file

@ -123,6 +123,7 @@ void AvatarData::setTargetScale(float targetScale) {
if (_targetScale != newValue) {
_targetScale = newValue;
_scaleChanged = usecTimestampNow();
_avatarScaleChanged = _scaleChanged;
}
}

View file

@ -80,13 +80,10 @@ AvatarSharedPointer AvatarHashMap::addAvatar(const QUuid& sessionUUID, const QWe
AvatarSharedPointer AvatarHashMap::newOrExistingAvatar(const QUuid& sessionUUID, const QWeakPointer<Node>& mixerWeakPointer) {
QWriteLocker locker(&_hashLock);
auto avatar = _avatarHash.value(sessionUUID);
if (!avatar) {
avatar = addAvatar(sessionUUID, mixerWeakPointer);
}
return avatar;
}
@ -103,27 +100,33 @@ void AvatarHashMap::processAvatarDataPacket(QSharedPointer<ReceivedMessage> mess
// enumerate over all of the avatars in this packet
// only add them if mixerWeakPointer points to something (meaning that mixer is still around)
while (message->getBytesLeftToRead()) {
QUuid sessionUUID = QUuid::fromRfc4122(message->readWithoutCopy(NUM_BYTES_RFC4122_UUID));
parseAvatarData(message, sendingNode);
}
}
int positionBeforeRead = message->getPosition();
AvatarSharedPointer AvatarHashMap::parseAvatarData(QSharedPointer<ReceivedMessage> message, SharedNodePointer sendingNode) {
QUuid sessionUUID = QUuid::fromRfc4122(message->readWithoutCopy(NUM_BYTES_RFC4122_UUID));
QByteArray byteArray = message->readWithoutCopy(message->getBytesLeftToRead());
int positionBeforeRead = message->getPosition();
// make sure this isn't our own avatar data or for a previously ignored node
auto nodeList = DependencyManager::get<NodeList>();
QByteArray byteArray = message->readWithoutCopy(message->getBytesLeftToRead());
if (sessionUUID != _lastOwnerSessionUUID && (!nodeList->isIgnoringNode(sessionUUID) || nodeList->getRequestsDomainListData())) {
auto avatar = newOrExistingAvatar(sessionUUID, sendingNode);
// make sure this isn't our own avatar data or for a previously ignored node
auto nodeList = DependencyManager::get<NodeList>();
// have the matching (or new) avatar parse the data from the packet
int bytesRead = avatar->parseDataFromBuffer(byteArray);
message->seek(positionBeforeRead + bytesRead);
} else {
// create a dummy AvatarData class to throw this data on the ground
AvatarData dummyData;
int bytesRead = dummyData.parseDataFromBuffer(byteArray);
message->seek(positionBeforeRead + bytesRead);
}
if (sessionUUID != _lastOwnerSessionUUID && (!nodeList->isIgnoringNode(sessionUUID) || nodeList->getRequestsDomainListData())) {
auto avatar = newOrExistingAvatar(sessionUUID, sendingNode);
// have the matching (or new) avatar parse the data from the packet
int bytesRead = avatar->parseDataFromBuffer(byteArray);
message->seek(positionBeforeRead + bytesRead);
return avatar;
} else {
// create a dummy AvatarData class to throw this data on the ground
AvatarData dummyData;
int bytesRead = dummyData.parseDataFromBuffer(byteArray);
message->seek(positionBeforeRead + bytesRead);
return std::make_shared<AvatarData>();
}
}

View file

@ -49,11 +49,11 @@ signals:
public slots:
bool isAvatarInRange(const glm::vec3 & position, const float range);
private slots:
protected slots:
void sessionUUIDChanged(const QUuid& sessionUUID, const QUuid& oldUUID);
void processAvatarDataPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer sendingNode);
virtual void processAvatarDataPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer sendingNode);
void processAvatarIdentityPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer sendingNode);
void processKillAvatar(QSharedPointer<ReceivedMessage> message, SharedNodePointer sendingNode);
void processExitingSpaceBubble(QSharedPointer<ReceivedMessage> message, SharedNodePointer sendingNode);
@ -61,12 +61,13 @@ private slots:
protected:
AvatarHashMap();
virtual AvatarSharedPointer parseAvatarData(QSharedPointer<ReceivedMessage> message, SharedNodePointer sendingNode);
virtual AvatarSharedPointer newSharedAvatar();
virtual AvatarSharedPointer addAvatar(const QUuid& sessionUUID, const QWeakPointer<Node>& mixerWeakPointer);
AvatarSharedPointer newOrExistingAvatar(const QUuid& sessionUUID, const QWeakPointer<Node>& mixerWeakPointer);
virtual AvatarSharedPointer findAvatar(const QUuid& sessionUUID) const; // uses a QReadLocker on the hashLock
virtual void removeAvatar(const QUuid& sessionUUID, KillAvatarReason removalReason = KillAvatarReason::NoReason);
virtual void handleRemovedAvatar(const AvatarSharedPointer& removedAvatar, KillAvatarReason removalReason = KillAvatarReason::NoReason);
AvatarHash _avatarHash;