Snapshot of no-judder, before cleanup.

This commit is contained in:
Howard Stearns 2015-09-07 09:57:05 -07:00
parent d3106de7c1
commit 0065c64b31
14 changed files with 108 additions and 32 deletions

View file

@ -1019,6 +1019,8 @@ void Application::paintGL() {
return; return;
} }
_inPaint = true; _inPaint = true;
_myAvatar->captureAttitude();
_myAvatar->startRender(); //FIXME
Finally clearFlagLambda([this] { _inPaint = false; }); Finally clearFlagLambda([this] { _inPaint = false; });
auto displayPlugin = getActiveDisplayPlugin(); auto displayPlugin = getActiveDisplayPlugin();
@ -1236,6 +1238,7 @@ void Application::paintGL() {
gpu::Batch batch; gpu::Batch batch;
batch.resetStages(); batch.resetStages();
renderArgs._context->render(batch); renderArgs._context->render(batch);
_myAvatar->endRender();
} }
void Application::runTests() { void Application::runTests() {
@ -2152,7 +2155,7 @@ void Application::setAvatarSimrateSample(float sample) {
} }
float Application::getAvatarSimrate() { float Application::getAvatarSimrate() {
uint64_t now = usecTimestampNow(); uint64_t now = usecTimestampNow();
if (now - _lastAvatarSimsPerSecondUpdate > USECS_PER_SECOND) { if (now - _lastAvatarSimsPerSecondUpdate > USECS_PER_SECOND) {
_avatarSimsPerSecondReport = _avatarSimsPerSecond.getAverage(); _avatarSimsPerSecondReport = _avatarSimsPerSecond.getAverage();
_lastAvatarSimsPerSecondUpdate = now; _lastAvatarSimsPerSecondUpdate = now;
@ -2444,7 +2447,7 @@ void Application::init() {
// Make sure any new sounds are loaded as soon as know about them. // Make sure any new sounds are loaded as soon as know about them.
connect(tree, &EntityTree::newCollisionSoundURL, DependencyManager::get<SoundCache>().data(), &SoundCache::getSound); connect(tree, &EntityTree::newCollisionSoundURL, DependencyManager::get<SoundCache>().data(), &SoundCache::getSound);
connect(_myAvatar, &MyAvatar::newCollisionSoundURL, DependencyManager::get<SoundCache>().data(), &SoundCache::getSound); connect(_myAvatar, &MyAvatar::newCollisionSoundURL, DependencyManager::get<SoundCache>().data(), &SoundCache::getSound);
setAvatarUpdateThreading(Menu::getInstance()->isOptionChecked(MenuOption::EnableAvatarUpdateThreading)); setAvatarUpdateThreading(Menu::getInstance()->isOptionChecked(MenuOption::EnableAvatarUpdateThreading));
} }

View file

@ -335,7 +335,7 @@ public:
gpu::ContextPointer getGPUContext() const { return _gpuContext; } gpu::ContextPointer getGPUContext() const { return _gpuContext; }
const QRect& getMirrorViewRect() const { return _mirrorViewRect; } const QRect& getMirrorViewRect() const { return _mirrorViewRect; }
void updateMyAvatarLookAtPosition(); void updateMyAvatarLookAtPosition();
AvatarUpdate* getAvatarUpdater() { return _avatarUpdate; } AvatarUpdate* getAvatarUpdater() { return _avatarUpdate; }
MyAvatar* getMyAvatar() { return _myAvatar; } MyAvatar* getMyAvatar() { return _myAvatar; }

View file

@ -316,7 +316,7 @@ void Avatar::removeFromScene(AvatarSharedPointer self, std::shared_ptr<render::S
} }
void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition) { void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition) {
avatarLock.lockForRead(); //FIXME: startRender();
if (_referential) { if (_referential) {
_referential->update(); _referential->update();
} }
@ -391,7 +391,7 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition) {
} }
if (frustum->sphereInFrustum(getPosition(), boundingRadius) == ViewFrustum::OUTSIDE) { if (frustum->sphereInFrustum(getPosition(), boundingRadius) == ViewFrustum::OUTSIDE) {
avatarLock.unlock(); //FIXME endRender();
return; return;
} }
@ -542,7 +542,7 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition) {
if (!isMyAvatar() || cameraMode != CAMERA_MODE_FIRST_PERSON) { if (!isMyAvatar() || cameraMode != CAMERA_MODE_FIRST_PERSON) {
renderDisplayName(batch, *renderArgs->_viewFrustum, renderArgs->_viewport); renderDisplayName(batch, *renderArgs->_viewFrustum, renderArgs->_viewport);
} }
avatarLock.unlock(); //FIXME endRender();
} }
glm::quat Avatar::computeRotationFromBodyToWorldUp(float proportion) const { glm::quat Avatar::computeRotationFromBodyToWorldUp(float proportion) const {

View file

@ -156,6 +156,7 @@ public:
void scaleVectorRelativeToPosition(glm::vec3 &positionToScale) const; void scaleVectorRelativeToPosition(glm::vec3 &positionToScale) const;
void slamPosition(const glm::vec3& position); void slamPosition(const glm::vec3& position);
virtual void updateAttitude() { _skeletonModel.updateAttitude(); }
// Call this when updating Avatar position with a delta. This will allow us to // Call this when updating Avatar position with a delta. This will allow us to
// _accurately_ measure position changes and compute the resulting velocity // _accurately_ measure position changes and compute the resulting velocity

View file

@ -129,9 +129,9 @@ void AvatarManager::updateOtherAvatars(float deltaTime) {
_avatarFades.push_back(avatarIterator.value()); _avatarFades.push_back(avatarIterator.value());
avatarIterator = _avatarHash.erase(avatarIterator); avatarIterator = _avatarHash.erase(avatarIterator);
} else { } else {
avatar->avatarLock.lockForWrite(); avatar->startUpdate();
avatar->simulate(deltaTime); avatar->simulate(deltaTime);
avatar->avatarLock.unlock(); avatar->endUpdate();
++avatarIterator; ++avatarIterator;
} }
} }
@ -150,7 +150,7 @@ void AvatarManager::simulateAvatarFades(float deltaTime) {
render::PendingChanges pendingChanges; render::PendingChanges pendingChanges;
while (fadingIterator != _avatarFades.end()) { while (fadingIterator != _avatarFades.end()) {
auto avatar = std::static_pointer_cast<Avatar>(*fadingIterator); auto avatar = std::static_pointer_cast<Avatar>(*fadingIterator);
avatar->avatarLock.lockForWrite(); avatar->startUpdate();
avatar->setTargetScale(avatar->getScale() * SHRINK_RATE, true); avatar->setTargetScale(avatar->getScale() * SHRINK_RATE, true);
if (avatar->getTargetScale() < MIN_FADE_SCALE) { if (avatar->getTargetScale() < MIN_FADE_SCALE) {
avatar->removeFromScene(*fadingIterator, scene, pendingChanges); avatar->removeFromScene(*fadingIterator, scene, pendingChanges);
@ -159,7 +159,7 @@ void AvatarManager::simulateAvatarFades(float deltaTime) {
avatar->simulate(deltaTime); avatar->simulate(deltaTime);
++fadingIterator; ++fadingIterator;
} }
avatar->avatarLock.unlock(); avatar->endUpdate();
} }
scene->enqueuePendingChanges(pendingChanges); scene->enqueuePendingChanges(pendingChanges);
} }

View file

@ -56,17 +56,20 @@ bool AvatarUpdate::process() {
_lastAvatarUpdate = start; _lastAvatarUpdate = start;
float deltaSeconds = deltaMicroseconds / (float) USECS_PER_SECOND; float deltaSeconds = deltaMicroseconds / (float) USECS_PER_SECOND;
Application::getInstance()->setAvatarSimrateSample(1.0f / deltaSeconds); Application::getInstance()->setAvatarSimrateSample(1.0f / deltaSeconds);
QSharedPointer<AvatarManager> manager = DependencyManager::get<AvatarManager>();
MyAvatar* myAvatar = manager->getMyAvatar();
//loop through all the other avatars and simulate them... //loop through all the other avatars and simulate them...
//gets current lookat data, removes missing avatars, etc. //gets current lookat data, removes missing avatars, etc.
DependencyManager::get<AvatarManager>()->updateOtherAvatars(deltaSeconds); manager->updateOtherAvatars(deltaSeconds);
Application::getInstance()->getMyAvatar()->avatarLock.lockForWrite(); myAvatar->startUpdate();
Application::getInstance()->updateMyAvatarLookAtPosition(); Application::getInstance()->updateMyAvatarLookAtPosition();
// Sample hardware, update view frustum if needed, and send avatar data to mixer/nodes // Sample hardware, update view frustum if needed, and send avatar data to mixer/nodes
DependencyManager::get<AvatarManager>()->updateMyAvatar(deltaSeconds); manager->updateMyAvatar(deltaSeconds);
Application::getInstance()->getMyAvatar()->avatarLock.unlock(); myAvatar->endUpdate();
if (!isThreaded()) { if (!isThreaded()) {
return true; return true;
} }

View file

@ -29,7 +29,7 @@ private:
quint64 _lastAvatarUpdate; // microsoeconds quint64 _lastAvatarUpdate; // microsoeconds
quint64 _targetInterval; // microseconds quint64 _targetInterval; // microseconds
bool _updateBillboard; bool _updateBillboard;
// Goes away if Application::getActiveDisplayPlugin() and friends are made thread safe: // Goes away if Application::getActiveDisplayPlugin() and friends are made thread safe:
public: public:
bool isHMDMode() { return _isHMDMode; } bool isHMDMode() { return _isHMDMode; }

View file

@ -192,6 +192,9 @@ void MyAvatar::simulate(float deltaTime) {
PerformanceTimer perfTimer("transform"); PerformanceTimer perfTimer("transform");
updateOrientation(deltaTime); updateOrientation(deltaTime);
updatePosition(deltaTime); updatePosition(deltaTime);
// The 2 updates set position, orientation, and all manner of physics stuff.
// Here we record the results.
nextAttitude(getPosition(), getOrientation());
} }
{ {
@ -266,8 +269,7 @@ void MyAvatar::updateFromHMDSensorMatrix(const glm::mat4& hmdSensorMatrix) {
if (getStandingHMDSensorMode()) { if (getStandingHMDSensorMode()) {
// set the body position/orientation to reflect motion due to the head. // set the body position/orientation to reflect motion due to the head.
auto worldMat = _sensorToWorldMatrix * _bodySensorMatrix; auto worldMat = _sensorToWorldMatrix * _bodySensorMatrix;
setPosition(extractTranslation(worldMat)); nextAttitude(extractTranslation(worldMat), glm::quat_cast(worldMat));
setOrientation(glm::quat_cast(worldMat));
} }
} }

View file

@ -40,10 +40,10 @@ SkeletonModel::~SkeletonModel() {
} }
void SkeletonModel::avatarLockForWriteIfApplicable() { void SkeletonModel::avatarLockForWriteIfApplicable() {
_owningAvatar->avatarLock.lockForWrite(); //FIXME _owningAvatar->avatarLock.lockForWrite();
} }
void SkeletonModel::avatarLockReleaseIfApplicable() { void SkeletonModel::avatarLockReleaseIfApplicable() {
_owningAvatar->avatarLock.unlock(); //FIXME _owningAvatar->avatarLock.unlock();
} }
void SkeletonModel::initJointStates(QVector<JointState> states) { void SkeletonModel::initJointStates(QVector<JointState> states) {
@ -154,13 +154,17 @@ void SkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) {
} }
} }
// Called by Avatar::simulate after it has set the joint states (fullUpdate true if changed), void SkeletonModel::updateAttitude() {
// but just before head has been simulated.
void SkeletonModel::simulate(float deltaTime, bool fullUpdate) {
setTranslation(_owningAvatar->getSkeletonPosition()); setTranslation(_owningAvatar->getSkeletonPosition());
static const glm::quat refOrientation = glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f)); static const glm::quat refOrientation = glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f));
setRotation(_owningAvatar->getOrientation() * refOrientation); setRotation(_owningAvatar->getOrientation() * refOrientation);
setScale(glm::vec3(1.0f, 1.0f, 1.0f) * _owningAvatar->getScale()); setScale(glm::vec3(1.0f, 1.0f, 1.0f) * _owningAvatar->getScale());
}
// Called by Avatar::simulate after it has set the joint states (fullUpdate true if changed),
// but just before head has been simulated.
void SkeletonModel::simulate(float deltaTime, bool fullUpdate) {
updateAttitude();
setBlendshapeCoefficients(_owningAvatar->getHead()->getBlendshapeCoefficients()); setBlendshapeCoefficients(_owningAvatar->getHead()->getBlendshapeCoefficients());
Model::simulate(deltaTime, fullUpdate); Model::simulate(deltaTime, fullUpdate);

View file

@ -31,6 +31,7 @@ public:
virtual void simulate(float deltaTime, bool fullUpdate = true); virtual void simulate(float deltaTime, bool fullUpdate = true);
virtual void updateRig(float deltaTime, glm::mat4 parentTransform); virtual void updateRig(float deltaTime, glm::mat4 parentTransform);
void updateAttitude();
void renderIKConstraints(gpu::Batch& batch); void renderIKConstraints(gpu::Batch& batch);

View file

@ -110,6 +110,54 @@ void AvatarData::setOrientation(const glm::quat& orientation, bool overideRefere
} }
} }
// There are a number of possible strategies, some more optimal than others in terms of using the latest info
// The current one does not update anything until captureAttitude, and then keeps that value until rendered.
void AvatarData::nextAttitude(glm::vec3 position, glm::quat orientation) {
setPosition(position, true); setOrientation(orientation, true);
_nextPending = 1; // FIXME type bool
}
void AvatarData::captureAttitude() {
if (!_nextAllowed) { // We haven't finished rendering the last one
return;
}
avatarLock.lockForWrite();
if (_nextPending) {
_nextAllowed = false;
_nextPosition = getPosition();
_nextOrientation = getOrientation();
} else {
qCDebug(avatars) << "FIXME capture with nothing pending";
}
avatarLock.unlock();
}
void AvatarData::startUpdate() {
avatarLock.lockForWrite();
}
void AvatarData::endUpdate() {
avatarLock.unlock();
}
void AvatarData::startRender() {
avatarLock.lockForRead();
if (!_nextPending) {
return;
}
glm::vec3 pos = getPosition();
glm::quat rot = getOrientation();
setPosition(_nextPosition, true);
//setOrientation(_nextOrientation, true);
updateAttitude();
_nextPosition = pos;
_nextOrientation = rot;
}
void AvatarData::endRender() {
setPosition(_nextPosition, true);
//setOrientation(_nextOrientation, true);
updateAttitude();
_nextPending = 0;
_nextAllowed = true;
avatarLock.unlock();
}
float AvatarData::getTargetScale() const { float AvatarData::getTargetScale() const {
if (_referential) { if (_referential) {
_referential->update(); _referential->update();

View file

@ -198,6 +198,14 @@ public:
glm::quat getOrientation() const; glm::quat getOrientation() const;
virtual void setOrientation(const glm::quat& orientation, bool overideReferential = false); virtual void setOrientation(const glm::quat& orientation, bool overideReferential = false);
void nextAttitude(glm::vec3 position, glm::quat orientation); // Can be safely called at any time.
void captureAttitude(); // Indicates that the latest values are about to be captured for camera, etc.
void startUpdate(); // start/end of update iteration
void endUpdate();
void startRender(); // start/end of rendering
void endRender();
virtual void updateAttitude() {} // Tell skeleton mesh about changes
glm::quat getHeadOrientation() const { return _headData->getOrientation(); } glm::quat getHeadOrientation() const { return _headData->getOrientation(); }
void setHeadOrientation(const glm::quat& orientation) { _headData->setOrientation(orientation); } void setHeadOrientation(const glm::quat& orientation) { _headData->setOrientation(orientation); }
@ -358,6 +366,11 @@ protected:
float _bodyPitch; // degrees float _bodyPitch; // degrees
float _bodyRoll; // degrees float _bodyRoll; // degrees
glm::vec3 _nextPosition {};
glm::quat _nextOrientation {};
int _nextPending = 0;
bool _nextAllowed = true;
// Body scale // Body scale
float _targetScale; float _targetScale;

View file

@ -405,14 +405,11 @@ void DynamicCharacterController::preSimulation(btScalar timeStep) {
void DynamicCharacterController::postSimulation() { void DynamicCharacterController::postSimulation() {
if (_enabled && _rigidBody) { if (_enabled && _rigidBody) {
_avatarData->avatarLock.lockForWrite();
const btTransform& avatarTransform = _rigidBody->getWorldTransform(); const btTransform& avatarTransform = _rigidBody->getWorldTransform();
glm::quat rotation = bulletToGLM(avatarTransform.getRotation()); glm::quat rotation = bulletToGLM(avatarTransform.getRotation());
glm::vec3 position = bulletToGLM(avatarTransform.getOrigin()); glm::vec3 position = bulletToGLM(avatarTransform.getOrigin());
_avatarData->setOrientation(rotation); _avatarData->nextAttitude(position - rotation * _shapeLocalOffset, rotation);
_avatarData->setPosition(position - rotation * _shapeLocalOffset);
_avatarData->setVelocity(bulletToGLM(_rigidBody->getLinearVelocity())); _avatarData->setVelocity(bulletToGLM(_rigidBody->getLinearVelocity()));
_avatarData->avatarLock.unlock();
} }
} }

View file

@ -1310,7 +1310,7 @@ void Model::updateClusterMatrices() {
if (_showTrueJointTransforms) { if (_showTrueJointTransforms) {
for (int j = 0; j < mesh.clusters.size(); j++) { for (int j = 0; j < mesh.clusters.size(); j++) {
const FBXCluster& cluster = mesh.clusters.at(j); const FBXCluster& cluster = mesh.clusters.at(j);
auto jointMatrix =_rig->getJointTransform(cluster.jointIndex); auto jointMatrix = _rig->getJointTransform(cluster.jointIndex);
state.clusterMatrices[j] = modelToWorld * jointMatrix * cluster.inverseBindMatrix; state.clusterMatrices[j] = modelToWorld * jointMatrix * cluster.inverseBindMatrix;
// as an optimization, don't build cautrizedClusterMatrices if the boneSet is empty. // as an optimization, don't build cautrizedClusterMatrices if the boneSet is empty.
@ -1324,7 +1324,7 @@ void Model::updateClusterMatrices() {
} else { } else {
for (int j = 0; j < mesh.clusters.size(); j++) { for (int j = 0; j < mesh.clusters.size(); j++) {
const FBXCluster& cluster = mesh.clusters.at(j); const FBXCluster& cluster = mesh.clusters.at(j);
auto jointMatrix = _rig->getJointVisibleTransform(cluster.jointIndex); auto jointMatrix = _rig->getJointVisibleTransform(cluster.jointIndex); // differs from above only in using get...VisibleTransform
state.clusterMatrices[j] = modelToWorld * jointMatrix * cluster.inverseBindMatrix; state.clusterMatrices[j] = modelToWorld * jointMatrix * cluster.inverseBindMatrix;
// as an optimization, don't build cautrizedClusterMatrices if the boneSet is empty. // as an optimization, don't build cautrizedClusterMatrices if the boneSet is empty.
@ -1472,6 +1472,10 @@ void Model::renderPart(RenderArgs* args, int meshIndex, int partIndex, bool tran
return; // bail asap return; // bail asap
} }
avatarLockForWriteIfApplicable();
if (!_calculatedMeshPartOffsetValid)
qCDebug(renderutils) << "FIXME surprise!";
_calculatedMeshPartOffsetValid = false; // FIXME
// We need to make sure we have valid offsets calculated before we can render // We need to make sure we have valid offsets calculated before we can render
if (!_calculatedMeshPartOffsetValid) { if (!_calculatedMeshPartOffsetValid) {
_mutex.lock(); _mutex.lock();
@ -1496,10 +1500,10 @@ void Model::renderPart(RenderArgs* args, int meshIndex, int partIndex, bool tran
// guard against partially loaded meshes // guard against partially loaded meshes
if (meshIndex >= (int)networkMeshes.size() || meshIndex >= (int)geometry.meshes.size() || meshIndex >= (int)_meshStates.size() ) { if (meshIndex >= (int)networkMeshes.size() || meshIndex >= (int)geometry.meshes.size() || meshIndex >= (int)_meshStates.size() ) {
avatarLockReleaseIfApplicable();
return; return;
} }
avatarLockForWriteIfApplicable();
updateClusterMatrices(); updateClusterMatrices();
const NetworkMesh& networkMesh = *(networkMeshes.at(meshIndex).get()); const NetworkMesh& networkMesh = *(networkMeshes.at(meshIndex).get());