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

View file

@ -335,7 +335,7 @@ public:
gpu::ContextPointer getGPUContext() const { return _gpuContext; }
const QRect& getMirrorViewRect() const { return _mirrorViewRect; }
void updateMyAvatarLookAtPosition();
AvatarUpdate* getAvatarUpdater() { return _avatarUpdate; }
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) {
avatarLock.lockForRead();
//FIXME: startRender();
if (_referential) {
_referential->update();
}
@ -391,7 +391,7 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition) {
}
if (frustum->sphereInFrustum(getPosition(), boundingRadius) == ViewFrustum::OUTSIDE) {
avatarLock.unlock();
//FIXME endRender();
return;
}
@ -542,7 +542,7 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition) {
if (!isMyAvatar() || cameraMode != CAMERA_MODE_FIRST_PERSON) {
renderDisplayName(batch, *renderArgs->_viewFrustum, renderArgs->_viewport);
}
avatarLock.unlock();
//FIXME endRender();
}
glm::quat Avatar::computeRotationFromBodyToWorldUp(float proportion) const {

View file

@ -156,6 +156,7 @@ public:
void scaleVectorRelativeToPosition(glm::vec3 &positionToScale) const;
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
// _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());
avatarIterator = _avatarHash.erase(avatarIterator);
} else {
avatar->avatarLock.lockForWrite();
avatar->startUpdate();
avatar->simulate(deltaTime);
avatar->avatarLock.unlock();
avatar->endUpdate();
++avatarIterator;
}
}
@ -150,7 +150,7 @@ void AvatarManager::simulateAvatarFades(float deltaTime) {
render::PendingChanges pendingChanges;
while (fadingIterator != _avatarFades.end()) {
auto avatar = std::static_pointer_cast<Avatar>(*fadingIterator);
avatar->avatarLock.lockForWrite();
avatar->startUpdate();
avatar->setTargetScale(avatar->getScale() * SHRINK_RATE, true);
if (avatar->getTargetScale() < MIN_FADE_SCALE) {
avatar->removeFromScene(*fadingIterator, scene, pendingChanges);
@ -159,7 +159,7 @@ void AvatarManager::simulateAvatarFades(float deltaTime) {
avatar->simulate(deltaTime);
++fadingIterator;
}
avatar->avatarLock.unlock();
avatar->endUpdate();
}
scene->enqueuePendingChanges(pendingChanges);
}

View file

@ -56,17 +56,20 @@ bool AvatarUpdate::process() {
_lastAvatarUpdate = start;
float deltaSeconds = deltaMicroseconds / (float) USECS_PER_SECOND;
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...
//gets current lookat data, removes missing avatars, etc.
DependencyManager::get<AvatarManager>()->updateOtherAvatars(deltaSeconds);
Application::getInstance()->getMyAvatar()->avatarLock.lockForWrite();
manager->updateOtherAvatars(deltaSeconds);
myAvatar->startUpdate();
Application::getInstance()->updateMyAvatarLookAtPosition();
// Sample hardware, update view frustum if needed, and send avatar data to mixer/nodes
DependencyManager::get<AvatarManager>()->updateMyAvatar(deltaSeconds);
Application::getInstance()->getMyAvatar()->avatarLock.unlock();
manager->updateMyAvatar(deltaSeconds);
myAvatar->endUpdate();
if (!isThreaded()) {
return true;
}

View file

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

View file

@ -192,6 +192,9 @@ void MyAvatar::simulate(float deltaTime) {
PerformanceTimer perfTimer("transform");
updateOrientation(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()) {
// set the body position/orientation to reflect motion due to the head.
auto worldMat = _sensorToWorldMatrix * _bodySensorMatrix;
setPosition(extractTranslation(worldMat));
setOrientation(glm::quat_cast(worldMat));
nextAttitude(extractTranslation(worldMat), glm::quat_cast(worldMat));
}
}

View file

@ -40,10 +40,10 @@ SkeletonModel::~SkeletonModel() {
}
void SkeletonModel::avatarLockForWriteIfApplicable() {
_owningAvatar->avatarLock.lockForWrite();
//FIXME _owningAvatar->avatarLock.lockForWrite();
}
void SkeletonModel::avatarLockReleaseIfApplicable() {
_owningAvatar->avatarLock.unlock();
//FIXME _owningAvatar->avatarLock.unlock();
}
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),
// but just before head has been simulated.
void SkeletonModel::simulate(float deltaTime, bool fullUpdate) {
void SkeletonModel::updateAttitude() {
setTranslation(_owningAvatar->getSkeletonPosition());
static const glm::quat refOrientation = glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f));
setRotation(_owningAvatar->getOrientation() * refOrientation);
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());
Model::simulate(deltaTime, fullUpdate);

View file

@ -31,6 +31,7 @@ public:
virtual void simulate(float deltaTime, bool fullUpdate = true);
virtual void updateRig(float deltaTime, glm::mat4 parentTransform);
void updateAttitude();
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 {
if (_referential) {
_referential->update();

View file

@ -198,6 +198,14 @@ public:
glm::quat getOrientation() const;
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(); }
void setHeadOrientation(const glm::quat& orientation) { _headData->setOrientation(orientation); }
@ -358,6 +366,11 @@ protected:
float _bodyPitch; // degrees
float _bodyRoll; // degrees
glm::vec3 _nextPosition {};
glm::quat _nextOrientation {};
int _nextPending = 0;
bool _nextAllowed = true;
// Body scale
float _targetScale;

View file

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

View file

@ -1310,7 +1310,7 @@ void Model::updateClusterMatrices() {
if (_showTrueJointTransforms) {
for (int j = 0; j < mesh.clusters.size(); 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;
// as an optimization, don't build cautrizedClusterMatrices if the boneSet is empty.
@ -1324,7 +1324,7 @@ void Model::updateClusterMatrices() {
} else {
for (int j = 0; j < mesh.clusters.size(); 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;
// 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
}
avatarLockForWriteIfApplicable();
if (!_calculatedMeshPartOffsetValid)
qCDebug(renderutils) << "FIXME surprise!";
_calculatedMeshPartOffsetValid = false; // FIXME
// We need to make sure we have valid offsets calculated before we can render
if (!_calculatedMeshPartOffsetValid) {
_mutex.lock();
@ -1496,10 +1500,10 @@ void Model::renderPart(RenderArgs* args, int meshIndex, int partIndex, bool tran
// guard against partially loaded meshes
if (meshIndex >= (int)networkMeshes.size() || meshIndex >= (int)geometry.meshes.size() || meshIndex >= (int)_meshStates.size() ) {
avatarLockReleaseIfApplicable();
return;
}
avatarLockForWriteIfApplicable();
updateClusterMatrices();
const NetworkMesh& networkMesh = *(networkMeshes.at(meshIndex).get());