From f9d6a7ba8d57cccb8e0feb16ecc9f4c344dbcdb5 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Wed, 8 Jun 2016 14:02:27 +1200 Subject: [PATCH 01/35] Fix image2d overlay color property --- interface/resources/qml/hifi/overlays/ImageOverlay.qml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/interface/resources/qml/hifi/overlays/ImageOverlay.qml b/interface/resources/qml/hifi/overlays/ImageOverlay.qml index b10b66f07c..b509f0ce3a 100644 --- a/interface/resources/qml/hifi/overlays/ImageOverlay.qml +++ b/interface/resources/qml/hifi/overlays/ImageOverlay.qml @@ -1,5 +1,6 @@ import QtQuick 2.3 import QtQuick.Controls 1.2 +import QtGraphicalEffects 1.0 import "." @@ -44,6 +45,12 @@ Overlay { } } + ColorOverlay { + id: color + anchors.fill: image + source: image + } + function updateSubImage(subImage) { var keys = Object.keys(subImage); for (var i = 0; i < keys.length; ++i) { @@ -70,6 +77,7 @@ Overlay { case "alpha": root.opacity = value; break; case "imageURL": image.source = value; break; case "subImage": updateSubImage(value); break; + case "color": color.color = Qt.rgba(value.red / 255, value.green / 255, value.blue / 255, root.opacity); break; default: console.log("OVERLAY Unhandled image property " + key); } } From 1b4b38c85bb3d6aaa410ad29e834a7b40ad50310 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 8 Jun 2016 11:28:49 -0700 Subject: [PATCH 02/35] when parent is an avatar, set velocity to zero (still incorrect, but avoids server-side problems) rather than the world-frame velocity --- libraries/shared/src/SpatiallyNestable.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/shared/src/SpatiallyNestable.cpp b/libraries/shared/src/SpatiallyNestable.cpp index 2a3cb4af47..ddc82e2169 100644 --- a/libraries/shared/src/SpatiallyNestable.cpp +++ b/libraries/shared/src/SpatiallyNestable.cpp @@ -422,7 +422,7 @@ void SpatiallyNestable::setVelocity(const glm::vec3& velocity, bool& success) { // causes EntityItem::stepKinematicMotion to have an effect on the equipped entity, // which causes it to drift from the hand. if (hasAncestorOfType(NestableType::Avatar)) { - _velocity = velocity; + _velocity = glm::vec3(0.0f); } else { // TODO: take parent angularVelocity into account. _velocity = glm::inverse(parentTransform.getRotation()) * (velocity - parentVelocity); From 5cbaf05e45cb708402adc1bf1a7c44c0f5cadc7e Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 8 Jun 2016 11:55:17 -0700 Subject: [PATCH 03/35] also zero angular velocity for child of avatar --- libraries/shared/src/SpatiallyNestable.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/libraries/shared/src/SpatiallyNestable.cpp b/libraries/shared/src/SpatiallyNestable.cpp index ddc82e2169..02a8d60fba 100644 --- a/libraries/shared/src/SpatiallyNestable.cpp +++ b/libraries/shared/src/SpatiallyNestable.cpp @@ -479,7 +479,12 @@ void SpatiallyNestable::setAngularVelocity(const glm::vec3& angularVelocity, boo glm::vec3 parentAngularVelocity = getParentAngularVelocity(success); Transform parentTransform = getParentTransform(success); _angularVelocityLock.withWriteLock([&] { - _angularVelocity = glm::inverse(parentTransform.getRotation()) * (angularVelocity - parentAngularVelocity); + if (hasAncestorOfType(NestableType::Avatar)) { + // TODO: this is done to keep entity-server from doing extrapolation, and isn't right. + _angularVelocity = glm::vec3(0.0f); + } else { + _angularVelocity = glm::inverse(parentTransform.getRotation()) * (angularVelocity - parentAngularVelocity); + } }); } From 201d7a7d3b616d26e0f5b4a6f23c2a3ad5ef520d Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 8 Jun 2016 12:11:08 -0700 Subject: [PATCH 04/35] when parent is an avatar, set velocity to zero (still incorrect, but avoids server-side problems) rather than the world-frame velocity --- libraries/shared/src/SpatiallyNestable.cpp | 32 ++++++++++++---------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/libraries/shared/src/SpatiallyNestable.cpp b/libraries/shared/src/SpatiallyNestable.cpp index 02a8d60fba..6872b1d197 100644 --- a/libraries/shared/src/SpatiallyNestable.cpp +++ b/libraries/shared/src/SpatiallyNestable.cpp @@ -415,12 +415,8 @@ void SpatiallyNestable::setVelocity(const glm::vec3& velocity, bool& success) { glm::vec3 parentVelocity = getParentVelocity(success); Transform parentTransform = getParentTransform(success); _velocityLock.withWriteLock([&] { - // HACK: until we are treating _velocity the same way we treat _position (meaning, - // _velocity is a vs parent value and any request for a world-frame velocity must - // be computed), do this to avoid equipped (parenting-grabbed) things from drifting. - // turning a zero velocity into a non-zero _velocity (because the avatar is moving) - // causes EntityItem::stepKinematicMotion to have an effect on the equipped entity, - // which causes it to drift from the hand. + // HACK: The entity-server doesn't know where avatars are. In order to avoid having the server + // try to do simple extrapolation, set relative velocities to zero if this is a child of an avatar. if (hasAncestorOfType(NestableType::Avatar)) { _velocity = glm::vec3(0.0f); } else { @@ -898,13 +894,21 @@ void SpatiallyNestable::setLocalTransformAndVelocities( _transformLock.withWriteLock([&] { _transform = localTransform; }); - // linear velocity - _velocityLock.withWriteLock([&] { - _velocity = localVelocity; - }); - // angular velocity - _angularVelocityLock.withWriteLock([&] { - _angularVelocity = localAngularVelocity; - }); + // linear and angular velocity + if (hasAncestorOfType(NestableType::Avatar)) { + _velocityLock.withWriteLock([&] { + _velocity = glm::vec3(0.0f); + }); + _angularVelocityLock.withWriteLock([&] { + _angularVelocity = glm::vec3(0.0f); + }); + } else { + _velocityLock.withWriteLock([&] { + _velocity = localVelocity; + }); + _angularVelocityLock.withWriteLock([&] { + _angularVelocity = localAngularVelocity; + }); + } locationChanged(false); } From a1766539f402a249758f87640163e6ea2edded26 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 8 Jun 2016 12:17:07 -0700 Subject: [PATCH 05/35] don't do simple simulation on children of avatars --- libraries/entities/src/EntitySimulation.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/libraries/entities/src/EntitySimulation.cpp b/libraries/entities/src/EntitySimulation.cpp index 893ae83cc5..b99ab76b7a 100644 --- a/libraries/entities/src/EntitySimulation.cpp +++ b/libraries/entities/src/EntitySimulation.cpp @@ -261,7 +261,11 @@ void EntitySimulation::moveSimpleKinematics(const quint64& now) { SetOfEntities::iterator itemItr = _simpleKinematicEntities.begin(); while (itemItr != _simpleKinematicEntities.end()) { EntityItemPointer entity = *itemItr; - if (entity->isMovingRelativeToParent() && !entity->getPhysicsInfo()) { + if (entity->isMovingRelativeToParent() && + !entity->getPhysicsInfo() && + // The entity-server doesn't know where avatars are, so don't attempt to do simple extrapolation for + // children of avatars. + !entity->hasAncestorOfType(NestableType::Avatar)) { entity->simulate(now); _entitiesToSort.insert(entity); ++itemItr; From d7fc789ea705df7de5c601e48a2c041e9705445d Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 8 Jun 2016 13:47:52 -0700 Subject: [PATCH 06/35] try harder to not do simple-simulation on things that have an avatar ancestor --- libraries/entities/src/EntitySimulation.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/libraries/entities/src/EntitySimulation.cpp b/libraries/entities/src/EntitySimulation.cpp index b99ab76b7a..8419e4ac6a 100644 --- a/libraries/entities/src/EntitySimulation.cpp +++ b/libraries/entities/src/EntitySimulation.cpp @@ -261,11 +261,14 @@ void EntitySimulation::moveSimpleKinematics(const quint64& now) { SetOfEntities::iterator itemItr = _simpleKinematicEntities.begin(); while (itemItr != _simpleKinematicEntities.end()) { EntityItemPointer entity = *itemItr; - if (entity->isMovingRelativeToParent() && - !entity->getPhysicsInfo() && - // The entity-server doesn't know where avatars are, so don't attempt to do simple extrapolation for - // children of avatars. - !entity->hasAncestorOfType(NestableType::Avatar)) { + + // The entity-server doesn't know where avatars are, so don't attempt to do simple extrapolation for + // children of avatars. + bool ancestryIsKnown; + entity->getMaximumAACube(ancestryIsKnown); + bool hasAvatarAncestor = entity->hasAncestorOfType(NestableType::Avatar); + + if (entity->isMovingRelativeToParent() && !entity->getPhysicsInfo() && ancestryIsKnown && !hasAvatarAncestor) { entity->simulate(now); _entitiesToSort.insert(entity); ++itemItr; From a312218722c6be133d303421c917f82dfa92a77d Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 8 Jun 2016 14:07:16 -0700 Subject: [PATCH 07/35] back out some changes --- libraries/shared/src/SpatiallyNestable.cpp | 41 +++++++++------------- 1 file changed, 16 insertions(+), 25 deletions(-) diff --git a/libraries/shared/src/SpatiallyNestable.cpp b/libraries/shared/src/SpatiallyNestable.cpp index 6872b1d197..2a3cb4af47 100644 --- a/libraries/shared/src/SpatiallyNestable.cpp +++ b/libraries/shared/src/SpatiallyNestable.cpp @@ -415,10 +415,14 @@ void SpatiallyNestable::setVelocity(const glm::vec3& velocity, bool& success) { glm::vec3 parentVelocity = getParentVelocity(success); Transform parentTransform = getParentTransform(success); _velocityLock.withWriteLock([&] { - // HACK: The entity-server doesn't know where avatars are. In order to avoid having the server - // try to do simple extrapolation, set relative velocities to zero if this is a child of an avatar. + // HACK: until we are treating _velocity the same way we treat _position (meaning, + // _velocity is a vs parent value and any request for a world-frame velocity must + // be computed), do this to avoid equipped (parenting-grabbed) things from drifting. + // turning a zero velocity into a non-zero _velocity (because the avatar is moving) + // causes EntityItem::stepKinematicMotion to have an effect on the equipped entity, + // which causes it to drift from the hand. if (hasAncestorOfType(NestableType::Avatar)) { - _velocity = glm::vec3(0.0f); + _velocity = velocity; } else { // TODO: take parent angularVelocity into account. _velocity = glm::inverse(parentTransform.getRotation()) * (velocity - parentVelocity); @@ -475,12 +479,7 @@ void SpatiallyNestable::setAngularVelocity(const glm::vec3& angularVelocity, boo glm::vec3 parentAngularVelocity = getParentAngularVelocity(success); Transform parentTransform = getParentTransform(success); _angularVelocityLock.withWriteLock([&] { - if (hasAncestorOfType(NestableType::Avatar)) { - // TODO: this is done to keep entity-server from doing extrapolation, and isn't right. - _angularVelocity = glm::vec3(0.0f); - } else { - _angularVelocity = glm::inverse(parentTransform.getRotation()) * (angularVelocity - parentAngularVelocity); - } + _angularVelocity = glm::inverse(parentTransform.getRotation()) * (angularVelocity - parentAngularVelocity); }); } @@ -894,21 +893,13 @@ void SpatiallyNestable::setLocalTransformAndVelocities( _transformLock.withWriteLock([&] { _transform = localTransform; }); - // linear and angular velocity - if (hasAncestorOfType(NestableType::Avatar)) { - _velocityLock.withWriteLock([&] { - _velocity = glm::vec3(0.0f); - }); - _angularVelocityLock.withWriteLock([&] { - _angularVelocity = glm::vec3(0.0f); - }); - } else { - _velocityLock.withWriteLock([&] { - _velocity = localVelocity; - }); - _angularVelocityLock.withWriteLock([&] { - _angularVelocity = localAngularVelocity; - }); - } + // linear velocity + _velocityLock.withWriteLock([&] { + _velocity = localVelocity; + }); + // angular velocity + _angularVelocityLock.withWriteLock([&] { + _angularVelocity = localAngularVelocity; + }); locationChanged(false); } From f070708b4a49c299967c78b7881df36bfa909cdc Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 8 Jun 2016 15:53:54 -0700 Subject: [PATCH 08/35] _avatarEntityData is accessed by more than one thread. --- interface/src/avatar/Avatar.cpp | 10 ++-- interface/src/avatar/MyAvatar.cpp | 14 ++--- libraries/avatars/src/AvatarData.cpp | 79 ++++++++++++++++++---------- libraries/avatars/src/AvatarData.h | 1 + 4 files changed, 65 insertions(+), 39 deletions(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 3e22448386..b5ac8ba77d 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -240,11 +240,13 @@ void Avatar::updateAvatarEntities() { } AvatarEntityIDs recentlyDettachedAvatarEntities = getAndClearRecentlyDetachedIDs(); - foreach (auto entityID, recentlyDettachedAvatarEntities) { - if (!_avatarEntityData.contains(entityID)) { - entityTree->deleteEntity(entityID, true, true); + _avatarEntitiesLock.withReadLock([&] { + foreach (auto entityID, recentlyDettachedAvatarEntities) { + if (!_avatarEntityData.contains(entityID)) { + entityTree->deleteEntity(entityID, true, true); + } } - } + }); }); if (success) { diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 62772c6933..324ff1534f 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -723,12 +723,14 @@ void MyAvatar::saveData() { settings.beginWriteArray("avatarEntityData"); int avatarEntityIndex = 0; - for (auto entityID : _avatarEntityData.keys()) { - settings.setArrayIndex(avatarEntityIndex); - settings.setValue("id", entityID); - settings.setValue("properties", _avatarEntityData.value(entityID)); - avatarEntityIndex++; - } + _avatarEntitiesLock.withReadLock([&] { + for (auto entityID : _avatarEntityData.keys()) { + settings.setArrayIndex(avatarEntityIndex); + settings.setValue("id", entityID); + settings.setValue("properties", _avatarEntityData.value(entityID)); + avatarEntityIndex++; + } + }); settings.endArray(); settings.setValue("displayName", _displayName); diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index ff7438bb17..6d99d6ad81 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -900,7 +900,11 @@ bool AvatarData::processAvatarIdentity(const Identity& identity) { hasIdentityChanged = true; } - if (identity.avatarEntityData != _avatarEntityData) { + bool avatarEntityDataChanged = false; + _avatarEntitiesLock.withReadLock([&] { + avatarEntityDataChanged = (identity.avatarEntityData != _avatarEntityData); + }); + if (avatarEntityDataChanged) { setAvatarEntityData(identity.avatarEntityData); hasIdentityChanged = true; } @@ -914,7 +918,9 @@ QByteArray AvatarData::identityByteArray() { QUrl emptyURL(""); const QUrl& urlToSend = _skeletonModelURL.scheme() == "file" ? emptyURL : _skeletonModelURL; - identityStream << getSessionUUID() << urlToSend << _attachmentData << _displayName << _avatarEntityData; + _avatarEntitiesLock.withReadLock([&] { + identityStream << getSessionUUID() << urlToSend << _attachmentData << _displayName << _avatarEntityData; + }); return identityData; } @@ -1306,16 +1312,18 @@ QJsonObject AvatarData::toJson() const { root[JSON_AVATAR_ATTACHEMENTS] = attachmentsJson; } - if (!_avatarEntityData.empty()) { - QJsonArray avatarEntityJson; - for (auto entityID : _avatarEntityData.keys()) { - QVariantMap entityData; - entityData.insert("id", entityID); - entityData.insert("properties", _avatarEntityData.value(entityID)); - avatarEntityJson.push_back(QVariant(entityData).toJsonObject()); + _avatarEntitiesLock.withReadLock([&] { + if (!_avatarEntityData.empty()) { + QJsonArray avatarEntityJson; + for (auto entityID : _avatarEntityData.keys()) { + QVariantMap entityData; + entityData.insert("id", entityID); + entityData.insert("properties", _avatarEntityData.value(entityID)); + avatarEntityJson.push_back(QVariant(entityData).toJsonObject()); + } + root[JSON_AVATAR_ENTITIES] = avatarEntityJson; } - root[JSON_AVATAR_ENTITIES] = avatarEntityJson; - } + }); auto recordingBasis = getRecordingBasis(); bool success; @@ -1604,8 +1612,10 @@ void AvatarData::updateAvatarEntity(const QUuid& entityID, const QByteArray& ent QMetaObject::invokeMethod(this, "updateAvatarEntity", Q_ARG(const QUuid&, entityID), Q_ARG(QByteArray, entityData)); return; } - _avatarEntityData.insert(entityID, entityData); - _avatarEntityDataLocallyEdited = true; + _avatarEntitiesLock.withWriteLock([&] { + _avatarEntityData.insert(entityID, entityData); + _avatarEntityDataLocallyEdited = true; + }); } void AvatarData::clearAvatarEntity(const QUuid& entityID) { @@ -1613,18 +1623,25 @@ void AvatarData::clearAvatarEntity(const QUuid& entityID) { QMetaObject::invokeMethod(this, "clearAvatarEntity", Q_ARG(const QUuid&, entityID)); return; } - _avatarEntityData.remove(entityID); - _avatarEntityDataLocallyEdited = true; + + _avatarEntitiesLock.withWriteLock([&] { + _avatarEntityData.remove(entityID); + _avatarEntityDataLocallyEdited = true; + }); } AvatarEntityMap AvatarData::getAvatarEntityData() const { + AvatarEntityMap result; if (QThread::currentThread() != thread()) { - AvatarEntityMap result; QMetaObject::invokeMethod(const_cast(this), "getAvatarEntityData", Qt::BlockingQueuedConnection, Q_RETURN_ARG(AvatarEntityMap, result)); return result; } - return _avatarEntityData; + + _avatarEntitiesLock.withReadLock([&] { + result = _avatarEntityData; + }); + return result; } void AvatarData::setAvatarEntityData(const AvatarEntityMap& avatarEntityData) { @@ -1632,29 +1649,33 @@ void AvatarData::setAvatarEntityData(const AvatarEntityMap& avatarEntityData) { QMetaObject::invokeMethod(this, "setAvatarEntityData", Q_ARG(const AvatarEntityMap&, avatarEntityData)); return; } - if (_avatarEntityData != avatarEntityData) { - // keep track of entities that were attached to this avatar but no longer are - AvatarEntityIDs previousAvatarEntityIDs = QSet::fromList(_avatarEntityData.keys()); + _avatarEntitiesLock.withWriteLock([&] { + if (_avatarEntityData != avatarEntityData) { + // keep track of entities that were attached to this avatar but no longer are + AvatarEntityIDs previousAvatarEntityIDs = QSet::fromList(_avatarEntityData.keys()); - _avatarEntityData = avatarEntityData; - setAvatarEntityDataChanged(true); + _avatarEntityData = avatarEntityData; + setAvatarEntityDataChanged(true); - foreach (auto entityID, previousAvatarEntityIDs) { - if (!_avatarEntityData.contains(entityID)) { - _avatarEntityDetached.insert(entityID); + foreach (auto entityID, previousAvatarEntityIDs) { + if (!_avatarEntityData.contains(entityID)) { + _avatarEntityDetached.insert(entityID); + } } } - } + }); } AvatarEntityIDs AvatarData::getAndClearRecentlyDetachedIDs() { + AvatarEntityIDs result; if (QThread::currentThread() != thread()) { - AvatarEntityIDs result; QMetaObject::invokeMethod(const_cast(this), "getRecentlyDetachedIDs", Qt::BlockingQueuedConnection, Q_RETURN_ARG(AvatarEntityIDs, result)); return result; } - AvatarEntityIDs result = _avatarEntityDetached; - _avatarEntityDetached.clear(); + _avatarEntitiesLock.withWriteLock([&] { + result = _avatarEntityDetached; + _avatarEntityDetached.clear(); + }); return result; } diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 61ee649273..2dd1079b49 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -418,6 +418,7 @@ protected: // updates about one avatar to another. glm::vec3 _globalPosition; + mutable ReadWriteLockable _avatarEntitiesLock; AvatarEntityIDs _avatarEntityDetached; // recently detached from this avatar AvatarEntityMap _avatarEntityData; bool _avatarEntityDataLocallyEdited { false }; From 24e5000aebee67e7ccd00a7fe8773c2362615cbe Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Wed, 8 Jun 2016 18:26:54 -0700 Subject: [PATCH 09/35] exposed orientation and eye position to procedural entity shaders --- .../src/RenderableProceduralItemShader.h | 2 ++ .../src/RenderableShapeEntityItem.cpp | 2 +- libraries/gpu-gl/src/gpu/gl/GLBackend.cpp | 17 +++++++++++++++++ libraries/gpu-gl/src/gpu/gl/GLBackend.h | 1 + libraries/gpu/src/gpu/Batch.cpp | 10 ++++++++++ libraries/gpu/src/gpu/Batch.h | 6 ++++++ .../procedural/src/procedural/Procedural.cpp | 18 +++++++++++++++--- .../procedural/src/procedural/Procedural.h | 6 +++++- .../src/procedural/ProceduralShaders.h | 2 ++ .../src/procedural/ProceduralSkybox.cpp | 2 +- 10 files changed, 60 insertions(+), 6 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableProceduralItemShader.h b/libraries/entities-renderer/src/RenderableProceduralItemShader.h index 4762f619bf..d7df43de14 100644 --- a/libraries/entities-renderer/src/RenderableProceduralItemShader.h +++ b/libraries/entities-renderer/src/RenderableProceduralItemShader.h @@ -314,6 +314,8 @@ in vec4 _position; // TODO add more uniforms uniform float iGlobalTime; // shader playback time (in seconds) uniform vec3 iWorldScale; // the dimensions of the object being rendered +uniform mat3 iWorldOrientation; // the orientation of the object being rendered +uniform vec3 iWorldEyePosition; // the world position of the eye // TODO add support for textures // TODO document available inputs other than the uniforms diff --git a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp index c93ae252e3..2b04478831 100644 --- a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp @@ -98,7 +98,7 @@ void RenderableShapeEntityItem::render(RenderArgs* args) { } batch.setModelTransform(modelTransform); // use a transform with scale, rotation, registration point and translation if (_procedural->ready()) { - _procedural->prepare(batch, getPosition(), getDimensions()); + _procedural->prepare(batch, getPosition(), getDimensions(), getOrientation(), args->getViewFrustum().getPosition()); auto outColor = _procedural->getColor(color); batch._glColor4f(outColor.r, outColor.g, outColor.b, outColor.a); DependencyManager::get()->renderShape(batch, MAPPING[_shape]); diff --git a/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp b/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp index ece1ee730c..e18b784018 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp +++ b/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp @@ -114,6 +114,7 @@ GLBackend::CommandCall GLBackend::_commandCalls[Batch::NUM_COMMANDS] = (&::gpu::gl::GLBackend::do_glUniform3fv), (&::gpu::gl::GLBackend::do_glUniform4fv), (&::gpu::gl::GLBackend::do_glUniform4iv), + (&::gpu::gl::GLBackend::do_glUniformMatrix3fv), (&::gpu::gl::GLBackend::do_glUniformMatrix4fv), (&::gpu::gl::GLBackend::do_glColor4f), @@ -515,6 +516,22 @@ void GLBackend::do_glUniform4iv(Batch& batch, size_t paramOffset) { (void)CHECK_GL_ERROR(); } +void GLBackend::do_glUniformMatrix3fv(Batch& batch, size_t paramOffset) { + if (_pipeline._program == 0) { + // We should call updatePipeline() to bind the program but we are not doing that + // because these uniform setters are deprecated and we don;t want to create side effect + return; + } + updatePipeline(); + + glUniformMatrix3fv( + GET_UNIFORM_LOCATION(batch._params[paramOffset + 3]._int), + batch._params[paramOffset + 2]._uint, + batch._params[paramOffset + 1]._uint, + (const GLfloat*)batch.editData(batch._params[paramOffset + 0]._uint)); + (void)CHECK_GL_ERROR(); +} + void GLBackend::do_glUniformMatrix4fv(Batch& batch, size_t paramOffset) { if (_pipeline._program == 0) { // We should call updatePipeline() to bind the program but we are not doing that diff --git a/libraries/gpu-gl/src/gpu/gl/GLBackend.h b/libraries/gpu-gl/src/gpu/gl/GLBackend.h index 610672f44f..5255a6cb25 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLBackend.h +++ b/libraries/gpu-gl/src/gpu/gl/GLBackend.h @@ -136,6 +136,7 @@ public: virtual void do_glUniform3fv(Batch& batch, size_t paramOffset) final; virtual void do_glUniform4fv(Batch& batch, size_t paramOffset) final; virtual void do_glUniform4iv(Batch& batch, size_t paramOffset) final; + virtual void do_glUniformMatrix3fv(Batch& batch, size_t paramOffset) final; virtual void do_glUniformMatrix4fv(Batch& batch, size_t paramOffset) final; virtual void do_glColor4f(Batch& batch, size_t paramOffset) final; diff --git a/libraries/gpu/src/gpu/Batch.cpp b/libraries/gpu/src/gpu/Batch.cpp index 9126f11acf..6dc1d63ca8 100644 --- a/libraries/gpu/src/gpu/Batch.cpp +++ b/libraries/gpu/src/gpu/Batch.cpp @@ -567,6 +567,16 @@ void Batch::_glUniform4iv(int32 location, int count, const int32* value) { _params.push_back(location); } +void Batch::_glUniformMatrix3fv(int32 location, int count, uint8 transpose, const float* value) { + ADD_COMMAND(glUniformMatrix3fv); + + const int MATRIX3_SIZE = 9 * sizeof(float); + _params.push_back(cacheData(count * MATRIX3_SIZE, value)); + _params.push_back(transpose); + _params.push_back(count); + _params.push_back(location); +} + void Batch::_glUniformMatrix4fv(int32 location, int count, uint8 transpose, const float* value) { ADD_COMMAND(glUniformMatrix4fv); diff --git a/libraries/gpu/src/gpu/Batch.h b/libraries/gpu/src/gpu/Batch.h index a2ee57759f..f8b447975c 100644 --- a/libraries/gpu/src/gpu/Batch.h +++ b/libraries/gpu/src/gpu/Batch.h @@ -269,6 +269,7 @@ public: void _glUniform3fv(int location, int count, const float* value); void _glUniform4fv(int location, int count, const float* value); void _glUniform4iv(int location, int count, const int* value); + void _glUniformMatrix3fv(int location, int count, unsigned char transpose, const float* value); void _glUniformMatrix4fv(int location, int count, unsigned char transpose, const float* value); void _glUniform(int location, int v0) { @@ -291,6 +292,10 @@ public: _glUniform4f(location, v.x, v.y, v.z, v.w); } + void _glUniform(int location, const glm::quat& v) { + _glUniformMatrix3fv(location, 1, false, reinterpret_cast< const float* >(&glm::mat3_cast(v))); + } + void _glColor4f(float red, float green, float blue, float alpha); enum Command { @@ -348,6 +353,7 @@ public: COMMAND_glUniform3fv, COMMAND_glUniform4fv, COMMAND_glUniform4iv, + COMMAND_glUniformMatrix3fv, COMMAND_glUniformMatrix4fv, COMMAND_glColor4f, diff --git a/libraries/procedural/src/procedural/Procedural.cpp b/libraries/procedural/src/procedural/Procedural.cpp index 781b508bc7..4f308e0812 100644 --- a/libraries/procedural/src/procedural/Procedural.cpp +++ b/libraries/procedural/src/procedural/Procedural.cpp @@ -39,6 +39,8 @@ static const std::string STANDARD_UNIFORM_NAMES[Procedural::NUM_STANDARD_UNIFORM "iFrameCount", "iWorldScale", "iWorldPosition", + "iWorldOrientation", + "iWorldEyePosition", "iChannelResolution" }; @@ -202,9 +204,11 @@ bool Procedural::ready() { return true; } -void Procedural::prepare(gpu::Batch& batch, const glm::vec3& position, const glm::vec3& size) { +void Procedural::prepare(gpu::Batch& batch, const glm::vec3& position, const glm::vec3& size, const glm::quat& orientation, const glm::vec3& eyePos) { _entityDimensions = size; _entityPosition = position; + _entityOrientation = orientation; + _eyePos = eyePos; if (_shaderUrl.isLocalFile()) { auto lastModified = (quint64)QFileInfo(_shaderPath).lastModified().toMSecsSinceEpoch(); if (lastModified > _shaderModified) { @@ -404,10 +408,10 @@ void Procedural::setupUniforms() { }); } - if (gpu::Shader::INVALID_LOCATION != _standardUniformSlots[SCALE]) { + if (gpu::Shader::INVALID_LOCATION != _standardUniformSlots[ORIENTATION]) { // FIXME move into the 'set once' section, since this doesn't change over time _uniforms.push_back([=](gpu::Batch& batch) { - batch._glUniform(_standardUniformSlots[SCALE], _entityDimensions); + batch._glUniform(_standardUniformSlots[ORIENTATION], _entityOrientation); }); } @@ -417,6 +421,14 @@ void Procedural::setupUniforms() { batch._glUniform(_standardUniformSlots[POSITION], _entityPosition); }); } + + if (gpu::Shader::INVALID_LOCATION != _standardUniformSlots[EYE_POSITION]) { + // FIXME move into the 'set once' section, since this doesn't change over time + _uniforms.push_back([=](gpu::Batch& batch) { + batch._glUniform(_standardUniformSlots[EYE_POSITION], _eyePos); + }); + } + } void Procedural::setupChannels(bool shouldCreate) { diff --git a/libraries/procedural/src/procedural/Procedural.h b/libraries/procedural/src/procedural/Procedural.h index f928d0e594..e27f8ade44 100644 --- a/libraries/procedural/src/procedural/Procedural.h +++ b/libraries/procedural/src/procedural/Procedural.h @@ -38,7 +38,7 @@ public: void parse(const QString& userDataJson); bool ready(); - void prepare(gpu::Batch& batch, const glm::vec3& position, const glm::vec3& size); + void prepare(gpu::Batch& batch, const glm::vec3& position, const glm::vec3& size, const glm::quat& orientation, const glm::vec3& eyePos); const gpu::ShaderPointer& getShader() const { return _shader; } glm::vec4 getColor(const glm::vec4& entityColor); @@ -56,6 +56,8 @@ public: FRAME_COUNT, SCALE, POSITION, + ORIENTATION, + EYE_POSITION, CHANNEL_RESOLUTION, NUM_STANDARD_UNIFORMS }; @@ -93,6 +95,8 @@ protected: // Entity metadata glm::vec3 _entityDimensions; glm::vec3 _entityPosition; + glm::quat _entityOrientation; + glm::vec3 _eyePos; private: // This should only be called from the render thread, as it shares data with Procedural::prepare diff --git a/libraries/procedural/src/procedural/ProceduralShaders.h b/libraries/procedural/src/procedural/ProceduralShaders.h index eddf53cb09..00571c3a94 100644 --- a/libraries/procedural/src/procedural/ProceduralShaders.h +++ b/libraries/procedural/src/procedural/ProceduralShaders.h @@ -289,6 +289,8 @@ const vec4 iChannelTime = vec4(0.0); uniform vec4 iDate; uniform int iFrameCount; uniform vec3 iWorldPosition; +uniform mat3 iWorldOrientation; +uniform vec3 iWorldEyePosition; uniform vec3 iChannelResolution[4]; uniform sampler2D iChannel0; uniform sampler2D iChannel1; diff --git a/libraries/procedural/src/procedural/ProceduralSkybox.cpp b/libraries/procedural/src/procedural/ProceduralSkybox.cpp index 1aa59c90d7..5905bfb017 100644 --- a/libraries/procedural/src/procedural/ProceduralSkybox.cpp +++ b/libraries/procedural/src/procedural/ProceduralSkybox.cpp @@ -52,7 +52,7 @@ void ProceduralSkybox::render(gpu::Batch& batch, const ViewFrustum& viewFrustum, batch.setModelTransform(Transform()); // only for Mac auto& procedural = skybox._procedural; - procedural.prepare(batch, glm::vec3(0), glm::vec3(1)); + procedural.prepare(batch, glm::vec3(0), glm::vec3(1), glm::quat(1, 0, 0, 0), glm::vec3(0)); auto textureSlot = procedural.getShader()->getTextures().findLocation("cubeMap"); auto bufferSlot = procedural.getShader()->getBuffers().findLocation("skyboxBuffer"); skybox.prepare(batch, textureSlot, bufferSlot); From 5650ef9d52b46d486639731747eb2acb154dcfba Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 9 Jun 2016 14:35:17 -0700 Subject: [PATCH 10/35] have code where physics guesses at server values also avoid doing simple simulation of children of avatars --- libraries/entities/src/EntitySimulation.cpp | 2 +- libraries/physics/src/EntityMotionState.cpp | 16 +++++++++++++--- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/libraries/entities/src/EntitySimulation.cpp b/libraries/entities/src/EntitySimulation.cpp index 8419e4ac6a..a29ea8e2c8 100644 --- a/libraries/entities/src/EntitySimulation.cpp +++ b/libraries/entities/src/EntitySimulation.cpp @@ -263,7 +263,7 @@ void EntitySimulation::moveSimpleKinematics(const quint64& now) { EntityItemPointer entity = *itemItr; // The entity-server doesn't know where avatars are, so don't attempt to do simple extrapolation for - // children of avatars. + // children of avatars. See related code in EntityMotionState::remoteSimulationOutOfSync. bool ancestryIsKnown; entity->getMaximumAACube(ancestryIsKnown); bool hasAvatarAncestor = entity->hasAncestorOfType(NestableType::Avatar); diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 053bfcbd85..be7862ade3 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -317,9 +317,19 @@ bool EntityMotionState::remoteSimulationOutOfSync(uint32_t simulationStep) { if (glm::length2(_serverVelocity) > 0.0f) { _serverVelocity += _serverAcceleration * dt; _serverVelocity *= powf(1.0f - _body->getLinearDamping(), dt); - // NOTE: we ignore the second-order acceleration term when integrating - // the position forward because Bullet also does this. - _serverPosition += dt * _serverVelocity; + + // the entity-server doesn't know where avatars are, so it doesn't do simple extrapolation for children of + // avatars. We are trying to guess what values the entity server has, so we don't do it here, either. See + // related code in EntitySimulation::moveSimpleKinematics. + bool ancestryIsKnown; + _entity->getMaximumAACube(ancestryIsKnown); + bool hasAvatarAncestor = _entity->hasAncestorOfType(NestableType::Avatar); + + if (ancestryIsKnown && !hasAvatarAncestor) { + // NOTE: we ignore the second-order acceleration term when integrating + // the position forward because Bullet also does this. + _serverPosition += dt * _serverVelocity; + } } if (_entity->actionDataNeedsTransmit()) { From 8cccd5416a3f6a66933979dcc24330fd77fd0f2f Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Thu, 9 Jun 2016 16:10:27 -0700 Subject: [PATCH 11/35] try to fix mac errors --- libraries/gpu/src/gpu/Batch.h | 5 +++-- libraries/procedural/src/procedural/Procedural.cpp | 2 +- libraries/procedural/src/procedural/Procedural.h | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/libraries/gpu/src/gpu/Batch.h b/libraries/gpu/src/gpu/Batch.h index f8b447975c..e0a0e057f7 100644 --- a/libraries/gpu/src/gpu/Batch.h +++ b/libraries/gpu/src/gpu/Batch.h @@ -14,6 +14,7 @@ #include #include #include +#include #include @@ -292,8 +293,8 @@ public: _glUniform4f(location, v.x, v.y, v.z, v.w); } - void _glUniform(int location, const glm::quat& v) { - _glUniformMatrix3fv(location, 1, false, reinterpret_cast< const float* >(&glm::mat3_cast(v))); + void _glUniform(int location, const glm::mat3& v) { + _glUniformMatrix3fv(location, 1, false, glm::value_ptr(v)); } void _glColor4f(float red, float green, float blue, float alpha); diff --git a/libraries/procedural/src/procedural/Procedural.cpp b/libraries/procedural/src/procedural/Procedural.cpp index 4f308e0812..ed3d5712e3 100644 --- a/libraries/procedural/src/procedural/Procedural.cpp +++ b/libraries/procedural/src/procedural/Procedural.cpp @@ -207,7 +207,7 @@ bool Procedural::ready() { void Procedural::prepare(gpu::Batch& batch, const glm::vec3& position, const glm::vec3& size, const glm::quat& orientation, const glm::vec3& eyePos) { _entityDimensions = size; _entityPosition = position; - _entityOrientation = orientation; + _entityOrientation = glm::mat3_cast(orientation); _eyePos = eyePos; if (_shaderUrl.isLocalFile()) { auto lastModified = (quint64)QFileInfo(_shaderPath).lastModified().toMSecsSinceEpoch(); diff --git a/libraries/procedural/src/procedural/Procedural.h b/libraries/procedural/src/procedural/Procedural.h index e27f8ade44..45dcfd7bf6 100644 --- a/libraries/procedural/src/procedural/Procedural.h +++ b/libraries/procedural/src/procedural/Procedural.h @@ -95,7 +95,7 @@ protected: // Entity metadata glm::vec3 _entityDimensions; glm::vec3 _entityPosition; - glm::quat _entityOrientation; + glm::mat3 _entityOrientation; glm::vec3 _eyePos; private: From e1ae2a193f0e3c510dcaa101ea5a21a984615437 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Fri, 10 Jun 2016 11:49:15 -0700 Subject: [PATCH 12/35] EntityMotionState now uses parent-relative position and rotation and velocity when deciding if it needs to send an edit packet to the entity-server --- libraries/physics/src/EntityMotionState.cpp | 41 ++++++------ libraries/physics/src/PhysicsEngine.cpp | 5 ++ libraries/shared/src/SpatiallyNestable.cpp | 69 +++++++++++++++++++++ libraries/shared/src/SpatiallyNestable.h | 22 ++++--- 4 files changed, 110 insertions(+), 27 deletions(-) diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index be7862ade3..28f7756d9a 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -85,10 +85,10 @@ void EntityMotionState::updateServerPhysicsVariables() { return; } - _serverPosition = _entity->getPosition(); - _serverRotation = _entity->getRotation(); - _serverVelocity = _entity->getVelocity(); - _serverAngularVelocity = _entity->getAngularVelocity(); + Transform localTransform; + _entity->getLocalTransformAndVelocities(localTransform, _serverVelocity, _serverAngularVelocity); + _serverPosition = localTransform.getTranslation(); + _serverRotation = localTransform.getRotation(); _serverAcceleration = _entity->getAcceleration(); _serverActionData = _entity->getActionData(); } @@ -274,11 +274,11 @@ bool EntityMotionState::remoteSimulationOutOfSync(uint32_t simulationStep) { // if we've never checked before, our _lastStep will be 0, and we need to initialize our state if (_lastStep == 0) { btTransform xform = _body->getWorldTransform(); - _serverPosition = bulletToGLM(xform.getOrigin()); - _serverRotation = bulletToGLM(xform.getRotation()); - _serverVelocity = getBodyLinearVelocityGTSigma(); + _serverPosition = _entity->worldPositionToParent(bulletToGLM(xform.getOrigin())); + _serverRotation = _entity->worldRotationToParent(bulletToGLM(xform.getRotation())); + _serverVelocity = _entity->worldVelocityToParent(getBodyLinearVelocityGTSigma()); _serverAcceleration = Vectors::ZERO; - _serverAngularVelocity = bulletToGLM(_body->getAngularVelocity()); + _serverAngularVelocity = _entity->worldVelocityToParent(bulletToGLM(_body->getAngularVelocity())); _lastStep = simulationStep; _serverActionData = _entity->getActionData(); _numInactiveUpdates = 1; @@ -315,9 +315,6 @@ bool EntityMotionState::remoteSimulationOutOfSync(uint32_t simulationStep) { _lastStep = simulationStep; if (glm::length2(_serverVelocity) > 0.0f) { - _serverVelocity += _serverAcceleration * dt; - _serverVelocity *= powf(1.0f - _body->getLinearDamping(), dt); - // the entity-server doesn't know where avatars are, so it doesn't do simple extrapolation for children of // avatars. We are trying to guess what values the entity server has, so we don't do it here, either. See // related code in EntitySimulation::moveSimpleKinematics. @@ -326,6 +323,9 @@ bool EntityMotionState::remoteSimulationOutOfSync(uint32_t simulationStep) { bool hasAvatarAncestor = _entity->hasAncestorOfType(NestableType::Avatar); if (ancestryIsKnown && !hasAvatarAncestor) { + _serverVelocity += _serverAcceleration * dt; + _serverVelocity *= powf(1.0f - _body->getLinearDamping(), dt); + // NOTE: we ignore the second-order acceleration term when integrating // the position forward because Bullet also does this. _serverPosition += dt * _serverVelocity; @@ -351,7 +351,7 @@ bool EntityMotionState::remoteSimulationOutOfSync(uint32_t simulationStep) { // compute position error btTransform worldTrans = _body->getWorldTransform(); - glm::vec3 position = bulletToGLM(worldTrans.getOrigin()); + glm::vec3 position = _entity->worldPositionToParent(bulletToGLM(worldTrans.getOrigin())); float dx2 = glm::distance2(position, _serverPosition); const float MAX_POSITION_ERROR_SQUARED = 0.000004f; // corresponds to 2mm @@ -386,7 +386,7 @@ bool EntityMotionState::remoteSimulationOutOfSync(uint32_t simulationStep) { } } const float MIN_ROTATION_DOT = 0.99999f; // This corresponds to about 0.5 degrees of rotation - glm::quat actualRotation = bulletToGLM(worldTrans.getRotation()); + glm::quat actualRotation = _entity->worldRotationToParent(bulletToGLM(worldTrans.getRotation())); #ifdef WANT_DEBUG if ((fabsf(glm::dot(actualRotation, _serverRotation)) < MIN_ROTATION_DOT)) { @@ -491,11 +491,11 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_ } // remember properties for local server prediction - _serverPosition = _entity->getPosition(); - _serverRotation = _entity->getRotation(); - _serverVelocity = _entity->getVelocity(); + Transform localTransform; + _entity->getLocalTransformAndVelocities(localTransform, _serverVelocity, _serverAngularVelocity); + _serverPosition = localTransform.getTranslation(); + _serverRotation = localTransform.getRotation(); _serverAcceleration = _entity->getAcceleration(); - _serverAngularVelocity = _entity->getAngularVelocity(); _serverActionData = _entity->getActionData(); EntityItemProperties properties; @@ -600,7 +600,7 @@ uint32_t EntityMotionState::getIncomingDirtyFlags() { if (_body && _entity) { dirtyFlags = _entity->getDirtyFlags(); - if (dirtyFlags | Simulation::DIRTY_SIMULATOR_ID) { + if (dirtyFlags & Simulation::DIRTY_SIMULATOR_ID) { // when SIMULATOR_ID changes we must check for reinterpretation of asymmetric collision mask // bits for the avatar groups (e.g. MY_AVATAR vs OTHER_AVATAR) uint8_t entityCollisionMask = _entity->getCollisionless() ? 0 : _entity->getCollisionMask(); @@ -613,8 +613,9 @@ uint32_t EntityMotionState::getIncomingDirtyFlags() { // we add DIRTY_MOTION_TYPE if the body's motion type disagrees with entity velocity settings int bodyFlags = _body->getCollisionFlags(); bool isMoving = _entity->isMovingRelativeToParent(); - if (((bodyFlags & btCollisionObject::CF_STATIC_OBJECT) && isMoving) || - (bodyFlags & btCollisionObject::CF_KINEMATIC_OBJECT && !isMoving)) { + if (((bodyFlags & btCollisionObject::CF_STATIC_OBJECT) && isMoving) // || + // (bodyFlags & btCollisionObject::CF_KINEMATIC_OBJECT && !isMoving) + ) { dirtyFlags |= Simulation::DIRTY_MOTION_TYPE; } } diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index d3247ec62c..6f8acfa6a7 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -75,6 +75,7 @@ void PhysicsEngine::addObjectToDynamicsWorld(ObjectMotionState* motionState) { motionState->setMotionType(motionType); switch(motionType) { case MOTION_TYPE_KINEMATIC: { + qDebug() << " --> KINEMATIC"; if (!body) { btCollisionShape* shape = motionState->getShape(); assert(shape); @@ -91,6 +92,8 @@ void PhysicsEngine::addObjectToDynamicsWorld(ObjectMotionState* motionState) { break; } case MOTION_TYPE_DYNAMIC: { + qDebug() << " --> DYNAMIC"; + mass = motionState->getMass(); btCollisionShape* shape = motionState->getShape(); assert(shape); @@ -117,6 +120,8 @@ void PhysicsEngine::addObjectToDynamicsWorld(ObjectMotionState* motionState) { } case MOTION_TYPE_STATIC: default: { + qDebug() << " --> STATIC"; + if (!body) { assert(motionState->getShape()); body = new btRigidBody(mass, motionState, motionState->getShape(), inertia); diff --git a/libraries/shared/src/SpatiallyNestable.cpp b/libraries/shared/src/SpatiallyNestable.cpp index 2a3cb4af47..6edf80ab98 100644 --- a/libraries/shared/src/SpatiallyNestable.cpp +++ b/libraries/shared/src/SpatiallyNestable.cpp @@ -174,6 +174,66 @@ glm::vec3 SpatiallyNestable::worldToLocal(const glm::vec3& position, return result.getTranslation(); } +glm::vec3 SpatiallyNestable::worldPositionToParent(const glm::vec3& position) { + bool success; + glm::vec3 result = SpatiallyNestable::worldToLocal(position, getParentID(), getParentJointIndex(), success); + if (!success) { + qDebug() << "Warning -- worldToLocal failed" << getID(); + } + return result; +} + +glm::vec3 SpatiallyNestable::worldVelocityToLocal(const glm::vec3& velocity, // can be linear or angular + const QUuid& parentID, int parentJointIndex, + bool& success) { + Transform result; + QSharedPointer parentFinder = DependencyManager::get(); + if (!parentFinder) { + success = false; + return glm::vec3(); + } + + Transform parentTransform; + auto parentWP = parentFinder->find(parentID, success); + if (!success) { + return glm::vec3(); + } + + auto parent = parentWP.lock(); + if (!parentID.isNull() && !parent) { + success = false; + return glm::vec3(); + } + + if (parent) { + parentTransform = parent->getTransform(parentJointIndex, success); + if (!success) { + return glm::vec3(); + } + parentTransform.setScale(1.0f); // TODO: scale + } + success = true; + + parentTransform.setTranslation(glm::vec3(0.0f)); + + Transform velocityTransform; + velocityTransform.setTranslation(velocity); + Transform myWorldTransform; + Transform::mult(myWorldTransform, parentTransform, velocityTransform); + myWorldTransform.setTranslation(velocity); + Transform::inverseMult(result, parentTransform, myWorldTransform); + return result.getTranslation(); +} + +glm::vec3 SpatiallyNestable::worldVelocityToParent(const glm::vec3& velocity) { + bool success; + glm::vec3 result = SpatiallyNestable::worldVelocityToLocal(velocity, getParentID(), getParentJointIndex(), success); + if (!success) { + qDebug() << "Warning -- worldVelocityToLocal failed" << getID(); + } + return result; +} + glm::quat SpatiallyNestable::worldToLocal(const glm::quat& orientation, const QUuid& parentID, int parentJointIndex, bool& success) { @@ -214,6 +274,15 @@ glm::quat SpatiallyNestable::worldToLocal(const glm::quat& orientation, return result.getRotation(); } +glm::quat SpatiallyNestable::worldRotationToParent(const glm::quat& orientation) { + bool success; + glm::quat result = SpatiallyNestable::worldToLocal(orientation, getParentID(), getParentJointIndex(), success); + if (!success) { + qDebug() << "Warning -- worldToLocal failed" << getID(); + } + return result; +} + glm::vec3 SpatiallyNestable::localToWorld(const glm::vec3& position, const QUuid& parentID, int parentJointIndex, bool& success) { diff --git a/libraries/shared/src/SpatiallyNestable.h b/libraries/shared/src/SpatiallyNestable.h index 04bb57a688..ffb00ac040 100644 --- a/libraries/shared/src/SpatiallyNestable.h +++ b/libraries/shared/src/SpatiallyNestable.h @@ -46,11 +46,17 @@ public: virtual void setParentJointIndex(quint16 parentJointIndex); static glm::vec3 worldToLocal(const glm::vec3& position, const QUuid& parentID, int parentJointIndex, bool& success); + static glm::vec3 worldVelocityToLocal(const glm::vec3& position, const QUuid& parentID, + int parentJointIndex, bool& success); static glm::quat worldToLocal(const glm::quat& orientation, const QUuid& parentID, int parentJointIndex, bool& success); static glm::vec3 localToWorld(const glm::vec3& position, const QUuid& parentID, int parentJointIndex, bool& success); static glm::quat localToWorld(const glm::quat& orientation, const QUuid& parentID, int parentJointIndex, bool& success); + glm::vec3 worldPositionToParent(const glm::vec3& position); + glm::vec3 worldVelocityToParent(const glm::vec3& velocity); + glm::quat worldRotationToParent(const glm::quat& orientation); + // world frame virtual const Transform getTransform(bool& success, int depth = 0) const; virtual void setTransform(const Transform& transform, bool& success); @@ -144,6 +150,15 @@ public: bool hasAncestorOfType(NestableType nestableType); + void getLocalTransformAndVelocities(Transform& localTransform, + glm::vec3& localVelocity, + glm::vec3& localAngularVelocity) const; + + void setLocalTransformAndVelocities( + const Transform& localTransform, + const glm::vec3& localVelocity, + const glm::vec3& localAngularVelocity); + protected: const NestableType _nestableType; // EntityItem or an AvatarData QUuid _id; @@ -151,13 +166,6 @@ protected: quint16 _parentJointIndex { 0 }; // which joint of the parent is this relative to? SpatiallyNestablePointer getParentPointer(bool& success) const; - void getLocalTransformAndVelocities(Transform& localTransform, glm::vec3& localVelocity, glm::vec3& localAngularVelocity) const; - - void setLocalTransformAndVelocities( - const Transform& localTransform, - const glm::vec3& localVelocity, - const glm::vec3& localAngularVelocity); - mutable SpatiallyNestableWeakPointer _parent; virtual void beParentOfChild(SpatiallyNestablePointer newChild) const; From 41c399897a2eec5d3ad3ed43d59aa12c1879f0ed Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Fri, 10 Jun 2016 12:08:13 -0700 Subject: [PATCH 13/35] remove some debug prints --- libraries/physics/src/EntityMotionState.cpp | 2 ++ libraries/physics/src/PhysicsEngine.cpp | 5 ----- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 28f7756d9a..e5957ce7b2 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -613,6 +613,8 @@ uint32_t EntityMotionState::getIncomingDirtyFlags() { // we add DIRTY_MOTION_TYPE if the body's motion type disagrees with entity velocity settings int bodyFlags = _body->getCollisionFlags(); bool isMoving = _entity->isMovingRelativeToParent(); + + // XXX what's right, here? if (((bodyFlags & btCollisionObject::CF_STATIC_OBJECT) && isMoving) // || // (bodyFlags & btCollisionObject::CF_KINEMATIC_OBJECT && !isMoving) ) { diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index 6f8acfa6a7..d3247ec62c 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -75,7 +75,6 @@ void PhysicsEngine::addObjectToDynamicsWorld(ObjectMotionState* motionState) { motionState->setMotionType(motionType); switch(motionType) { case MOTION_TYPE_KINEMATIC: { - qDebug() << " --> KINEMATIC"; if (!body) { btCollisionShape* shape = motionState->getShape(); assert(shape); @@ -92,8 +91,6 @@ void PhysicsEngine::addObjectToDynamicsWorld(ObjectMotionState* motionState) { break; } case MOTION_TYPE_DYNAMIC: { - qDebug() << " --> DYNAMIC"; - mass = motionState->getMass(); btCollisionShape* shape = motionState->getShape(); assert(shape); @@ -120,8 +117,6 @@ void PhysicsEngine::addObjectToDynamicsWorld(ObjectMotionState* motionState) { } case MOTION_TYPE_STATIC: default: { - qDebug() << " --> STATIC"; - if (!body) { assert(motionState->getShape()); body = new btRigidBody(mass, motionState, motionState->getShape(), inertia); From da98ee0916b904cd963f05c67c2a7c8264d0baee Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Fri, 10 Jun 2016 13:42:19 -0700 Subject: [PATCH 14/35] reorganized procedural shader code, added getWorldEyeWorldPos(), removed iWorldEyePosition --- .../src/RenderableProceduralItemShader.h | 382 ------------------ libraries/gpu/src/gpu/Transform.slh | 4 + .../procedural/src/procedural/Procedural.cpp | 13 +- .../procedural/src/procedural/Procedural.h | 1 - ...oceduralShaders.h => ProceduralCommon.slf} | 22 +- .../src/procedural/ProceduralSkybox.cpp | 2 +- 6 files changed, 16 insertions(+), 408 deletions(-) delete mode 100644 libraries/entities-renderer/src/RenderableProceduralItemShader.h rename libraries/procedural/src/procedural/{ProceduralShaders.h => ProceduralCommon.slf} (94%) diff --git a/libraries/entities-renderer/src/RenderableProceduralItemShader.h b/libraries/entities-renderer/src/RenderableProceduralItemShader.h deleted file mode 100644 index d7df43de14..0000000000 --- a/libraries/entities-renderer/src/RenderableProceduralItemShader.h +++ /dev/null @@ -1,382 +0,0 @@ -// -// Created by Bradley Austin Davis on 2015/09/05 -// Copyright 2013-2015 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -// Shader includes portions of webgl-noise: -// Description : Array and textureless GLSL 2D/3D/4D simplex -// noise functions. -// Author : Ian McEwan, Ashima Arts. -// Maintainer : ijm -// Lastmod : 20110822 (ijm) -// License : Copyright (C) 2011 Ashima Arts. All rights reserved. -// Distributed under the MIT License. See LICENSE file. -// https://github.com/ashima/webgl-noise -// - - -const QString SHADER_COMMON = R"SHADER( -layout(location = 0) out vec4 _fragColor0; -layout(location = 1) out vec4 _fragColor1; -layout(location = 2) out vec4 _fragColor2; - -// the alpha threshold -uniform float alphaThreshold; - -vec2 signNotZero(vec2 v) { - return vec2((v.x >= 0.0) ? +1.0 : -1.0, (v.y >= 0.0) ? +1.0 : -1.0); -} - -vec2 float32x3_to_oct(in vec3 v) { - vec2 p = v.xy * (1.0 / (abs(v.x) + abs(v.y) + abs(v.z))); - return ((v.z <= 0.0) ? ((1.0 - abs(p.yx)) * signNotZero(p)) : p); -} - - -vec3 oct_to_float32x3(in vec2 e) { - vec3 v = vec3(e.xy, 1.0 - abs(e.x) - abs(e.y)); - if (v.z < 0) { - v.xy = (1.0 - abs(v.yx)) * signNotZero(v.xy); - } - return normalize(v); -} - -vec3 snorm12x2_to_unorm8x3(vec2 f) { - vec2 u = vec2(round(clamp(f, -1.0, 1.0) * 2047.0 + 2047.0)); - float t = floor(u.y / 256.0); - - return floor(vec3( - u.x / 16.0, - fract(u.x / 16.0) * 256.0 + t, - u.y - t * 256.0 - )) / 255.0; -} - -vec2 unorm8x3_to_snorm12x2(vec3 u) { - u *= 255.0; - u.y *= (1.0 / 16.0); - vec2 s = vec2( u.x * 16.0 + floor(u.y), - fract(u.y) * (16.0 * 256.0) + u.z); - return clamp(s * (1.0 / 2047.0) - 1.0, vec2(-1.0), vec2(1.0)); -} - -float mod289(float x) { - return x - floor(x * (1.0 / 289.0)) * 289.0; -} - -vec2 mod289(vec2 x) { - return x - floor(x * (1.0 / 289.0)) * 289.0; -} - -vec3 mod289(vec3 x) { - return x - floor(x * (1.0 / 289.0)) * 289.0; -} - -vec4 mod289(vec4 x) { - return x - floor(x * (1.0 / 289.0)) * 289.0; -} - -float permute(float x) { - return mod289(((x*34.0)+1.0)*x); -} - -vec3 permute(vec3 x) { - return mod289(((x*34.0)+1.0)*x); -} - -vec4 permute(vec4 x) { - return mod289(((x*34.0)+1.0)*x); -} - -float taylorInvSqrt(float r) { - return 1.79284291400159 - 0.85373472095314 * r; -} - -vec4 taylorInvSqrt(vec4 r) { - return 1.79284291400159 - 0.85373472095314 * r; -} - -vec4 grad4(float j, vec4 ip) { - const vec4 ones = vec4(1.0, 1.0, 1.0, -1.0); - vec4 p, s; - - p.xyz = floor(fract(vec3(j) * ip.xyz) * 7.0) * ip.z - 1.0; - p.w = 1.5 - dot(abs(p.xyz), ones.xyz); - s = vec4(lessThan(p, vec4(0.0))); - p.xyz = p.xyz + (s.xyz * 2.0 - 1.0) * s.www; - - return p; -} - -// (sqrt(5) - 1)/4 = F4, used once below -#define F4 0.309016994374947451 - -float snoise(vec4 v) { - const vec4 C = vec4(0.138196601125011, // (5 - sqrt(5))/20 G4 - 0.276393202250021, // 2 * G4 - 0.414589803375032, // 3 * G4 - -0.447213595499958); // -1 + 4 * G4 - - // First corner - vec4 i = floor(v + dot(v, vec4(F4))); - vec4 x0 = v - i + dot(i, C.xxxx); - - // Other corners - - // Rank sorting originally contributed by Bill Licea-Kane, AMD (formerly ATI) - vec4 i0; - vec3 isX = step(x0.yzw, x0.xxx); - vec3 isYZ = step(x0.zww, x0.yyz); - i0.x = isX.x + isX.y + isX.z; - i0.yzw = 1.0 - isX; - i0.y += isYZ.x + isYZ.y; - i0.zw += 1.0 - isYZ.xy; - i0.z += isYZ.z; - i0.w += 1.0 - isYZ.z; - - // i0 now contains the unique values 0,1,2,3 in each channel - vec4 i3 = clamp(i0, 0.0, 1.0); - vec4 i2 = clamp(i0 - 1.0, 0.0, 1.0); - vec4 i1 = clamp(i0 - 2.0, 0.0, 1.0); - - vec4 x1 = x0 - i1 + C.xxxx; - vec4 x2 = x0 - i2 + C.yyyy; - vec4 x3 = x0 - i3 + C.zzzz; - vec4 x4 = x0 + C.wwww; - - // Permutations - i = mod289(i); - float j0 = permute(permute(permute(permute(i.w) + i.z) + i.y) + i.x); - vec4 j1 = permute( - permute( - permute( - permute(i.w + vec4(i1.w, i2.w, i3.w, 1.0)) + i.z - + vec4(i1.z, i2.z, i3.z, 1.0)) + i.y - + vec4(i1.y, i2.y, i3.y, 1.0)) + i.x - + vec4(i1.x, i2.x, i3.x, 1.0)); - - // Gradients: 7x7x6 points over a cube, mapped onto a 4-cross polytope - // 7*7*6 = 294, which is close to the ring size 17*17 = 289. - vec4 ip = vec4(1.0 / 294.0, 1.0 / 49.0, 1.0 / 7.0, 0.0); - - vec4 p0 = grad4(j0, ip); - vec4 p1 = grad4(j1.x, ip); - vec4 p2 = grad4(j1.y, ip); - vec4 p3 = grad4(j1.z, ip); - vec4 p4 = grad4(j1.w, ip); - - // Normalise gradients - vec4 norm = taylorInvSqrt( - vec4(dot(p0, p0), dot(p1, p1), dot(p2, p2), dot(p3, p3))); - p0 *= norm.x; - p1 *= norm.y; - p2 *= norm.z; - p3 *= norm.w; - p4 *= taylorInvSqrt(dot(p4, p4)); - - // Mix contributions from the five corners - vec3 m0 = max(0.6 - vec3(dot(x0, x0), dot(x1, x1), dot(x2, x2)), 0.0); - vec2 m1 = max(0.6 - vec2(dot(x3, x3), dot(x4, x4)), 0.0); - m0 = m0 * m0; - m1 = m1 * m1; - return 49.0 - * (dot(m0 * m0, vec3(dot(p0, x0), dot(p1, x1), dot(p2, x2))) - + dot(m1 * m1, vec2(dot(p3, x3), dot(p4, x4)))); - -} - -float snoise(vec3 v) { - const vec2 C = vec2(1.0 / 6.0, 1.0 / 3.0); - const vec4 D = vec4(0.0, 0.5, 1.0, 2.0); - - // First corner - vec3 i = floor(v + dot(v, C.yyy)); - vec3 x0 = v - i + dot(i, C.xxx); - - // Other corners - vec3 g = step(x0.yzx, x0.xyz); - vec3 l = 1.0 - g; - vec3 i1 = min(g.xyz, l.zxy); - vec3 i2 = max(g.xyz, l.zxy); - - vec3 x1 = x0 - i1 + C.xxx; - vec3 x2 = x0 - i2 + C.yyy; // 2.0*C.x = 1/3 = C.y - vec3 x3 = x0 - D.yyy; // -1.0+3.0*C.x = -0.5 = -D.y - - // Permutations - i = mod289(i); - vec4 p = permute( - permute( - permute(i.z + vec4(0.0, i1.z, i2.z, 1.0)) + i.y - + vec4(0.0, i1.y, i2.y, 1.0)) + i.x - + vec4(0.0, i1.x, i2.x, 1.0)); - - // Gradients: 7x7 points over a square, mapped onto an octahedron. - // The ring size 17*17 = 289 is close to a multiple of 49 (49*6 = 294) - float n_ = 0.142857142857; // 1.0/7.0 - vec3 ns = n_ * D.wyz - D.xzx; - - vec4 j = p - 49.0 * floor(p * ns.z * ns.z); // mod(p,7*7) - - vec4 x_ = floor(j * ns.z); - vec4 y_ = floor(j - 7.0 * x_); // mod(j,N) - - vec4 x = x_ * ns.x + ns.yyyy; - vec4 y = y_ * ns.x + ns.yyyy; - vec4 h = 1.0 - abs(x) - abs(y); - - vec4 b0 = vec4(x.xy, y.xy); - vec4 b1 = vec4(x.zw, y.zw); - - //vec4 s0 = vec4(lessThan(b0,0.0))*2.0 - 1.0; - //vec4 s1 = vec4(lessThan(b1,0.0))*2.0 - 1.0; - vec4 s0 = floor(b0) * 2.0 + 1.0; - vec4 s1 = floor(b1) * 2.0 + 1.0; - vec4 sh = -step(h, vec4(0.0)); - - vec4 a0 = b0.xzyw + s0.xzyw * sh.xxyy; - vec4 a1 = b1.xzyw + s1.xzyw * sh.zzww; - - vec3 p0 = vec3(a0.xy, h.x); - vec3 p1 = vec3(a0.zw, h.y); - vec3 p2 = vec3(a1.xy, h.z); - vec3 p3 = vec3(a1.zw, h.w); - - //Normalise gradients - vec4 norm = taylorInvSqrt( - vec4(dot(p0, p0), dot(p1, p1), dot(p2, p2), dot(p3, p3))); - p0 *= norm.x; - p1 *= norm.y; - p2 *= norm.z; - p3 *= norm.w; - - // Mix final noise value - vec4 m = max(0.6 - vec4(dot(x0, x0), dot(x1, x1), dot(x2, x2), dot(x3, x3)), - 0.0); - m = m * m; - return 42.0 - * dot(m * m, vec4(dot(p0, x0), dot(p1, x1), dot(p2, x2), dot(p3, x3))); -} - -float snoise(vec2 v) { - const vec4 C = vec4(0.211324865405187, // (3.0-sqrt(3.0))/6.0 - 0.366025403784439, // 0.5*(sqrt(3.0)-1.0) - -0.577350269189626, // -1.0 + 2.0 * C.x - 0.024390243902439); // 1.0 / 41.0 - // First corner - vec2 i = floor(v + dot(v, C.yy)); - vec2 x0 = v - i + dot(i, C.xx); - - // Other corners - vec2 i1; - i1 = (x0.x > x0.y) ? vec2(1.0, 0.0) : vec2(0.0, 1.0); - vec4 x12 = x0.xyxy + C.xxzz; - x12.xy -= i1; - - // Permutations - i = mod289(i); // Avoid truncation effects in permutation - vec3 p = permute( - permute(i.y + vec3(0.0, i1.y, 1.0)) + i.x + vec3(0.0, i1.x, 1.0)); - - vec3 m = max(0.5 - vec3(dot(x0, x0), dot(x12.xy, x12.xy), dot(x12.zw, x12.zw)), - 0.0); - m = m * m; - m = m * m; - - // Gradients: 41 points uniformly over a line, mapped onto a diamond. - // The ring size 17*17 = 289 is close to a multiple of 41 (41*7 = 287) - - vec3 x = 2.0 * fract(p * C.www) - 1.0; - vec3 h = abs(x) - 0.5; - vec3 ox = floor(x + 0.5); - vec3 a0 = x - ox; - - // Normalise gradients implicitly by scaling m - // Approximation of: m *= inversesqrt( a0*a0 + h*h ); - m *= 1.79284291400159 - 0.85373472095314 * (a0 * a0 + h * h); - - // Compute final noise value at P - vec3 g; - g.x = a0.x * x0.x + h.x * x0.y; - g.yz = a0.yz * x12.xz + h.yz * x12.yw; - return 130.0 * dot(m, g); -} - -// the interpolated normal -in vec3 _normal; -in vec3 _color; -in vec2 _texCoord0; -in vec4 _position; - -// TODO add more uniforms -uniform float iGlobalTime; // shader playback time (in seconds) -uniform vec3 iWorldScale; // the dimensions of the object being rendered -uniform mat3 iWorldOrientation; // the orientation of the object being rendered -uniform vec3 iWorldEyePosition; // the world position of the eye - -// TODO add support for textures -// TODO document available inputs other than the uniforms -// TODO provide world scale in addition to the untransformed position - -const vec3 DEFAULT_SPECULAR = vec3(0.1); -const float DEFAULT_SHININESS = 10; - -)SHADER"; - -// V1 shaders, only support emissive -// vec4 getProceduralColor() -const QString SHADER_TEMPLATE_V1 = SHADER_COMMON + R"SCRIBE( - -#line 1001 -%1 -#line 317 - -void main(void) { - vec4 emissive = getProceduralColor(); - - float alpha = emissive.a; - if (alpha != 1.0) { - discard; - } - - vec4 diffuse = vec4(_color.rgb, alpha); - vec4 normal = vec4(packNormal(normalize(_normal)), 0.5); - - _fragColor0 = diffuse; - _fragColor1 = normal; - _fragColor2 = vec4(emissive.rgb, DEFAULT_SHININESS / 128.0); -} - -)SCRIBE"; - -// void getProceduralDiffuseAndEmissive(out vec4 diffuse, out vec4 emissive) -const QString SHADER_TEMPLATE_V2 = SHADER_COMMON + R"SCRIBE( -// FIXME should we be doing the swizzle here? -vec3 iResolution = iWorldScale.xzy; - -// FIXME Mouse X,Y coordinates, and Z,W are for the click position if clicked (not supported in High Fidelity at the moment) -vec4 iMouse = vec4(0); - -// FIXME We set the seconds (iDate.w) of iDate to iGlobalTime, which contains the current date in seconds -vec4 iDate = vec4(0, 0, 0, iGlobalTime); - - -#line 1001 -%1 -#line 351 - -void main(void) { - vec3 diffuse = _color.rgb; - vec3 specular = DEFAULT_SPECULAR; - float shininess = DEFAULT_SHININESS; - - float emissiveAmount = getProceduralColors(diffuse, specular, shininess); - - _fragColor0 = vec4(diffuse.rgb, 1.0); - _fragColor1 = vec4(packNormal(normalize(_normal.xyz)), 1.0 - (emissiveAmount / 2.0)); - _fragColor2 = vec4(specular, shininess / 128.0); -} -)SCRIBE"; diff --git a/libraries/gpu/src/gpu/Transform.slh b/libraries/gpu/src/gpu/Transform.slh index 246167e186..20629c5f32 100644 --- a/libraries/gpu/src/gpu/Transform.slh +++ b/libraries/gpu/src/gpu/Transform.slh @@ -27,6 +27,10 @@ layout(std140) uniform transformCameraBuffer { TransformCamera getTransformCamera() { return _camera; } + +vec3 getEyeWorldPos() { + return _camera._viewInverse[3].xyz; +} <@endfunc@> diff --git a/libraries/procedural/src/procedural/Procedural.cpp b/libraries/procedural/src/procedural/Procedural.cpp index ed3d5712e3..c9ed959087 100644 --- a/libraries/procedural/src/procedural/Procedural.cpp +++ b/libraries/procedural/src/procedural/Procedural.cpp @@ -19,7 +19,7 @@ #include #include -#include "ProceduralShaders.h" +#include "ProceduralCommon_frag.h" // Userdata parsing constants static const QString PROCEDURAL_USER_DATA_KEY = "ProceduralEntity"; @@ -40,7 +40,6 @@ static const std::string STANDARD_UNIFORM_NAMES[Procedural::NUM_STANDARD_UNIFORM "iWorldScale", "iWorldPosition", "iWorldOrientation", - "iWorldEyePosition", "iChannelResolution" }; @@ -231,7 +230,7 @@ void Procedural::prepare(gpu::Batch& batch, const glm::vec3& position, const glm std::string fragmentShaderSource = _fragmentSource; size_t replaceIndex = fragmentShaderSource.find(PROCEDURAL_COMMON_BLOCK); if (replaceIndex != std::string::npos) { - fragmentShaderSource.replace(replaceIndex, PROCEDURAL_COMMON_BLOCK.size(), SHADER_COMMON); + fragmentShaderSource.replace(replaceIndex, PROCEDURAL_COMMON_BLOCK.size(), ProceduralCommon_frag); } replaceIndex = fragmentShaderSource.find(PROCEDURAL_VERSION); @@ -421,14 +420,6 @@ void Procedural::setupUniforms() { batch._glUniform(_standardUniformSlots[POSITION], _entityPosition); }); } - - if (gpu::Shader::INVALID_LOCATION != _standardUniformSlots[EYE_POSITION]) { - // FIXME move into the 'set once' section, since this doesn't change over time - _uniforms.push_back([=](gpu::Batch& batch) { - batch._glUniform(_standardUniformSlots[EYE_POSITION], _eyePos); - }); - } - } void Procedural::setupChannels(bool shouldCreate) { diff --git a/libraries/procedural/src/procedural/Procedural.h b/libraries/procedural/src/procedural/Procedural.h index 45dcfd7bf6..e551afe004 100644 --- a/libraries/procedural/src/procedural/Procedural.h +++ b/libraries/procedural/src/procedural/Procedural.h @@ -57,7 +57,6 @@ public: SCALE, POSITION, ORIENTATION, - EYE_POSITION, CHANNEL_RESOLUTION, NUM_STANDARD_UNIFORMS }; diff --git a/libraries/procedural/src/procedural/ProceduralShaders.h b/libraries/procedural/src/procedural/ProceduralCommon.slf similarity index 94% rename from libraries/procedural/src/procedural/ProceduralShaders.h rename to libraries/procedural/src/procedural/ProceduralCommon.slf index 00571c3a94..09fb1b0b04 100644 --- a/libraries/procedural/src/procedural/ProceduralShaders.h +++ b/libraries/procedural/src/procedural/ProceduralCommon.slf @@ -1,3 +1,5 @@ +<@include gpu/Config.slh@> +// Generated on <$_SCRIBE_DATE$> // // Created by Bradley Austin Davis on 2015/09/05 // Copyright 2013-2015 High Fidelity, Inc. @@ -17,8 +19,8 @@ // https://github.com/ashima/webgl-noise // - -const std::string SHADER_COMMON = R"SHADER( +<@include gpu/Transform.slh@> +<$declareStandardCameraTransform()$> float mod289(float x) { return x - floor(x * (1.0 / 289.0)) * 289.0; @@ -262,11 +264,6 @@ float snoise(vec2 v) { return 130.0 * dot(m, g); } -// shader playback time (in seconds) -uniform float iGlobalTime; -// the dimensions of the object being rendered -uniform vec3 iWorldScale; - #define PROCEDURAL 1 //PROCEDURAL_VERSION @@ -286,17 +283,16 @@ const float iSampleRate = 1.0; const vec4 iChannelTime = vec4(0.0); +uniform float iGlobalTime; // shader playback time (in seconds) uniform vec4 iDate; uniform int iFrameCount; -uniform vec3 iWorldPosition; -uniform mat3 iWorldOrientation; -uniform vec3 iWorldEyePosition; +uniform vec3 iWorldPosition; // the position of the object being rendered +uniform vec3 iWorldScale; // the dimensions of the object being rendered +uniform mat3 iWorldOrientation; // the orientation of the object being rendered uniform vec3 iChannelResolution[4]; uniform sampler2D iChannel0; uniform sampler2D iChannel1; uniform sampler2D iChannel2; uniform sampler2D iChannel3; -#endif - -)SHADER"; +#endif \ No newline at end of file diff --git a/libraries/procedural/src/procedural/ProceduralSkybox.cpp b/libraries/procedural/src/procedural/ProceduralSkybox.cpp index 5905bfb017..7ba711bdb1 100644 --- a/libraries/procedural/src/procedural/ProceduralSkybox.cpp +++ b/libraries/procedural/src/procedural/ProceduralSkybox.cpp @@ -52,7 +52,7 @@ void ProceduralSkybox::render(gpu::Batch& batch, const ViewFrustum& viewFrustum, batch.setModelTransform(Transform()); // only for Mac auto& procedural = skybox._procedural; - procedural.prepare(batch, glm::vec3(0), glm::vec3(1), glm::quat(1, 0, 0, 0), glm::vec3(0)); + procedural.prepare(batch, glm::vec3(0), glm::vec3(1), glm::quat(), glm::vec3(0)); auto textureSlot = procedural.getShader()->getTextures().findLocation("cubeMap"); auto bufferSlot = procedural.getShader()->getBuffers().findLocation("skyboxBuffer"); skybox.prepare(batch, textureSlot, bufferSlot); From f32e29ac2df13b536586932a2b8d1bf0671ab759 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Fri, 10 Jun 2016 13:46:02 -0700 Subject: [PATCH 15/35] small changes --- libraries/gpu/src/gpu/Batch.h | 2 +- libraries/gpu/src/gpu/Context.h | 2 +- libraries/procedural/src/procedural/ProceduralCommon.slf | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/gpu/src/gpu/Batch.h b/libraries/gpu/src/gpu/Batch.h index e0a0e057f7..4e51038368 100644 --- a/libraries/gpu/src/gpu/Batch.h +++ b/libraries/gpu/src/gpu/Batch.h @@ -453,7 +453,7 @@ public: Params _params; Bytes _data; - // SSBO class... layout MUST match the layout in TransformCamera.slh + // SSBO class... layout MUST match the layout in Transform.slh class TransformObject { public: Mat4 _model; diff --git a/libraries/gpu/src/gpu/Context.h b/libraries/gpu/src/gpu/Context.h index cead2c623d..652338f911 100644 --- a/libraries/gpu/src/gpu/Context.h +++ b/libraries/gpu/src/gpu/Context.h @@ -95,7 +95,7 @@ public: virtual void syncCache() = 0; virtual void downloadFramebuffer(const FramebufferPointer& srcFramebuffer, const Vec4i& region, QImage& destImage) = 0; - // UBO class... layout MUST match the layout in TransformCamera.slh + // UBO class... layout MUST match the layout in Transform.slh class TransformCamera { public: mutable Mat4 _view; diff --git a/libraries/procedural/src/procedural/ProceduralCommon.slf b/libraries/procedural/src/procedural/ProceduralCommon.slf index 09fb1b0b04..128723265f 100644 --- a/libraries/procedural/src/procedural/ProceduralCommon.slf +++ b/libraries/procedural/src/procedural/ProceduralCommon.slf @@ -23,7 +23,7 @@ <$declareStandardCameraTransform()$> float mod289(float x) { - return x - floor(x * (1.0 / 289.0)) * 289.0; + return x - floor(x * (1.0 / 289.0)) * 289.0; } vec2 mod289(vec2 x) { From 53435fc7301b3ec0dea8779e60b784305858a515 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Fri, 10 Jun 2016 14:04:33 -0700 Subject: [PATCH 16/35] removed extra argument --- libraries/entities-renderer/src/RenderableShapeEntityItem.cpp | 2 +- libraries/procedural/src/procedural/Procedural.cpp | 3 +-- libraries/procedural/src/procedural/Procedural.h | 3 +-- libraries/procedural/src/procedural/ProceduralSkybox.cpp | 2 +- 4 files changed, 4 insertions(+), 6 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp index 2b04478831..ec07e10ccf 100644 --- a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp @@ -98,7 +98,7 @@ void RenderableShapeEntityItem::render(RenderArgs* args) { } batch.setModelTransform(modelTransform); // use a transform with scale, rotation, registration point and translation if (_procedural->ready()) { - _procedural->prepare(batch, getPosition(), getDimensions(), getOrientation(), args->getViewFrustum().getPosition()); + _procedural->prepare(batch, getPosition(), getDimensions(), getOrientation()); auto outColor = _procedural->getColor(color); batch._glColor4f(outColor.r, outColor.g, outColor.b, outColor.a); DependencyManager::get()->renderShape(batch, MAPPING[_shape]); diff --git a/libraries/procedural/src/procedural/Procedural.cpp b/libraries/procedural/src/procedural/Procedural.cpp index c9ed959087..a9a297a2e1 100644 --- a/libraries/procedural/src/procedural/Procedural.cpp +++ b/libraries/procedural/src/procedural/Procedural.cpp @@ -203,11 +203,10 @@ bool Procedural::ready() { return true; } -void Procedural::prepare(gpu::Batch& batch, const glm::vec3& position, const glm::vec3& size, const glm::quat& orientation, const glm::vec3& eyePos) { +void Procedural::prepare(gpu::Batch& batch, const glm::vec3& position, const glm::vec3& size, const glm::quat& orientation) { _entityDimensions = size; _entityPosition = position; _entityOrientation = glm::mat3_cast(orientation); - _eyePos = eyePos; if (_shaderUrl.isLocalFile()) { auto lastModified = (quint64)QFileInfo(_shaderPath).lastModified().toMSecsSinceEpoch(); if (lastModified > _shaderModified) { diff --git a/libraries/procedural/src/procedural/Procedural.h b/libraries/procedural/src/procedural/Procedural.h index e551afe004..6991b47946 100644 --- a/libraries/procedural/src/procedural/Procedural.h +++ b/libraries/procedural/src/procedural/Procedural.h @@ -38,7 +38,7 @@ public: void parse(const QString& userDataJson); bool ready(); - void prepare(gpu::Batch& batch, const glm::vec3& position, const glm::vec3& size, const glm::quat& orientation, const glm::vec3& eyePos); + void prepare(gpu::Batch& batch, const glm::vec3& position, const glm::vec3& size, const glm::quat& orientation); const gpu::ShaderPointer& getShader() const { return _shader; } glm::vec4 getColor(const glm::vec4& entityColor); @@ -95,7 +95,6 @@ protected: glm::vec3 _entityDimensions; glm::vec3 _entityPosition; glm::mat3 _entityOrientation; - glm::vec3 _eyePos; private: // This should only be called from the render thread, as it shares data with Procedural::prepare diff --git a/libraries/procedural/src/procedural/ProceduralSkybox.cpp b/libraries/procedural/src/procedural/ProceduralSkybox.cpp index 7ba711bdb1..9e9a26d902 100644 --- a/libraries/procedural/src/procedural/ProceduralSkybox.cpp +++ b/libraries/procedural/src/procedural/ProceduralSkybox.cpp @@ -52,7 +52,7 @@ void ProceduralSkybox::render(gpu::Batch& batch, const ViewFrustum& viewFrustum, batch.setModelTransform(Transform()); // only for Mac auto& procedural = skybox._procedural; - procedural.prepare(batch, glm::vec3(0), glm::vec3(1), glm::quat(), glm::vec3(0)); + procedural.prepare(batch, glm::vec3(0), glm::vec3(1), glm::quat()); auto textureSlot = procedural.getShader()->getTextures().findLocation("cubeMap"); auto bufferSlot = procedural.getShader()->getBuffers().findLocation("skyboxBuffer"); skybox.prepare(batch, textureSlot, bufferSlot); From 7b21d711804e45cdbb121ecca0f9e189b2665f8e Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Fri, 10 Jun 2016 14:09:04 -0700 Subject: [PATCH 17/35] try to fix cmake error --- libraries/procedural/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/procedural/CMakeLists.txt b/libraries/procedural/CMakeLists.txt index 7145f7de5c..a2c1a019de 100644 --- a/libraries/procedural/CMakeLists.txt +++ b/libraries/procedural/CMakeLists.txt @@ -1,5 +1,5 @@ set(TARGET_NAME procedural) -AUTOSCRIBE_SHADER_LIB(gpu model) +AUTOSCRIBE_SHADER_LIB(gpu model procedural) setup_hifi_library() link_hifi_libraries(shared gpu gpu-gl networking model model-networking) From 4344a35c60f421e99e48df11612ac75c1cd21f28 Mon Sep 17 00:00:00 2001 From: howard-stearns Date: Fri, 10 Jun 2016 16:00:16 -0700 Subject: [PATCH 18/35] Use the new system pointer functionality. --- .../controllers/handControllerPointer.js | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/scripts/system/controllers/handControllerPointer.js b/scripts/system/controllers/handControllerPointer.js index 7b45babf4d..1728647e5e 100644 --- a/scripts/system/controllers/handControllerPointer.js +++ b/scripts/system/controllers/handControllerPointer.js @@ -305,13 +305,19 @@ var leftTrigger = new Trigger(); var rightTrigger = new Trigger(); var activeTrigger = rightTrigger; var activeHand = Controller.Standard.RightHand; +var LEFT_HUD_LASER = 1; +var RIGHT_HUD_LASER = 2; +var BOTH_HUD_LASERS = LEFT_HUD_LASER + RIGHT_HUD_LASER; +var activeHudLaser = RIGHT_HUD_LASER; function toggleHand() { // unequivocally switch which hand controls mouse position if (activeHand === Controller.Standard.RightHand) { activeHand = Controller.Standard.LeftHand; activeTrigger = leftTrigger; + activeHudLaser = LEFT_HUD_LASER; } else { activeHand = Controller.Standard.RightHand; activeTrigger = rightTrigger; + activeHudLaser = RIGHT_HUD_LASER; } } function makeToggleAction(hand) { // return a function(0|1) that makes the specified hand control mouse when 1 @@ -342,6 +348,7 @@ clickMapping.enable(); // Same properties as handControllerGrab search sphere var BALL_SIZE = 0.011; var BALL_ALPHA = 0.5; +var LASER_COLOR_XYZW = {x: 10 / 255, y: 10 / 255, z: 255 / 255, w: BALL_ALPHA}; var fakeProjectionBall = Overlays.addOverlay("sphere", { size: 5 * BALL_SIZE, color: {red: 255, green: 10, blue: 10}, @@ -356,9 +363,24 @@ Script.scriptEnding.connect(function () { overlays.forEach(Overlays.deleteOverlay); }); var visualizationIsShowing = false; // Not whether it desired, but simply whether it is. Just an optimziation. +var systemLaserOn = false; +var SYSTEM_LASER_DIRECTION = Vec3.normalize({x: 0, y: -1, z: -1}); // Guessing 45 degrees. +function clearSystemLaser() { + if (!systemLaserOn) { + return; + } + print('FIXME remove: disableHandLasers', BOTH_HUD_LASERS); + HMD.disableHandLasers(BOTH_HUD_LASERS); + systemLaserOn = false; +} function turnOffVisualization(optionalEnableClicks) { // because we're showing cursor on HUD if (!optionalEnableClicks) { expireMouseCursor(); + clearSystemLaser(); + } else if (!systemLaserOn) { + print('FIXME remove: setHandLasers', activeHudLaser, true, JSON.stringify(LASER_COLOR_XYZW), JSON.stringify(SYSTEM_LASER_DIRECTION)); + HMD.setHandLasers(activeHudLaser, true, LASER_COLOR_XYZW, SYSTEM_LASER_DIRECTION); + systemLaserOn = true; } if (!visualizationIsShowing) { return; @@ -371,6 +393,7 @@ function turnOffVisualization(optionalEnableClicks) { // because we're showing c var MAX_RAY_SCALE = 32000; // Anything large. It's a scale, not a distance. function updateVisualization(controllerPosition, controllerDirection, hudPosition3d, hudPosition2d) { ignore(controllerPosition, controllerDirection, hudPosition2d); + clearSystemLaser(); // Show an indication of where the cursor will appear when crossing a HUD element, // and where in-world clicking will occur. // From 8a682450a9b88b0feb7e881bf2b238249d36ff0f Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Fri, 10 Jun 2016 17:01:22 -0700 Subject: [PATCH 19/35] still trying to fix cmake errors --- libraries/entities-renderer/CMakeLists.txt | 2 +- libraries/gpu-gl/CMakeLists.txt | 1 - libraries/procedural/CMakeLists.txt | 2 +- libraries/render-utils/CMakeLists.txt | 2 +- libraries/render/CMakeLists.txt | 2 +- 5 files changed, 4 insertions(+), 5 deletions(-) diff --git a/libraries/entities-renderer/CMakeLists.txt b/libraries/entities-renderer/CMakeLists.txt index bb90c04c95..0063f4a701 100644 --- a/libraries/entities-renderer/CMakeLists.txt +++ b/libraries/entities-renderer/CMakeLists.txt @@ -1,5 +1,5 @@ set(TARGET_NAME entities-renderer) -AUTOSCRIBE_SHADER_LIB(gpu model render render-utils) +AUTOSCRIBE_SHADER_LIB(gpu model procedural render render-utils) setup_hifi_library(Widgets Network Script) link_hifi_libraries(shared gpu procedural model model-networking script-engine render render-utils) diff --git a/libraries/gpu-gl/CMakeLists.txt b/libraries/gpu-gl/CMakeLists.txt index dfac6dd516..398fdd04d6 100644 --- a/libraries/gpu-gl/CMakeLists.txt +++ b/libraries/gpu-gl/CMakeLists.txt @@ -1,5 +1,4 @@ set(TARGET_NAME gpu-gl) -AUTOSCRIBE_SHADER_LIB(gpu) setup_hifi_library() link_hifi_libraries(shared gl gpu) GroupSources("src") diff --git a/libraries/procedural/CMakeLists.txt b/libraries/procedural/CMakeLists.txt index a2c1a019de..7145f7de5c 100644 --- a/libraries/procedural/CMakeLists.txt +++ b/libraries/procedural/CMakeLists.txt @@ -1,5 +1,5 @@ set(TARGET_NAME procedural) -AUTOSCRIBE_SHADER_LIB(gpu model procedural) +AUTOSCRIBE_SHADER_LIB(gpu model) setup_hifi_library() link_hifi_libraries(shared gpu gpu-gl networking model model-networking) diff --git a/libraries/render-utils/CMakeLists.txt b/libraries/render-utils/CMakeLists.txt index c4f28aeffd..2a7d33e33a 100644 --- a/libraries/render-utils/CMakeLists.txt +++ b/libraries/render-utils/CMakeLists.txt @@ -1,5 +1,5 @@ set(TARGET_NAME render-utils) -AUTOSCRIBE_SHADER_LIB(gpu model render) +AUTOSCRIBE_SHADER_LIB(gpu model render procedural) # pull in the resources.qrc file qt5_add_resources(QT_RESOURCES_FILE "${CMAKE_CURRENT_SOURCE_DIR}/res/fonts/fonts.qrc") setup_hifi_library(Widgets OpenGL Network Qml Quick Script) diff --git a/libraries/render/CMakeLists.txt b/libraries/render/CMakeLists.txt index 76fc8303ce..c5cfdf3668 100644 --- a/libraries/render/CMakeLists.txt +++ b/libraries/render/CMakeLists.txt @@ -1,5 +1,5 @@ set(TARGET_NAME render) -AUTOSCRIBE_SHADER_LIB(gpu model) +AUTOSCRIBE_SHADER_LIB(gpu model procedural) setup_hifi_library() link_hifi_libraries(shared gpu model) From 52245f25f28645b66caaeee686fe752cf6e07d23 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 13 Jun 2016 11:48:45 -0700 Subject: [PATCH 20/35] rework code that transforms global _server* values into parent-frame values --- libraries/physics/src/EntityMotionState.cpp | 39 ++++++++++++++++++--- 1 file changed, 35 insertions(+), 4 deletions(-) diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index e5957ce7b2..5fffc9901b 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -274,9 +274,39 @@ bool EntityMotionState::remoteSimulationOutOfSync(uint32_t simulationStep) { // if we've never checked before, our _lastStep will be 0, and we need to initialize our state if (_lastStep == 0) { btTransform xform = _body->getWorldTransform(); - _serverPosition = _entity->worldPositionToParent(bulletToGLM(xform.getOrigin())); - _serverRotation = _entity->worldRotationToParent(bulletToGLM(xform.getRotation())); - _serverVelocity = _entity->worldVelocityToParent(getBodyLinearVelocityGTSigma()); + + // _serverPosition = _entity->worldPositionToParent(bulletToGLM(xform.getOrigin())); + // _serverRotation = _entity->worldRotationToParent(bulletToGLM(xform.getRotation())); + // _serverVelocity = _entity->worldVelocityToParent(getBodyLinearVelocityGTSigma()); + + + _serverPosition = bulletToGLM(xform.getOrigin()); + _serverRotation = bulletToGLM(xform.getRotation()); + _serverVelocity = getBodyLinearVelocityGTSigma(); + bool success; + Transform parentTransform = _entity->getParentTransform(success); + if (success) { + Transform bodyTransform; + bodyTransform.setTranslation(_serverPosition); + bodyTransform.setRotation(_serverRotation); + Transform result; + Transform::inverseMult(result, parentTransform, bodyTransform); + _serverPosition = result.getTranslation(); + _serverRotation = result.getRotation(); + + // transform velocity into parent-frame + parentTransform.setTranslation(glm::vec3(0.0f)); + Transform velocityTransform; + velocityTransform.setTranslation(_serverVelocity); + Transform myWorldTransform; + Transform::mult(myWorldTransform, parentTransform, velocityTransform); + myWorldTransform.setTranslation(_serverVelocity); + Transform::inverseMult(result, parentTransform, myWorldTransform); + _serverVelocity = result.getTranslation(); + } + + + _serverAcceleration = Vectors::ZERO; _serverAngularVelocity = _entity->worldVelocityToParent(bulletToGLM(_body->getAngularVelocity())); _lastStep = simulationStep; @@ -614,8 +644,9 @@ uint32_t EntityMotionState::getIncomingDirtyFlags() { int bodyFlags = _body->getCollisionFlags(); bool isMoving = _entity->isMovingRelativeToParent(); - // XXX what's right, here? if (((bodyFlags & btCollisionObject::CF_STATIC_OBJECT) && isMoving) // || + // TODO -- there is opportunity for an optimization here, but this currently causes + // excessive re-insertion of the rigid body. // (bodyFlags & btCollisionObject::CF_KINEMATIC_OBJECT && !isMoving) ) { dirtyFlags |= Simulation::DIRTY_MOTION_TYPE; From 9640727f518e06ad915746848ad3b8ebea030d7e Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Wed, 8 Jun 2016 17:09:30 -0700 Subject: [PATCH 21/35] Hand laser rendering support in HMD plugins. --- .../src/scripting/HMDScriptingInterface.cpp | 10 ++ .../src/scripting/HMDScriptingInterface.h | 2 + .../display-plugins/OpenGLDisplayPlugin.cpp | 53 ++++--- .../src/display-plugins/OpenGLDisplayPlugin.h | 21 ++- .../display-plugins/hmd/HmdDisplayPlugin.cpp | 149 +++++++++++++++++- .../display-plugins/hmd/HmdDisplayPlugin.h | 20 ++- libraries/gl/src/gl/OglplusHelpers.cpp | 92 ++++++++++- libraries/gl/src/gl/OglplusHelpers.h | 5 +- libraries/plugins/src/plugins/DisplayPlugin.h | 20 +++ .../oculus/src/OculusBaseDisplayPlugin.cpp | 5 +- .../src/OculusLegacyDisplayPlugin.cpp | 5 +- plugins/openvr/src/OpenVrDisplayPlugin.cpp | 63 ++++++-- plugins/openvr/src/OpenVrDisplayPlugin.h | 1 - plugins/openvr/src/OpenVrHelpers.cpp | 4 + plugins/openvr/src/OpenVrHelpers.h | 1 + 15 files changed, 399 insertions(+), 52 deletions(-) diff --git a/interface/src/scripting/HMDScriptingInterface.cpp b/interface/src/scripting/HMDScriptingInterface.cpp index 7bf1547a3c..02840a9775 100644 --- a/interface/src/scripting/HMDScriptingInterface.cpp +++ b/interface/src/scripting/HMDScriptingInterface.cpp @@ -105,3 +105,13 @@ QString HMDScriptingInterface::preferredAudioInput() const { QString HMDScriptingInterface::preferredAudioOutput() const { return qApp->getActiveDisplayPlugin()->getPreferredAudioOutDevice(); } + +bool HMDScriptingInterface::setHandLasers(int hands, bool enabled, const glm::vec4& color, const glm::vec3& direction) const { + return qApp->getActiveDisplayPlugin()->setHandLaser(hands, + enabled ? DisplayPlugin::HandLaserMode::Overlay : DisplayPlugin::HandLaserMode::None, + color, direction); +} + +void HMDScriptingInterface::disableHandLasers(int hands) const { + qApp->getActiveDisplayPlugin()->setHandLaser(hands, DisplayPlugin::HandLaserMode::None); +} diff --git a/interface/src/scripting/HMDScriptingInterface.h b/interface/src/scripting/HMDScriptingInterface.h index d4c7b7cc0e..c55320ca83 100644 --- a/interface/src/scripting/HMDScriptingInterface.h +++ b/interface/src/scripting/HMDScriptingInterface.h @@ -36,6 +36,8 @@ public: Q_INVOKABLE glm::vec2 overlayToSpherical(const glm::vec2 & overlayPos) const; Q_INVOKABLE QString preferredAudioInput() const; Q_INVOKABLE QString preferredAudioOutput() const; + Q_INVOKABLE bool setHandLasers(int hands, bool enabled, const glm::vec4& color, const glm::vec3& direction) const; + Q_INVOKABLE void disableHandLasers(int hands) const; public: HMDScriptingInterface(); diff --git a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp index d9ee979777..363bde15e6 100644 --- a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp @@ -213,9 +213,10 @@ OpenGLDisplayPlugin::OpenGLDisplayPlugin() { } void OpenGLDisplayPlugin::cleanupForSceneTexture(const gpu::TexturePointer& sceneTexture) { - Lock lock(_mutex); - Q_ASSERT(_sceneTextureToFrameIndexMap.contains(sceneTexture)); - _sceneTextureToFrameIndexMap.remove(sceneTexture); + withRenderThreadLock([&] { + Q_ASSERT(_sceneTextureToFrameIndexMap.contains(sceneTexture)); + _sceneTextureToFrameIndexMap.remove(sceneTexture); + }); } @@ -394,10 +395,9 @@ void OpenGLDisplayPlugin::submitSceneTexture(uint32_t frameIndex, const gpu::Tex return; } - { - Lock lock(_mutex); + withRenderThreadLock([&] { _sceneTextureToFrameIndexMap[sceneTexture] = frameIndex; - } + }); // Submit it to the presentation thread via escrow _sceneTextureEscrow.submit(sceneTexture); @@ -431,11 +431,12 @@ void OpenGLDisplayPlugin::updateTextures() { } void OpenGLDisplayPlugin::updateFrameData() { - Lock lock(_mutex); - auto previousFrameIndex = _currentPresentFrameIndex; - _currentPresentFrameIndex = _sceneTextureToFrameIndexMap[_currentSceneTexture]; - auto skippedCount = (_currentPresentFrameIndex - previousFrameIndex) - 1; - _droppedFrameRate.increment(skippedCount); + withPresentThreadLock([&] { + auto previousFrameIndex = _currentPresentFrameIndex; + _currentPresentFrameIndex = _sceneTextureToFrameIndexMap[_currentSceneTexture]; + auto skippedCount = (_currentPresentFrameIndex - previousFrameIndex) - 1; + _droppedFrameRate.increment(skippedCount); + }); } void OpenGLDisplayPlugin::compositeOverlay() { @@ -492,14 +493,14 @@ void OpenGLDisplayPlugin::compositeLayers() { } _compositeFramebuffer->Bound(Framebuffer::Target::Draw, [&] { Context::Viewport(targetRenderSize.x, targetRenderSize.y); - Context::Clear().DepthBuffer(); - glBindTexture(GL_TEXTURE_2D, getSceneTextureId()); - compositeScene(); + auto sceneTextureId = getSceneTextureId(); auto overlayTextureId = getOverlayTextureId(); + glBindTexture(GL_TEXTURE_2D, sceneTextureId); + compositeScene(); if (overlayTextureId) { - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glBindTexture(GL_TEXTURE_2D, overlayTextureId); + Context::Enable(Capability::Blend); + Context::BlendFunc(BlendFunction::SrcAlpha, BlendFunction::OneMinusSrcAlpha); compositeOverlay(); auto compositorHelper = DependencyManager::get(); @@ -507,10 +508,14 @@ void OpenGLDisplayPlugin::compositeLayers() { auto& cursorManager = Cursor::Manager::instance(); const auto& cursorData = _cursorsData[cursorManager.getCursor()->getIcon()]; glBindTexture(GL_TEXTURE_2D, cursorData.texture); + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, overlayTextureId); compositePointer(); + glBindTexture(GL_TEXTURE_2D, 0); + glActiveTexture(GL_TEXTURE0); } glBindTexture(GL_TEXTURE_2D, 0); - glDisable(GL_BLEND); + Context::Disable(Capability::Blend); } }); } @@ -549,7 +554,11 @@ float OpenGLDisplayPlugin::newFramePresentRate() const { } float OpenGLDisplayPlugin::droppedFrameRate() const { - return _droppedFrameRate.rate(); + float result; + withRenderThreadLock([&] { + result = _droppedFrameRate.rate(); + }); + return result; } float OpenGLDisplayPlugin::presentRate() const { @@ -664,3 +673,11 @@ void OpenGLDisplayPlugin::useProgram(const ProgramPtr& program) { _activeProgram = program; } } + +void OpenGLDisplayPlugin::assertIsRenderThread() const { + Q_ASSERT(QThread::currentThread() != _presentThread); +} + +void OpenGLDisplayPlugin::assertIsPresentThread() const { + Q_ASSERT(QThread::currentThread() == _presentThread); +} diff --git a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h index c87ff1bc93..ec8aa45840 100644 --- a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h +++ b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h @@ -109,7 +109,6 @@ protected: int32_t _alphaUniform { -1 }; ShapeWrapperPtr _plane; - mutable Mutex _mutex; RateCounter<> _droppedFrameRate; RateCounter<> _newFrameRate; RateCounter<> _presentRate; @@ -135,7 +134,27 @@ protected: BasicFramebufferWrapperPtr _compositeFramebuffer; bool _lockCurrentTexture { false }; + void assertIsRenderThread() const; + void assertIsPresentThread() const; + + template + void withPresentThreadLock(F f) const { + assertIsPresentThread(); + Lock lock(_presentMutex); + f(); + } + + template + void withRenderThreadLock(F f) const { + assertIsRenderThread(); + Lock lock(_presentMutex); + f(); + } + private: + // Any resource shared by the main thread and the presntaion thread must + // be serialized through this mutex + mutable Mutex _presentMutex; ProgramPtr _activeProgram; }; diff --git a/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp index 1616dcdb77..ce1a42971e 100644 --- a/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp @@ -9,6 +9,7 @@ #include #include +#include #include #include @@ -37,7 +38,6 @@ QRect HmdDisplayPlugin::getRecommendedOverlayRect() const { return CompositorHelper::VIRTUAL_SCREEN_RECOMMENDED_OVERLAY_RECT; } - bool HmdDisplayPlugin::internalActivate() { _monoPreview = _container->getBoolSetting("monoPreview", DEFAULT_MONO_VIEW); @@ -197,14 +197,43 @@ static ProgramPtr getReprojectionProgram() { #endif +static const char * LASER_VS = R"VS(#version 410 core +uniform mat4 mvp = mat4(1); + +in vec3 Position; + +out vec3 vPosition; + +void main() { + gl_Position = mvp * vec4(Position, 1); + vPosition = Position; +} + +)VS"; + +static const char * LASER_FS = R"FS(#version 410 core + +uniform vec4 color = vec4(1.0, 1.0, 1.0, 1.0); +in vec3 vPosition; + +out vec4 FragColor; + +void main() { + FragColor = color; +} + +)FS"; + void HmdDisplayPlugin::customizeContext() { Parent::customizeContext(); // Only enable mirroring if we know vsync is disabled enableVsync(false); _enablePreview = !isVsyncEnabled(); _sphereSection = loadSphereSection(_program, CompositorHelper::VIRTUAL_UI_TARGET_FOV.y, CompositorHelper::VIRTUAL_UI_ASPECT_RATIO); + compileProgram(_laserProgram, LASER_VS, LASER_FS); + _laserGeometry = loadLaser(_laserProgram); compileProgram(_reprojectionProgram, REPROJECTION_VS, REPROJECTION_FS); - + using namespace oglplus; REPROJECTION_MATRIX_LOCATION = Uniform(*_reprojectionProgram, "reprojection").Location(); INVERSE_PROJECTION_MATRIX_LOCATION = Uniform(*_reprojectionProgram, "inverseProjections").Location(); @@ -215,6 +244,8 @@ void HmdDisplayPlugin::uncustomizeContext() { _sphereSection.reset(); _compositeFramebuffer.reset(); _reprojectionProgram.reset(); + _laserProgram.reset(); + _laserGeometry.reset(); Parent::uncustomizeContext(); } @@ -285,6 +316,8 @@ void HmdDisplayPlugin::compositePointer() { Uniform(*_program, _mvpUniform).Set(mvp); _plane->Draw(); }); + + compositeLasers(); } void HmdDisplayPlugin::internalPresent() { @@ -343,22 +376,122 @@ void HmdDisplayPlugin::setEyeRenderPose(uint32_t frameIndex, Eye eye, const glm: void HmdDisplayPlugin::updateFrameData() { // Check if we have old frame data to discard - { - Lock lock(_mutex); + withPresentThreadLock([&] { auto itr = _frameInfos.find(_currentPresentFrameIndex); if (itr != _frameInfos.end()) { _frameInfos.erase(itr); } - } + }); Parent::updateFrameData(); - { - Lock lock(_mutex); + withPresentThreadLock([&] { _currentPresentFrameInfo = _frameInfos[_currentPresentFrameIndex]; - } + }); } glm::mat4 HmdDisplayPlugin::getHeadPose() const { return _currentRenderFrameInfo.renderPose; } + +bool HmdDisplayPlugin::setHandLaser(uint32_t hands, HandLaserMode mode, const vec4& color, const vec3& direction) { + HandLaserInfo info; + info.mode = mode; + info.color = color; + info.direction = direction; + withRenderThreadLock([&] { + if (hands & Hand::LeftHand) { + _handLasers[0] = info; + } + if (hands & Hand::RightHand) { + _handLasers[1] = info; + } + }); + // FIXME defer to a child class plugin to determine if hand lasers are actually + return true; +} + +static float calculateRayUiCollisionDistance(const glm::mat4& headPose, const glm::vec3& position, const glm::vec3& direction) { + auto relativePosition4 = glm::inverse(headPose) * vec4(position, 1); + auto relativePosition = vec3(relativePosition4) / relativePosition4.w; + auto relativeDirection = glm::inverse(glm::quat_cast(headPose)) * direction; + if (glm::abs(glm::length2(relativeDirection) - 1.0f) > EPSILON) { + relativeDirection = glm::normalize(relativeDirection); + } + float uiRadius = 1.0f; + float instersectionDistance; + if (!glm::intersectRaySphere(relativePosition, relativeDirection, vec3(0), uiRadius * uiRadius, instersectionDistance)) { + return -1; + } + return instersectionDistance; +} + +void HmdDisplayPlugin::compositeLasers() { + std::array handLasers; + std::array renderHandPoses; + withPresentThreadLock([&] { + handLasers = _handLasers; + renderHandPoses = _handPoses; + }); + + // If neither hand laser is activated, exit + if (!handLasers[0].valid() && !handLasers[1].valid()) { + return; + } + + static const glm::mat4 identity; + if (renderHandPoses[0] == identity && renderHandPoses[1] == identity) { + return; + } + + // Render hand lasers + using namespace oglplus; + useProgram(_laserProgram); + _laserGeometry->Use(); + std::array handLaserModelMatrices; + + for (int i = 0; i < 2; ++i) { + if (renderHandPoses[i] == identity) { + continue; + } + const auto& handLaser = handLasers[i]; + if (!handLaser.valid()) { + continue; + } + + const auto& laserDirection = handLaser.direction; + auto model = renderHandPoses[i]; + auto castDirection = glm::quat_cast(model) * laserDirection; + + // Find the intersection of the laser with he UI and use it to scale the model matrix + float distance = calculateRayUiCollisionDistance(_currentPresentFrameInfo.presentPose, vec3(renderHandPoses[i][3]), castDirection); + if (distance < 0) { + continue; + } + + // Make sure we rotate to match the desired laser direction + if (laserDirection != Vectors::UNIT_NEG_Z) { + auto rotation = glm::rotation(Vectors::UNIT_NEG_Z, laserDirection); + model = model * glm::mat4_cast(rotation); + } + + model = glm::scale(model, vec3(distance)); + handLaserModelMatrices[i] = model; + } + + for_each_eye([&](Eye eye) { + eyeViewport(eye); + auto eyePose = _currentPresentFrameInfo.presentPose * getEyeToHeadTransform(eye); + auto view = glm::inverse(eyePose); + const auto& projection = _eyeProjections[eye]; + for (int i = 0; i < 2; ++i) { + if (handLaserModelMatrices[i] == identity) { + continue; + } + Uniform(*_laserProgram, "mvp").Set(projection * view * handLaserModelMatrices[i]); + Uniform(*_laserProgram, "color").Set(handLasers[i].color); + _laserGeometry->Draw(); + // TODO render some kind of visual indicator at the intersection point with the UI. + } + }); +} diff --git a/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.h b/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.h index e6ceb7e376..7cdcf06e9a 100644 --- a/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.h +++ b/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.h @@ -30,7 +30,7 @@ public: virtual glm::mat4 getHeadPose() const override; - + bool setHandLaser(uint32_t hands, HandLaserMode mode, const vec4& color, const vec3& direction) override; protected: virtual void hmdPresent() = 0; @@ -47,6 +47,22 @@ protected: void uncustomizeContext() override; void updateFrameData() override; + void compositeLasers(); + + + struct HandLaserInfo { + HandLaserMode mode { HandLaserMode::None }; + vec4 color { 1.0f }; + vec3 direction { 0, 0, -1 }; + + // Is this hand laser info suitable for drawing? + bool valid() const { + return (mode != HandLaserMode::None && color.a > 0.0f && direction != vec3()); + } + }; + + std::array _handLasers; + std::array _handPoses; std::array _eyeOffsets; std::array _eyeProjections; std::array _eyeInverseProjections; @@ -75,5 +91,7 @@ private: bool _enableReprojection { true }; ShapeWrapperPtr _sphereSection; ProgramPtr _reprojectionProgram; + ProgramPtr _laserProgram; + ShapeWrapperPtr _laserGeometry; }; diff --git a/libraries/gl/src/gl/OglplusHelpers.cpp b/libraries/gl/src/gl/OglplusHelpers.cpp index 5bf0298593..7a535a806d 100644 --- a/libraries/gl/src/gl/OglplusHelpers.cpp +++ b/libraries/gl/src/gl/OglplusHelpers.cpp @@ -45,9 +45,11 @@ in vec2 vTexCoord; out vec4 FragColor; void main() { - FragColor = texture(sampler, vTexCoord); FragColor.a *= alpha; + if (FragColor.a <= 0.0) { + discard; + } } )FS"; @@ -359,6 +361,94 @@ ShapeWrapperPtr loadSphereSection(ProgramPtr program, float fov, float aspect, i ); } +namespace oglplus { + namespace shapes { + + class Laser : public DrawingInstructionWriter, public DrawMode { + public: + using IndexArray = std::vector; + using PosArray = std::vector; + /// The type of the index container returned by Indices() + // vertex positions + PosArray _pos_data; + IndexArray _idx_data; + unsigned int _prim_count { 0 }; + + public: + Laser() { + int vertices = 2; + _pos_data.resize(vertices * 3); + _pos_data[0] = 0; + _pos_data[1] = 0; + _pos_data[2] = 0; + + _pos_data[3] = 0; + _pos_data[4] = 0; + _pos_data[5] = -1; + + _idx_data.push_back(0); + _idx_data.push_back(1); + _prim_count = 1; + } + + /// Returns the winding direction of faces + FaceOrientation FaceWinding(void) const { + return FaceOrientation::CCW; + } + + /// Queries the bounding sphere coordinates and dimensions + template + void BoundingSphere(Sphere& bounding_sphere) const { + bounding_sphere = Sphere(0, 0, -0.5, 0.5); + } + + typedef GLuint(Laser::*VertexAttribFunc)(std::vector&) const; + + /// Makes the vertex positions and returns the number of values per vertex + template + GLuint Positions(std::vector& dest) const { + dest.clear(); + dest.insert(dest.begin(), _pos_data.begin(), _pos_data.end()); + return 3; + } + + typedef VertexAttribsInfo< + Laser, + std::tuple + > VertexAttribs; + + + /// Returns element indices that are used with the drawing instructions + const IndexArray & Indices(Default = Default()) const { + return _idx_data; + } + + /// Returns the instructions for rendering of faces + DrawingInstructions Instructions(PrimitiveType primitive) const { + DrawingInstructions instr = MakeInstructions(); + DrawOperation operation; + operation.method = DrawOperation::Method::DrawElements; + operation.mode = primitive; + operation.first = 0; + operation.count = _prim_count * 3; + operation.restart_index = DrawOperation::NoRestartIndex(); + operation.phase = 0; + AddInstruction(instr, operation); + return instr; + } + + /// Returns the instructions for rendering of faces + DrawingInstructions Instructions(Default = Default()) const { + return Instructions(PrimitiveType::Lines); + } + }; + } +} + +ShapeWrapperPtr loadLaser(const ProgramPtr& program) { + return std::make_shared(shapes::ShapeWrapper("Position", shapes::Laser(), *program)); +} + void TextureRecycler::setSize(const uvec2& size) { if (size == _size) { return; diff --git a/libraries/gl/src/gl/OglplusHelpers.h b/libraries/gl/src/gl/OglplusHelpers.h index afb06069b8..8940205b21 100644 --- a/libraries/gl/src/gl/OglplusHelpers.h +++ b/libraries/gl/src/gl/OglplusHelpers.h @@ -64,8 +64,9 @@ ProgramPtr loadCubemapShader(); void compileProgram(ProgramPtr & result, const std::string& vs, const std::string& fs); ShapeWrapperPtr loadSkybox(ProgramPtr program); ShapeWrapperPtr loadPlane(ProgramPtr program, float aspect = 1.0f); -ShapeWrapperPtr loadSphereSection(ProgramPtr program, float fov = PI / 3.0f * 2.0f, float aspect = 16.0f / 9.0f, int slices = 32, int stacks = 32); - +ShapeWrapperPtr loadSphereSection(ProgramPtr program, float fov = PI / 3.0f * 2.0f, float aspect = 16.0f / 9.0f, int slices = 128, int stacks = 128); +ShapeWrapperPtr loadLaser(const ProgramPtr& program); + // A basic wrapper for constructing a framebuffer with a renderbuffer // for the depth attachment and an undefined type for the color attachement diff --git a/libraries/plugins/src/plugins/DisplayPlugin.h b/libraries/plugins/src/plugins/DisplayPlugin.h index 1f6a16cd46..9cb4e071f3 100644 --- a/libraries/plugins/src/plugins/DisplayPlugin.h +++ b/libraries/plugins/src/plugins/DisplayPlugin.h @@ -168,6 +168,26 @@ public: static const QString& MENU_PATH(); + enum Hand { + LeftHand = 0x01, + RightHand = 0x02, + }; + + enum class HandLaserMode { + None, // Render no hand lasers + Overlay, // Render hand lasers only if they intersect with the UI layer, and stop at the UI layer + }; + + virtual bool setHandLaser( + uint32_t hands, // Bits from the Hand enum + HandLaserMode mode, // Mode in which to render + const vec4& color = vec4(1), // The color of the rendered laser + const vec3& direction = vec3(0, 0, -1) // The direction in which to render the hand lasers + ) { + return false; + } + + signals: void recommendedFramebufferSizeChanged(const QSize & size); // Indicates that this display plugin is no longer valid for use. diff --git a/plugins/oculus/src/OculusBaseDisplayPlugin.cpp b/plugins/oculus/src/OculusBaseDisplayPlugin.cpp index e9f8545cff..f5fdbd303c 100644 --- a/plugins/oculus/src/OculusBaseDisplayPlugin.cpp +++ b/plugins/oculus/src/OculusBaseDisplayPlugin.cpp @@ -24,8 +24,9 @@ bool OculusBaseDisplayPlugin::beginFrameRender(uint32_t frameIndex) { auto trackingState = ovr_GetTrackingState(_session, _currentRenderFrameInfo.predictedDisplayTime, ovrTrue); _currentRenderFrameInfo.renderPose = toGlm(trackingState.HeadPose.ThePose); _currentRenderFrameInfo.presentPose = _currentRenderFrameInfo.renderPose; - Lock lock(_mutex); - _frameInfos[frameIndex] = _currentRenderFrameInfo; + withRenderThreadLock([&] { + _frameInfos[frameIndex] = _currentRenderFrameInfo; + }); return true; } diff --git a/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.cpp b/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.cpp index 8e044fbc16..29a2a4bb1a 100644 --- a/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.cpp +++ b/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.cpp @@ -45,8 +45,9 @@ bool OculusLegacyDisplayPlugin::beginFrameRender(uint32_t frameIndex) { _currentRenderFrameInfo.predictedDisplayTime = _currentRenderFrameInfo.sensorSampleTime = ovr_GetTimeInSeconds(); _trackingState = ovrHmd_GetTrackingState(_hmd, _currentRenderFrameInfo.predictedDisplayTime); _currentRenderFrameInfo.rawRenderPose = _currentRenderFrameInfo.renderPose = toGlm(_trackingState.HeadPose.ThePose); - Lock lock(_mutex); - _frameInfos[frameIndex] = _currentRenderFrameInfo; + withRenderThreadLock([&]{ + _frameInfos[frameIndex] = _currentRenderFrameInfo; + }) return true; } diff --git a/plugins/openvr/src/OpenVrDisplayPlugin.cpp b/plugins/openvr/src/OpenVrDisplayPlugin.cpp index fbade9fd68..92c01dc0a3 100644 --- a/plugins/openvr/src/OpenVrDisplayPlugin.cpp +++ b/plugins/openvr/src/OpenVrDisplayPlugin.cpp @@ -29,11 +29,13 @@ Q_DECLARE_LOGGING_CATEGORY(displayplugins) const QString OpenVrDisplayPlugin::NAME("OpenVR (Vive)"); const QString StandingHMDSensorMode = "Standing HMD Sensor Mode"; // this probably shouldn't be hardcoded here -static vr::IVRCompositor* _compositor{ nullptr }; +static vr::IVRCompositor* _compositor { nullptr }; vr::TrackedDevicePose_t _trackedDevicePose[vr::k_unMaxTrackedDeviceCount]; + mat4 _trackedDevicePoseMat4[vr::k_unMaxTrackedDeviceCount]; vec3 _trackedDeviceLinearVelocities[vr::k_unMaxTrackedDeviceCount]; vec3 _trackedDeviceAngularVelocities[vr::k_unMaxTrackedDeviceCount]; + static mat4 _sensorResetMat; static std::array VR_EYES { { vr::Eye_Left, vr::Eye_Right } }; bool _openVrDisplayActive { false }; @@ -59,16 +61,14 @@ bool OpenVrDisplayPlugin::internalActivate() { // left + right eyes _renderTargetSize.x *= 2; - { - Lock lock(_poseMutex); + withRenderThreadLock([&] { openvr_for_each_eye([&](vr::Hmd_Eye eye) { _eyeOffsets[eye] = toGlm(_system->GetEyeToHeadTransform(eye)); _eyeProjections[eye] = toGlm(_system->GetProjectionMatrix(eye, DEFAULT_NEAR_CLIP, DEFAULT_FAR_CLIP, vr::API_OpenGL)); }); // FIXME Calculate the proper combined projection by using GetProjectionRaw values from both eyes _cullingProjection = _eyeProjections[0]; - - } + }); _compositor = vr::VRCompositor(); Q_ASSERT(_compositor); @@ -113,7 +113,7 @@ void OpenVrDisplayPlugin::internalDeactivate() { void OpenVrDisplayPlugin::customizeContext() { // Display plugins in DLLs must initialize glew locally static std::once_flag once; - std::call_once(once, []{ + std::call_once(once, [] { glewExperimental = true; GLenum err = glewInit(); glGetError(); // clear the potential error from glewExperimental @@ -123,9 +123,10 @@ void OpenVrDisplayPlugin::customizeContext() { } void OpenVrDisplayPlugin::resetSensors() { - Lock lock(_poseMutex); - glm::mat4 m = toGlm(_trackedDevicePose[0].mDeviceToAbsoluteTracking); - _sensorResetMat = glm::inverse(cancelOutRollAndPitch(m)); + withRenderThreadLock([&] { + glm::mat4 m = toGlm(_trackedDevicePose[0].mDeviceToAbsoluteTracking); + _sensorResetMat = glm::inverse(cancelOutRollAndPitch(m)); + }); } @@ -150,6 +151,24 @@ bool OpenVrDisplayPlugin::beginFrameRender(uint32_t frameIndex) { _system->GetDeviceToAbsoluteTrackingPose(vr::TrackingUniverseStanding, _currentRenderFrameInfo.predictedDisplayTime, _trackedDevicePose, vr::k_unMaxTrackedDeviceCount); + + vr::TrackedDeviceIndex_t handIndices[2] { vr::k_unTrackedDeviceIndexInvalid, vr::k_unTrackedDeviceIndexInvalid }; + { + vr::TrackedDeviceIndex_t controllerIndices[2] ; + auto trackedCount = _system->GetSortedTrackedDeviceIndicesOfClass(vr::TrackedDeviceClass_Controller, controllerIndices, 2); + // Find the left and right hand controllers, if they exist + for (uint32_t i = 0; i < std::min(trackedCount, 2); ++i) { + if (_trackedDevicePose[i].bPoseIsValid) { + auto role = _system->GetControllerRoleForTrackedDeviceIndex(controllerIndices[i]); + if (vr::TrackedControllerRole_LeftHand == role) { + handIndices[0] = controllerIndices[i]; + } else if (vr::TrackedControllerRole_RightHand == role) { + handIndices[1] = controllerIndices[i]; + } + } + } + } + // copy and process predictedTrackedDevicePoses for (int i = 0; i < vr::k_unMaxTrackedDeviceCount; i++) { _trackedDevicePoseMat4[i] = _sensorResetMat * toGlm(_trackedDevicePose[i].mDeviceToAbsoluteTracking); @@ -159,18 +178,27 @@ bool OpenVrDisplayPlugin::beginFrameRender(uint32_t frameIndex) { _currentRenderFrameInfo.rawRenderPose = toGlm(_trackedDevicePose[vr::k_unTrackedDeviceIndex_Hmd].mDeviceToAbsoluteTracking); _currentRenderFrameInfo.renderPose = _trackedDevicePoseMat4[vr::k_unTrackedDeviceIndex_Hmd]; - Lock lock(_mutex); - _frameInfos[frameIndex] = _currentRenderFrameInfo; + bool keyboardVisible = isOpenVrKeyboardShown(); + withRenderThreadLock([&] { + // Make controller poses available to the presentation thread + for (int i = 0; i < 2; ++i) { + if (keyboardVisible || handIndices[i] == vr::k_unTrackedDeviceIndexInvalid) { + _handPoses[i] = glm::mat4(); + } else { + _handPoses[i] = _sensorResetMat * toGlm(_trackedDevicePose[handIndices[i]].mDeviceToAbsoluteTracking); + } + } + _frameInfos[frameIndex] = _currentRenderFrameInfo; + }); return true; } void OpenVrDisplayPlugin::hmdPresent() { - PROFILE_RANGE_EX(__FUNCTION__, 0xff00ff00, (uint64_t)_currentPresentFrameIndex) // Flip y-axis since GL UV coords are backwards. - static vr::VRTextureBounds_t leftBounds{ 0, 0, 0.5f, 1 }; - static vr::VRTextureBounds_t rightBounds{ 0.5f, 0, 1, 1 }; + static vr::VRTextureBounds_t leftBounds { 0, 0, 0.5f, 1 }; + static vr::VRTextureBounds_t rightBounds { 0.5f, 0, 1, 1 }; vr::Texture_t texture { (void*)oglplus::GetName(_compositeFramebuffer->color), vr::API_OpenGL, vr::ColorSpace_Auto }; @@ -191,6 +219,10 @@ bool OpenVrDisplayPlugin::isHmdMounted() const { } void OpenVrDisplayPlugin::updatePresentPose() { + mat4 sensorResetMat; + withPresentThreadLock([&] { + sensorResetMat = _sensorResetMat; + }); { float fSecondsSinceLastVsync; _system->GetTimeSinceLastVsync(&fSecondsSinceLastVsync, nullptr); @@ -202,9 +234,8 @@ void OpenVrDisplayPlugin::updatePresentPose() { _system->GetDeviceToAbsoluteTrackingPose(vr::TrackingUniverseStanding, fPredictedSecondsFromNow, &pose, 1); _currentPresentFrameInfo.rawPresentPose = toGlm(pose.mDeviceToAbsoluteTracking); } - _currentPresentFrameInfo.presentPose = _sensorResetMat * _currentPresentFrameInfo.rawPresentPose; + _currentPresentFrameInfo.presentPose = sensorResetMat * _currentPresentFrameInfo.rawPresentPose; mat3 renderRotation(_currentPresentFrameInfo.rawRenderPose); mat3 presentRotation(_currentPresentFrameInfo.rawPresentPose); _currentPresentFrameInfo.presentReprojection = glm::mat3(glm::inverse(renderRotation) * presentRotation); } - diff --git a/plugins/openvr/src/OpenVrDisplayPlugin.h b/plugins/openvr/src/OpenVrDisplayPlugin.h index fda5e37c2a..ee693b8091 100644 --- a/plugins/openvr/src/OpenVrDisplayPlugin.h +++ b/plugins/openvr/src/OpenVrDisplayPlugin.h @@ -43,5 +43,4 @@ private: vr::IVRSystem* _system { nullptr }; std::atomic _hmdActivityLevel { vr::k_EDeviceActivityLevel_Unknown }; static const QString NAME; - mutable Mutex _poseMutex; }; diff --git a/plugins/openvr/src/OpenVrHelpers.cpp b/plugins/openvr/src/OpenVrHelpers.cpp index 1ff1c65ef8..e4cca6ecd6 100644 --- a/plugins/openvr/src/OpenVrHelpers.cpp +++ b/plugins/openvr/src/OpenVrHelpers.cpp @@ -208,6 +208,10 @@ void disableOpenVrKeyboard() { QObject::disconnect(_focusConnection); } +bool isOpenVrKeyboardShown() { + return _keyboardShown; +} + void handleOpenVrEvents() { if (!activeHmd) { diff --git a/plugins/openvr/src/OpenVrHelpers.h b/plugins/openvr/src/OpenVrHelpers.h index 426178cd65..db8bb4f2e8 100644 --- a/plugins/openvr/src/OpenVrHelpers.h +++ b/plugins/openvr/src/OpenVrHelpers.h @@ -20,6 +20,7 @@ void handleOpenVrEvents(); bool openVrQuitRequested(); void enableOpenVrKeyboard(); void disableOpenVrKeyboard(); +bool isOpenVrKeyboardShown(); template From bb3722d91516d120a6dc14592dc93ef330109efd Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Fri, 10 Jun 2016 01:36:25 -0700 Subject: [PATCH 22/35] trying again to fix mac build. --- plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.cpp b/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.cpp index 29a2a4bb1a..8d2bc24177 100644 --- a/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.cpp +++ b/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.cpp @@ -47,7 +47,7 @@ bool OculusLegacyDisplayPlugin::beginFrameRender(uint32_t frameIndex) { _currentRenderFrameInfo.rawRenderPose = _currentRenderFrameInfo.renderPose = toGlm(_trackingState.HeadPose.ThePose); withRenderThreadLock([&]{ _frameInfos[frameIndex] = _currentRenderFrameInfo; - }) + }); return true; } From 130c0dda318335d70e1d26de6625fb1bc46112ee Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Fri, 10 Jun 2016 10:09:09 -0700 Subject: [PATCH 23/35] PR feedback --- .../display-plugins/src/display-plugins/OpenGLDisplayPlugin.h | 2 +- .../src/display-plugins/hmd/HmdDisplayPlugin.cpp | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h index ec8aa45840..02a30a2570 100644 --- a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h +++ b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h @@ -152,7 +152,7 @@ protected: } private: - // Any resource shared by the main thread and the presntaion thread must + // Any resource shared by the main thread and the presentation thread must // be serialized through this mutex mutable Mutex _presentMutex; ProgramPtr _activeProgram; diff --git a/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp index ce1a42971e..9b71d3703b 100644 --- a/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp @@ -408,9 +408,11 @@ bool HmdDisplayPlugin::setHandLaser(uint32_t hands, HandLaserMode mode, const ve } }); // FIXME defer to a child class plugin to determine if hand lasers are actually + // available based on the presence or absence of hand controllers return true; } +// FIXME try to consolidate the duplication of logic between this function and a similar one in CompsitorHelper. static float calculateRayUiCollisionDistance(const glm::mat4& headPose, const glm::vec3& position, const glm::vec3& direction) { auto relativePosition4 = glm::inverse(headPose) * vec4(position, 1); auto relativePosition = vec3(relativePosition4) / relativePosition4.w; @@ -418,6 +420,7 @@ static float calculateRayUiCollisionDistance(const glm::mat4& headPose, const gl if (glm::abs(glm::length2(relativeDirection) - 1.0f) > EPSILON) { relativeDirection = glm::normalize(relativeDirection); } + // FIXME fetch the actual UI radius from... somewhere? float uiRadius = 1.0f; float instersectionDistance; if (!glm::intersectRaySphere(relativePosition, relativeDirection, vec3(0), uiRadius * uiRadius, instersectionDistance)) { From 342fc07d2904192d32283a7eddeb15c425c5507a Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Mon, 13 Jun 2016 13:06:56 -0700 Subject: [PATCH 24/35] select active element in edit.js after change --- scripts/system/html/entityProperties.html | 24 +++++++++-------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/scripts/system/html/entityProperties.html b/scripts/system/html/entityProperties.html index 2a82d8fa74..1c4c3740cd 100644 --- a/scripts/system/html/entityProperties.html +++ b/scripts/system/html/entityProperties.html @@ -546,17 +546,11 @@ disableProperties(); } else { - var activeElement = document.activeElement; - - try { - var selected = (activeElement - && activeElement.selectionStart == 0 - && activeElement.selectionEnd == activeElement.value.length); - } catch (e) { - var selected = false; - } + properties = data.selections[0].properties; + + //WE SHOULD ONLY UPDATE CHANGED VALUES elID.innerHTML = properties.id; elType.innerHTML = properties.type; @@ -572,6 +566,7 @@ enableProperties(); } + console.log('updated properties :: ',properties) elName.value = properties.name; @@ -811,11 +806,10 @@ elYTextureURL.value = properties.yTextureURL; elZTextureURL.value = properties.zTextureURL; } - - if (selected) { - activeElement.focus(); - activeElement.select(); - } + + var activeElement = document.activeElement; + + activeElement.select(); } } }); @@ -1178,7 +1172,7 @@ for (var i = 0; i < els.length; i++) { var clicked = false; var originalText; - els[i].onfocus = function() { + els[i].onfocus = function(e) { originalText = this.value; this.select(); clicked = false; From 567118f4a9053aca53ade3fb079ba14b4a2a2491 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Mon, 13 Jun 2016 13:08:12 -0700 Subject: [PATCH 25/35] cleanup --- scripts/system/html/entityProperties.html | 1 - 1 file changed, 1 deletion(-) diff --git a/scripts/system/html/entityProperties.html b/scripts/system/html/entityProperties.html index 1c4c3740cd..ca0f9be072 100644 --- a/scripts/system/html/entityProperties.html +++ b/scripts/system/html/entityProperties.html @@ -550,7 +550,6 @@ properties = data.selections[0].properties; - //WE SHOULD ONLY UPDATE CHANGED VALUES elID.innerHTML = properties.id; elType.innerHTML = properties.type; From 188590a891010e44b0b5c188f3095db3a7af0498 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Mon, 13 Jun 2016 13:08:22 -0700 Subject: [PATCH 26/35] cleanup --- scripts/system/html/entityProperties.html | 2 -- 1 file changed, 2 deletions(-) diff --git a/scripts/system/html/entityProperties.html b/scripts/system/html/entityProperties.html index ca0f9be072..c8edbdb369 100644 --- a/scripts/system/html/entityProperties.html +++ b/scripts/system/html/entityProperties.html @@ -564,8 +564,6 @@ } else { enableProperties(); } - - console.log('updated properties :: ',properties) elName.value = properties.name; From eba518cb65634edb8dd47824ecb01f25eb9b27ed Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 13 Jun 2016 14:26:41 -0700 Subject: [PATCH 27/35] try to make code that converts bullet-calculated values to parent-frame values more effecient --- libraries/physics/src/EntityMotionState.cpp | 53 +++++++-------------- libraries/shared/src/SpatiallyNestable.cpp | 27 ----------- libraries/shared/src/SpatiallyNestable.h | 4 -- 3 files changed, 17 insertions(+), 67 deletions(-) diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 5fffc9901b..8f22c576f0 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -271,44 +271,25 @@ bool EntityMotionState::isCandidateForOwnership() const { bool EntityMotionState::remoteSimulationOutOfSync(uint32_t simulationStep) { // NOTE: we only get here if we think we own the simulation assert(_body); + + bool parentTransformSuccess; + Transform localToWorld = _entity->getParentTransform(parentTransformSuccess); + Transform worldToLocal; + Transform worldVelocityToLocal; + if (parentTransformSuccess) { + localToWorld.evalInverse(worldToLocal); + worldVelocityToLocal = worldToLocal; + worldVelocityToLocal.setTranslation(glm::vec3(0.0f)); + } + // if we've never checked before, our _lastStep will be 0, and we need to initialize our state if (_lastStep == 0) { btTransform xform = _body->getWorldTransform(); - - // _serverPosition = _entity->worldPositionToParent(bulletToGLM(xform.getOrigin())); - // _serverRotation = _entity->worldRotationToParent(bulletToGLM(xform.getRotation())); - // _serverVelocity = _entity->worldVelocityToParent(getBodyLinearVelocityGTSigma()); - - - _serverPosition = bulletToGLM(xform.getOrigin()); - _serverRotation = bulletToGLM(xform.getRotation()); - _serverVelocity = getBodyLinearVelocityGTSigma(); - bool success; - Transform parentTransform = _entity->getParentTransform(success); - if (success) { - Transform bodyTransform; - bodyTransform.setTranslation(_serverPosition); - bodyTransform.setRotation(_serverRotation); - Transform result; - Transform::inverseMult(result, parentTransform, bodyTransform); - _serverPosition = result.getTranslation(); - _serverRotation = result.getRotation(); - - // transform velocity into parent-frame - parentTransform.setTranslation(glm::vec3(0.0f)); - Transform velocityTransform; - velocityTransform.setTranslation(_serverVelocity); - Transform myWorldTransform; - Transform::mult(myWorldTransform, parentTransform, velocityTransform); - myWorldTransform.setTranslation(_serverVelocity); - Transform::inverseMult(result, parentTransform, myWorldTransform); - _serverVelocity = result.getTranslation(); - } - - - + _serverPosition = worldToLocal.transform(bulletToGLM(xform.getOrigin())); + _serverRotation = worldToLocal.getRotation() * bulletToGLM(xform.getRotation()); + _serverVelocity = worldVelocityToLocal.transform(getBodyLinearVelocityGTSigma()); _serverAcceleration = Vectors::ZERO; - _serverAngularVelocity = _entity->worldVelocityToParent(bulletToGLM(_body->getAngularVelocity())); + _serverAngularVelocity = worldVelocityToLocal.transform(bulletToGLM(_body->getAngularVelocity())); _lastStep = simulationStep; _serverActionData = _entity->getActionData(); _numInactiveUpdates = 1; @@ -381,7 +362,7 @@ bool EntityMotionState::remoteSimulationOutOfSync(uint32_t simulationStep) { // compute position error btTransform worldTrans = _body->getWorldTransform(); - glm::vec3 position = _entity->worldPositionToParent(bulletToGLM(worldTrans.getOrigin())); + glm::vec3 position = worldToLocal.transform(bulletToGLM(worldTrans.getOrigin())); float dx2 = glm::distance2(position, _serverPosition); const float MAX_POSITION_ERROR_SQUARED = 0.000004f; // corresponds to 2mm @@ -416,7 +397,7 @@ bool EntityMotionState::remoteSimulationOutOfSync(uint32_t simulationStep) { } } const float MIN_ROTATION_DOT = 0.99999f; // This corresponds to about 0.5 degrees of rotation - glm::quat actualRotation = _entity->worldRotationToParent(bulletToGLM(worldTrans.getRotation())); + glm::quat actualRotation = worldToLocal.getRotation() * bulletToGLM(worldTrans.getRotation()); #ifdef WANT_DEBUG if ((fabsf(glm::dot(actualRotation, _serverRotation)) < MIN_ROTATION_DOT)) { diff --git a/libraries/shared/src/SpatiallyNestable.cpp b/libraries/shared/src/SpatiallyNestable.cpp index 6edf80ab98..29a033f340 100644 --- a/libraries/shared/src/SpatiallyNestable.cpp +++ b/libraries/shared/src/SpatiallyNestable.cpp @@ -174,15 +174,6 @@ glm::vec3 SpatiallyNestable::worldToLocal(const glm::vec3& position, return result.getTranslation(); } -glm::vec3 SpatiallyNestable::worldPositionToParent(const glm::vec3& position) { - bool success; - glm::vec3 result = SpatiallyNestable::worldToLocal(position, getParentID(), getParentJointIndex(), success); - if (!success) { - qDebug() << "Warning -- worldToLocal failed" << getID(); - } - return result; -} - glm::vec3 SpatiallyNestable::worldVelocityToLocal(const glm::vec3& velocity, // can be linear or angular const QUuid& parentID, int parentJointIndex, bool& success) { @@ -225,15 +216,6 @@ glm::vec3 SpatiallyNestable::worldVelocityToLocal(const glm::vec3& velocity, // return result.getTranslation(); } -glm::vec3 SpatiallyNestable::worldVelocityToParent(const glm::vec3& velocity) { - bool success; - glm::vec3 result = SpatiallyNestable::worldVelocityToLocal(velocity, getParentID(), getParentJointIndex(), success); - if (!success) { - qDebug() << "Warning -- worldVelocityToLocal failed" << getID(); - } - return result; -} - glm::quat SpatiallyNestable::worldToLocal(const glm::quat& orientation, const QUuid& parentID, int parentJointIndex, bool& success) { @@ -274,15 +256,6 @@ glm::quat SpatiallyNestable::worldToLocal(const glm::quat& orientation, return result.getRotation(); } -glm::quat SpatiallyNestable::worldRotationToParent(const glm::quat& orientation) { - bool success; - glm::quat result = SpatiallyNestable::worldToLocal(orientation, getParentID(), getParentJointIndex(), success); - if (!success) { - qDebug() << "Warning -- worldToLocal failed" << getID(); - } - return result; -} - glm::vec3 SpatiallyNestable::localToWorld(const glm::vec3& position, const QUuid& parentID, int parentJointIndex, bool& success) { diff --git a/libraries/shared/src/SpatiallyNestable.h b/libraries/shared/src/SpatiallyNestable.h index ffb00ac040..23beffda53 100644 --- a/libraries/shared/src/SpatiallyNestable.h +++ b/libraries/shared/src/SpatiallyNestable.h @@ -53,10 +53,6 @@ public: static glm::vec3 localToWorld(const glm::vec3& position, const QUuid& parentID, int parentJointIndex, bool& success); static glm::quat localToWorld(const glm::quat& orientation, const QUuid& parentID, int parentJointIndex, bool& success); - glm::vec3 worldPositionToParent(const glm::vec3& position); - glm::vec3 worldVelocityToParent(const glm::vec3& velocity); - glm::quat worldRotationToParent(const glm::quat& orientation); - // world frame virtual const Transform getTransform(bool& success, int depth = 0) const; virtual void setTransform(const Transform& transform, bool& success); From 62051ad297056a5fd0e07966c9ea0cc108f6f3f4 Mon Sep 17 00:00:00 2001 From: Bradley Austin Davis Date: Mon, 13 Jun 2016 14:40:15 -0700 Subject: [PATCH 28/35] Working on touch --- .../controllers/src/controllers/Forward.h | 1 + .../oculus/src/OculusBaseDisplayPlugin.cpp | 10 +++ .../oculus/src/OculusControllerManager.cpp | 82 +---------------- plugins/oculus/src/OculusHelpers.cpp | 88 +++++++++++++++++++ plugins/oculus/src/OculusHelpers.h | 5 ++ 5 files changed, 106 insertions(+), 80 deletions(-) diff --git a/libraries/controllers/src/controllers/Forward.h b/libraries/controllers/src/controllers/Forward.h index e1a62556d4..23dd162831 100644 --- a/libraries/controllers/src/controllers/Forward.h +++ b/libraries/controllers/src/controllers/Forward.h @@ -32,6 +32,7 @@ class Mapping; using MappingPointer = std::shared_ptr; using MappingList = std::list; +struct Pose; } #endif diff --git a/plugins/oculus/src/OculusBaseDisplayPlugin.cpp b/plugins/oculus/src/OculusBaseDisplayPlugin.cpp index f5fdbd303c..a16f630bf8 100644 --- a/plugins/oculus/src/OculusBaseDisplayPlugin.cpp +++ b/plugins/oculus/src/OculusBaseDisplayPlugin.cpp @@ -24,7 +24,17 @@ bool OculusBaseDisplayPlugin::beginFrameRender(uint32_t frameIndex) { auto trackingState = ovr_GetTrackingState(_session, _currentRenderFrameInfo.predictedDisplayTime, ovrTrue); _currentRenderFrameInfo.renderPose = toGlm(trackingState.HeadPose.ThePose); _currentRenderFrameInfo.presentPose = _currentRenderFrameInfo.renderPose; + withRenderThreadLock([&] { + // Make controller poses available to the presentation thread + ovr_for_each_hand([&](ovrHandType hand){ + static const auto REQUIRED_HAND_STATUS = ovrStatus_OrientationTracked & ovrStatus_PositionTracked; + if (REQUIRED_HAND_STATUS == (trackingState.HandStatusFlags[hand] & REQUIRED_HAND_STATUS)) { + _handPoses[hand] = toGlm(trackingState.HandPoses[hand].ThePose); + } else { + _handPoses[hand] = glm::mat4(); + } + }); _frameInfos[frameIndex] = _currentRenderFrameInfo; }); return true; diff --git a/plugins/oculus/src/OculusControllerManager.cpp b/plugins/oculus/src/OculusControllerManager.cpp index 9f0e76363b..0e9ca21804 100644 --- a/plugins/oculus/src/OculusControllerManager.cpp +++ b/plugins/oculus/src/OculusControllerManager.cpp @@ -243,91 +243,13 @@ void OculusControllerManager::TouchDevice::focusOutEvent() { void OculusControllerManager::TouchDevice::handlePose(float deltaTime, const controller::InputCalibrationData& inputCalibrationData, ovrHandType hand, const ovrPoseStatef& handPose) { - // When the sensor-to-world rotation is identity the coordinate axes look like this: - // - // user - // forward - // -z - // | - // y| user - // y o----x right - // o-----x user - // | up - // | - // z - // - // Rift - - // From ABOVE the hand canonical axes looks like this: - // - // | | | | y | | | | - // | | | | | | | | | - // | | | | | - // |left | / x---- + \ |right| - // | _/ z \_ | - // | | | | - // | | | | - // - - // So when the user is in Rift space facing the -zAxis with hands outstretched and palms down - // the rotation to align the Touch axes with those of the hands is: - // - // touchToHand = halfTurnAboutY * quaterTurnAboutX - - // Due to how the Touch controllers fit into the palm there is an offset that is different for each hand. - // You can think of this offset as the inverse of the measured rotation when the hands are posed, such that - // the combination (measurement * offset) is identity at this orientation. - // - // Qoffset = glm::inverse(deltaRotation when hand is posed fingers forward, palm down) - // - // An approximate offset for the Touch can be obtained by inspection: - // - // Qoffset = glm::inverse(glm::angleAxis(sign * PI/2.0f, zAxis) * glm::angleAxis(PI/4.0f, xAxis)) - // - // So the full equation is: - // - // Q = combinedMeasurement * touchToHand - // - // Q = (deltaQ * QOffset) * (yFlip * quarterTurnAboutX) - // - // Q = (deltaQ * inverse(deltaQForAlignedHand)) * (yFlip * quarterTurnAboutX) - auto poseId = hand == ovrHand_Left ? controller::LEFT_HAND : controller::RIGHT_HAND; auto& pose = _poseStateMap[poseId]; - - static const glm::quat yFlip = glm::angleAxis(PI, Vectors::UNIT_Y); - static const glm::quat quarterX = glm::angleAxis(PI_OVER_TWO, Vectors::UNIT_X); - static const glm::quat touchToHand = yFlip * quarterX; - - static const glm::quat leftQuarterZ = glm::angleAxis(-PI_OVER_TWO, Vectors::UNIT_Z); - static const glm::quat rightQuarterZ = glm::angleAxis(PI_OVER_TWO, Vectors::UNIT_Z); - static const glm::quat eighthX = glm::angleAxis(PI / 4.0f, Vectors::UNIT_X); - - static const glm::quat leftRotationOffset = glm::inverse(leftQuarterZ * eighthX) * touchToHand; - static const glm::quat rightRotationOffset = glm::inverse(rightQuarterZ * eighthX) * touchToHand; - - static const float CONTROLLER_LENGTH_OFFSET = 0.0762f; // three inches - static const glm::vec3 CONTROLLER_OFFSET = glm::vec3(CONTROLLER_LENGTH_OFFSET / 2.0f, - CONTROLLER_LENGTH_OFFSET / 2.0f, - CONTROLLER_LENGTH_OFFSET * 2.0f); - static const glm::vec3 leftTranslationOffset = glm::vec3(-1.0f, 1.0f, 1.0f) * CONTROLLER_OFFSET; - static const glm::vec3 rightTranslationOffset = CONTROLLER_OFFSET; - - auto translationOffset = (hand == ovrHand_Left ? leftTranslationOffset : rightTranslationOffset); - auto rotationOffset = (hand == ovrHand_Left ? leftRotationOffset : rightRotationOffset); - - glm::quat rotation = toGlm(handPose.ThePose.Orientation); - - pose.translation = toGlm(handPose.ThePose.Position); - pose.translation += rotation * translationOffset; - pose.rotation = rotation * rotationOffset; - pose.angularVelocity = toGlm(handPose.AngularVelocity); - pose.velocity = toGlm(handPose.LinearVelocity); - pose.valid = true; - + pose = ovrControllerPoseToHandPose(hand, handPose); // transform into avatar frame glm::mat4 controllerToAvatar = glm::inverse(inputCalibrationData.avatarMat) * inputCalibrationData.sensorToWorldMat; pose = pose.transform(controllerToAvatar); + } bool OculusControllerManager::TouchDevice::triggerHapticPulse(float strength, float duration, controller::Hand hand) { diff --git a/plugins/oculus/src/OculusHelpers.cpp b/plugins/oculus/src/OculusHelpers.cpp index 6ddace684b..705c0a0781 100644 --- a/plugins/oculus/src/OculusHelpers.cpp +++ b/plugins/oculus/src/OculusHelpers.cpp @@ -15,6 +15,9 @@ #include #include +#include +#include + using Mutex = std::mutex; using Lock = std::unique_lock; @@ -191,3 +194,88 @@ void SwapFramebufferWrapper::onBind(oglplus::Framebuffer::Target target) { void SwapFramebufferWrapper::onUnbind(oglplus::Framebuffer::Target target) { glFramebufferTexture2D(toEnum(target), GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0); } + + +controller::Pose ovrControllerPoseToHandPose( + ovrHandType hand, + const ovrPoseStatef& handPose) { + // When the sensor-to-world rotation is identity the coordinate axes look like this: + // + // user + // forward + // -z + // | + // y| user + // y o----x right + // o-----x user + // | up + // | + // z + // + // Rift + + // From ABOVE the hand canonical axes looks like this: + // + // | | | | y | | | | + // | | | | | | | | | + // | | | | | + // |left | / x---- + \ |right| + // | _/ z \_ | + // | | | | + // | | | | + // + + // So when the user is in Rift space facing the -zAxis with hands outstretched and palms down + // the rotation to align the Touch axes with those of the hands is: + // + // touchToHand = halfTurnAboutY * quaterTurnAboutX + + // Due to how the Touch controllers fit into the palm there is an offset that is different for each hand. + // You can think of this offset as the inverse of the measured rotation when the hands are posed, such that + // the combination (measurement * offset) is identity at this orientation. + // + // Qoffset = glm::inverse(deltaRotation when hand is posed fingers forward, palm down) + // + // An approximate offset for the Touch can be obtained by inspection: + // + // Qoffset = glm::inverse(glm::angleAxis(sign * PI/2.0f, zAxis) * glm::angleAxis(PI/4.0f, xAxis)) + // + // So the full equation is: + // + // Q = combinedMeasurement * touchToHand + // + // Q = (deltaQ * QOffset) * (yFlip * quarterTurnAboutX) + // + // Q = (deltaQ * inverse(deltaQForAlignedHand)) * (yFlip * quarterTurnAboutX) + static const glm::quat yFlip = glm::angleAxis(PI, Vectors::UNIT_Y); + static const glm::quat quarterX = glm::angleAxis(PI_OVER_TWO, Vectors::UNIT_X); + static const glm::quat touchToHand = yFlip * quarterX; + + static const glm::quat leftQuarterZ = glm::angleAxis(-PI_OVER_TWO, Vectors::UNIT_Z); + static const glm::quat rightQuarterZ = glm::angleAxis(PI_OVER_TWO, Vectors::UNIT_Z); + static const glm::quat eighthX = glm::angleAxis(PI / 4.0f, Vectors::UNIT_X); + + static const glm::quat leftRotationOffset = glm::inverse(leftQuarterZ * eighthX) * touchToHand; + static const glm::quat rightRotationOffset = glm::inverse(rightQuarterZ * eighthX) * touchToHand; + + static const float CONTROLLER_LENGTH_OFFSET = 0.0762f; // three inches + static const glm::vec3 CONTROLLER_OFFSET = glm::vec3(CONTROLLER_LENGTH_OFFSET / 2.0f, + CONTROLLER_LENGTH_OFFSET / 2.0f, + CONTROLLER_LENGTH_OFFSET * 2.0f); + static const glm::vec3 leftTranslationOffset = glm::vec3(-1.0f, 1.0f, 1.0f) * CONTROLLER_OFFSET; + static const glm::vec3 rightTranslationOffset = CONTROLLER_OFFSET; + + auto translationOffset = (hand == ovrHand_Left ? leftTranslationOffset : rightTranslationOffset); + auto rotationOffset = (hand == ovrHand_Left ? leftRotationOffset : rightRotationOffset); + + glm::quat rotation = toGlm(handPose.ThePose.Orientation); + + controller::Pose pose; + pose.translation = toGlm(handPose.ThePose.Position); + pose.translation += rotation * translationOffset; + pose.rotation = rotation * rotationOffset; + pose.angularVelocity = toGlm(handPose.AngularVelocity); + pose.velocity = toGlm(handPose.LinearVelocity); + pose.valid = true; + return pose; +} \ No newline at end of file diff --git a/plugins/oculus/src/OculusHelpers.h b/plugins/oculus/src/OculusHelpers.h index 2f13c45466..66cdccf15a 100644 --- a/plugins/oculus/src/OculusHelpers.h +++ b/plugins/oculus/src/OculusHelpers.h @@ -13,6 +13,7 @@ #include #include +#include void logWarning(const char* what); void logFatal(const char* what); @@ -128,3 +129,7 @@ protected: private: ovrSession _session; }; + +controller::Pose ovrControllerPoseToHandPose( + ovrHandType hand, + const ovrPoseStatef& handPose); From f8f62a4ff1120f4a83cea57b82b614ed80fa0d4f Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 13 Jun 2016 15:10:52 -0700 Subject: [PATCH 29/35] remove unused function --- libraries/shared/src/SpatiallyNestable.cpp | 42 ---------------------- libraries/shared/src/SpatiallyNestable.h | 2 -- 2 files changed, 44 deletions(-) diff --git a/libraries/shared/src/SpatiallyNestable.cpp b/libraries/shared/src/SpatiallyNestable.cpp index 29a033f340..2a3cb4af47 100644 --- a/libraries/shared/src/SpatiallyNestable.cpp +++ b/libraries/shared/src/SpatiallyNestable.cpp @@ -174,48 +174,6 @@ glm::vec3 SpatiallyNestable::worldToLocal(const glm::vec3& position, return result.getTranslation(); } -glm::vec3 SpatiallyNestable::worldVelocityToLocal(const glm::vec3& velocity, // can be linear or angular - const QUuid& parentID, int parentJointIndex, - bool& success) { - Transform result; - QSharedPointer parentFinder = DependencyManager::get(); - if (!parentFinder) { - success = false; - return glm::vec3(); - } - - Transform parentTransform; - auto parentWP = parentFinder->find(parentID, success); - if (!success) { - return glm::vec3(); - } - - auto parent = parentWP.lock(); - if (!parentID.isNull() && !parent) { - success = false; - return glm::vec3(); - } - - if (parent) { - parentTransform = parent->getTransform(parentJointIndex, success); - if (!success) { - return glm::vec3(); - } - parentTransform.setScale(1.0f); // TODO: scale - } - success = true; - - parentTransform.setTranslation(glm::vec3(0.0f)); - - Transform velocityTransform; - velocityTransform.setTranslation(velocity); - Transform myWorldTransform; - Transform::mult(myWorldTransform, parentTransform, velocityTransform); - myWorldTransform.setTranslation(velocity); - Transform::inverseMult(result, parentTransform, myWorldTransform); - return result.getTranslation(); -} - glm::quat SpatiallyNestable::worldToLocal(const glm::quat& orientation, const QUuid& parentID, int parentJointIndex, bool& success) { diff --git a/libraries/shared/src/SpatiallyNestable.h b/libraries/shared/src/SpatiallyNestable.h index 23beffda53..c2563a1188 100644 --- a/libraries/shared/src/SpatiallyNestable.h +++ b/libraries/shared/src/SpatiallyNestable.h @@ -46,8 +46,6 @@ public: virtual void setParentJointIndex(quint16 parentJointIndex); static glm::vec3 worldToLocal(const glm::vec3& position, const QUuid& parentID, int parentJointIndex, bool& success); - static glm::vec3 worldVelocityToLocal(const glm::vec3& position, const QUuid& parentID, - int parentJointIndex, bool& success); static glm::quat worldToLocal(const glm::quat& orientation, const QUuid& parentID, int parentJointIndex, bool& success); static glm::vec3 localToWorld(const glm::vec3& position, const QUuid& parentID, int parentJointIndex, bool& success); From b9bf7977535e4780bf99cb14f97d4413927bf8b5 Mon Sep 17 00:00:00 2001 From: Bradley Austin Davis Date: Mon, 13 Jun 2016 15:26:48 -0700 Subject: [PATCH 30/35] Fixing issues with unclosed groups in settings persistence --- libraries/networking/src/AccountManager.cpp | 1 + libraries/script-engine/src/ScriptEngines.cpp | 1 + libraries/shared/src/SettingHandle.cpp | 9 +++++++++ libraries/shared/src/SettingHandle.h | 2 ++ libraries/shared/src/SettingInterface.cpp | 2 ++ 5 files changed, 15 insertions(+) diff --git a/libraries/networking/src/AccountManager.cpp b/libraries/networking/src/AccountManager.cpp index bac031885f..26b3801ec1 100644 --- a/libraries/networking/src/AccountManager.cpp +++ b/libraries/networking/src/AccountManager.cpp @@ -173,6 +173,7 @@ void AccountManager::setAuthURL(const QUrl& authURL) { << "from previous settings file"; } } + settings.endGroup(); if (_accountInfo.getAccessToken().token.isEmpty()) { qCWarning(networking) << "Unable to load account file. No existing account settings will be loaded."; diff --git a/libraries/script-engine/src/ScriptEngines.cpp b/libraries/script-engine/src/ScriptEngines.cpp index 29c223f4b3..beddc21787 100644 --- a/libraries/script-engine/src/ScriptEngines.cpp +++ b/libraries/script-engine/src/ScriptEngines.cpp @@ -334,6 +334,7 @@ void ScriptEngines::clearScripts() { Settings settings; settings.beginWriteArray(SETTINGS_KEY); settings.remove(""); + settings.endArray(); } void ScriptEngines::saveScripts() { diff --git a/libraries/shared/src/SettingHandle.cpp b/libraries/shared/src/SettingHandle.cpp index b2f23f5a04..13f9ea48ce 100644 --- a/libraries/shared/src/SettingHandle.cpp +++ b/libraries/shared/src/SettingHandle.cpp @@ -18,6 +18,7 @@ const QString Settings::firstRun { "firstRun" }; + Settings::Settings() : _manager(DependencyManager::get()), _locker(&(_manager->getLock())) @@ -25,6 +26,9 @@ Settings::Settings() : } Settings::~Settings() { + if (_prefixes.size() != 0) { + qFatal("Unstable Settings Prefixes: You must call endGroup for every beginGroup and endArray for every begin*Array call"); + } } void Settings::remove(const QString& key) { @@ -50,14 +54,17 @@ bool Settings::contains(const QString& key) const { } int Settings::beginReadArray(const QString & prefix) { + _prefixes.push(prefix); return _manager->beginReadArray(prefix); } void Settings::beginWriteArray(const QString& prefix, int size) { + _prefixes.push(prefix); _manager->beginWriteArray(prefix, size); } void Settings::endArray() { + _prefixes.pop(); _manager->endArray(); } @@ -66,10 +73,12 @@ void Settings::setArrayIndex(int i) { } void Settings::beginGroup(const QString& prefix) { + _prefixes.push(prefix); _manager->beginGroup(prefix); } void Settings::endGroup() { + _prefixes.pop(); _manager->endGroup(); } diff --git a/libraries/shared/src/SettingHandle.h b/libraries/shared/src/SettingHandle.h index e83c563036..f19fc5875b 100644 --- a/libraries/shared/src/SettingHandle.h +++ b/libraries/shared/src/SettingHandle.h @@ -58,8 +58,10 @@ public: void setQuatValue(const QString& name, const glm::quat& quatValue); void getQuatValueIfValid(const QString& name, glm::quat& quatValue); +private: QSharedPointer _manager; QWriteLocker _locker; + QStack _prefixes; }; namespace Setting { diff --git a/libraries/shared/src/SettingInterface.cpp b/libraries/shared/src/SettingInterface.cpp index 630d52bf7d..1ebaa5cf82 100644 --- a/libraries/shared/src/SettingInterface.cpp +++ b/libraries/shared/src/SettingInterface.cpp @@ -98,6 +98,8 @@ namespace Setting { // Register Handle manager->registerHandle(this); _isInitialized = true; + } else { + qWarning() << "Settings interface used after manager destroyed"; } // Load value from disk From 526fc7d062366dbf3b2be7c8e87b80c70d01e391 Mon Sep 17 00:00:00 2001 From: howard-stearns Date: Mon, 13 Jun 2016 17:13:10 -0700 Subject: [PATCH 31/35] Make handControllerGrab independent of whether we're using laser or Reticle. --- scripts/system/controllers/handControllerGrab.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/scripts/system/controllers/handControllerGrab.js b/scripts/system/controllers/handControllerGrab.js index 25cd100991..53c16f26c1 100644 --- a/scripts/system/controllers/handControllerGrab.js +++ b/scripts/system/controllers/handControllerGrab.js @@ -300,7 +300,10 @@ function propsArePhysical(props) { // and we should not be showing lasers when someone else is using the Reticle to indicate a 2D minor mode. var EXTERNALLY_MANAGED_2D_MINOR_MODE = true; function isIn2DMode() { - return EXTERNALLY_MANAGED_2D_MINOR_MODE && Reticle.visible; + // In this version, we make our own determination of whether we're aimed a HUD element, + // because other scripts (such as handControllerPointer) might be using some other visualization + // instead of setting Reticle.visible. + return EXTERNALLY_MANAGED_2D_MINOR_MODE && (Reticle.pointingAtSystemOverlay || Overlays.getOverlayAtPoint(Reticle.position)); } function restore2DMode() { if (!EXTERNALLY_MANAGED_2D_MINOR_MODE) { From dfd03d5e6184ffb7a0f3b9a0b81e584dcf78e2a6 Mon Sep 17 00:00:00 2001 From: howard-stearns Date: Mon, 13 Jun 2016 17:15:51 -0700 Subject: [PATCH 32/35] Prepare for working laser. But at this point, we still show the laser AND the Reticle. --- .../system/controllers/handControllerPointer.js | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/scripts/system/controllers/handControllerPointer.js b/scripts/system/controllers/handControllerPointer.js index 1728647e5e..f5c0c4bb7c 100644 --- a/scripts/system/controllers/handControllerPointer.js +++ b/scripts/system/controllers/handControllerPointer.js @@ -319,6 +319,7 @@ function toggleHand() { // unequivocally switch which hand controls mouse positi activeTrigger = rightTrigger; activeHudLaser = RIGHT_HUD_LASER; } + clearSystemLaser(); } function makeToggleAction(hand) { // return a function(0|1) that makes the specified hand control mouse when 1 return function (on) { @@ -335,8 +336,8 @@ Script.scriptEnding.connect(clickMapping.disable); clickMapping.from(Controller.Standard.RT).peek().to(rightTrigger.triggerPress); clickMapping.from(Controller.Standard.LT).peek().to(leftTrigger.triggerPress); // Full smoothed trigger is a click. -clickMapping.from(rightTrigger.full).to(Controller.Actions.ReticleClick); -clickMapping.from(leftTrigger.full).to(Controller.Actions.ReticleClick); +clickMapping.from(rightTrigger.full).when(isPointingAtOverlay).to(Controller.Actions.ReticleClick); +clickMapping.from(leftTrigger.full).when(isPointingAtOverlay).to(Controller.Actions.ReticleClick); clickMapping.from(Controller.Standard.RightSecondaryThumb).peek().to(Controller.Actions.ContextMenu); clickMapping.from(Controller.Standard.LeftSecondaryThumb).peek().to(Controller.Actions.ContextMenu); // Partial smoothed trigger is activation. @@ -363,8 +364,8 @@ Script.scriptEnding.connect(function () { overlays.forEach(Overlays.deleteOverlay); }); var visualizationIsShowing = false; // Not whether it desired, but simply whether it is. Just an optimziation. -var systemLaserOn = false; var SYSTEM_LASER_DIRECTION = Vec3.normalize({x: 0, y: -1, z: -1}); // Guessing 45 degrees. +var systemLaserOn = false; function clearSystemLaser() { if (!systemLaserOn) { return; @@ -379,8 +380,12 @@ function turnOffVisualization(optionalEnableClicks) { // because we're showing c clearSystemLaser(); } else if (!systemLaserOn) { print('FIXME remove: setHandLasers', activeHudLaser, true, JSON.stringify(LASER_COLOR_XYZW), JSON.stringify(SYSTEM_LASER_DIRECTION)); - HMD.setHandLasers(activeHudLaser, true, LASER_COLOR_XYZW, SYSTEM_LASER_DIRECTION); + // If the active plugin doesn't implement hand lasers, show the mouse reticle instead. + /*Reticle.visible = !*/HMD.setHandLasers(activeHudLaser, true, LASER_COLOR_XYZW, SYSTEM_LASER_DIRECTION); + Reticle.visible = true; // FIXME: just for now, while hand lasers has the bug that requires this. systemLaserOn = true; + } else { + Reticle.visible = true; } if (!visualizationIsShowing) { return; @@ -415,9 +420,11 @@ function updateVisualization(controllerPosition, controllerDirection, hudPositio // For now, though, we present a false projection of the cursor onto whatever is below it. This is // different from the hand beam termination because the false projection is from the camera, while // the hand beam termination is from the hand. + /* // FIXME: We can tighten this up later, once we know what will and won't be included. var eye = Camera.getPosition(); var falseProjection = intersection3d(eye, Vec3.subtract(hudPosition3d, eye)); Overlays.editOverlay(fakeProjectionBall, {visible: true, position: falseProjection}); + */ Reticle.visible = false; return visualizationIsShowing; // In case we change caller to act conditionally. @@ -465,7 +472,6 @@ function update() { if (HMD.active) { // Doesn't hurt anything without the guard, but consider it documentation. Reticle.depth = SPHERICAL_HUD_DISTANCE; // NOT CORRECT IF WE SWITCH TO OFFSET SPHERE! } - Reticle.visible = true; return turnOffVisualization(true); } // We are not pointing at a HUD element (but it could be a 3d overlay). From 6707f889b82d2e8fdaa065ac32e4d536f24b8dd6 Mon Sep 17 00:00:00 2001 From: Bradley Austin Davis Date: Mon, 13 Jun 2016 17:21:09 -0700 Subject: [PATCH 33/35] Fixing laser offset, support laser in Oculus --- .../display-plugins/OpenGLDisplayPlugin.cpp | 1 + .../src/display-plugins/OpenGLDisplayPlugin.h | 1 + .../display-plugins/hmd/HmdDisplayPlugin.cpp | 32 +++---- .../display-plugins/hmd/HmdDisplayPlugin.h | 4 +- .../oculus/src/OculusBaseDisplayPlugin.cpp | 24 ++++-- plugins/openvr/src/OpenVrDisplayPlugin.cpp | 26 ++++-- plugins/openvr/src/OpenVrHelpers.cpp | 86 ++++++++++++++++++- plugins/openvr/src/OpenVrHelpers.h | 4 + plugins/openvr/src/ViveControllerManager.cpp | 83 +----------------- 9 files changed, 138 insertions(+), 123 deletions(-) diff --git a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp index 363bde15e6..23c836b3de 100644 --- a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp @@ -517,6 +517,7 @@ void OpenGLDisplayPlugin::compositeLayers() { glBindTexture(GL_TEXTURE_2D, 0); Context::Disable(Capability::Blend); } + compositeExtra(); }); } diff --git a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h index 02a30a2570..69653b8c76 100644 --- a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h +++ b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h @@ -74,6 +74,7 @@ protected: virtual void compositeScene(); virtual void compositeOverlay(); virtual void compositePointer(); + virtual void compositeExtra() {}; virtual bool hasFocus() const override; diff --git a/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp index 9b71d3703b..9ae843d45d 100644 --- a/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp @@ -316,10 +316,9 @@ void HmdDisplayPlugin::compositePointer() { Uniform(*_program, _mvpUniform).Set(mvp); _plane->Draw(); }); - - compositeLasers(); } + void HmdDisplayPlugin::internalPresent() { PROFILE_RANGE_EX(__FUNCTION__, 0xff00ff00, (uint64_t)presentCount()) @@ -412,24 +411,7 @@ bool HmdDisplayPlugin::setHandLaser(uint32_t hands, HandLaserMode mode, const ve return true; } -// FIXME try to consolidate the duplication of logic between this function and a similar one in CompsitorHelper. -static float calculateRayUiCollisionDistance(const glm::mat4& headPose, const glm::vec3& position, const glm::vec3& direction) { - auto relativePosition4 = glm::inverse(headPose) * vec4(position, 1); - auto relativePosition = vec3(relativePosition4) / relativePosition4.w; - auto relativeDirection = glm::inverse(glm::quat_cast(headPose)) * direction; - if (glm::abs(glm::length2(relativeDirection) - 1.0f) > EPSILON) { - relativeDirection = glm::normalize(relativeDirection); - } - // FIXME fetch the actual UI radius from... somewhere? - float uiRadius = 1.0f; - float instersectionDistance; - if (!glm::intersectRaySphere(relativePosition, relativeDirection, vec3(0), uiRadius * uiRadius, instersectionDistance)) { - return -1; - } - return instersectionDistance; -} - -void HmdDisplayPlugin::compositeLasers() { +void HmdDisplayPlugin::compositeExtra() { std::array handLasers; std::array renderHandPoses; withPresentThreadLock([&] { @@ -465,10 +447,16 @@ void HmdDisplayPlugin::compositeLasers() { const auto& laserDirection = handLaser.direction; auto model = renderHandPoses[i]; auto castDirection = glm::quat_cast(model) * laserDirection; + if (glm::abs(glm::length2(castDirection) - 1.0f) > EPSILON) { + castDirection = glm::normalize(castDirection); + } + + // FIXME fetch the actual UI radius from... somewhere? + float uiRadius = 1.0f; // Find the intersection of the laser with he UI and use it to scale the model matrix - float distance = calculateRayUiCollisionDistance(_currentPresentFrameInfo.presentPose, vec3(renderHandPoses[i][3]), castDirection); - if (distance < 0) { + float distance; + if (!glm::intersectRaySphere(vec3(renderHandPoses[i][3]), castDirection, vec3(0), uiRadius * uiRadius, distance)) { continue; } diff --git a/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.h b/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.h index 7cdcf06e9a..738028d684 100644 --- a/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.h +++ b/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.h @@ -46,9 +46,7 @@ protected: void customizeContext() override; void uncustomizeContext() override; void updateFrameData() override; - - void compositeLasers(); - + void compositeExtra() override; struct HandLaserInfo { HandLaserMode mode { HandLaserMode::None }; diff --git a/plugins/oculus/src/OculusBaseDisplayPlugin.cpp b/plugins/oculus/src/OculusBaseDisplayPlugin.cpp index a16f630bf8..61c4696f51 100644 --- a/plugins/oculus/src/OculusBaseDisplayPlugin.cpp +++ b/plugins/oculus/src/OculusBaseDisplayPlugin.cpp @@ -8,6 +8,7 @@ #include "OculusBaseDisplayPlugin.h" #include +#include #include "OculusHelpers.h" @@ -25,16 +26,21 @@ bool OculusBaseDisplayPlugin::beginFrameRender(uint32_t frameIndex) { _currentRenderFrameInfo.renderPose = toGlm(trackingState.HeadPose.ThePose); _currentRenderFrameInfo.presentPose = _currentRenderFrameInfo.renderPose; + std::array handPoses; + // Make controller poses available to the presentation thread + ovr_for_each_hand([&](ovrHandType hand) { + static const auto REQUIRED_HAND_STATUS = ovrStatus_OrientationTracked & ovrStatus_PositionTracked; + if (REQUIRED_HAND_STATUS != (trackingState.HandStatusFlags[hand] & REQUIRED_HAND_STATUS)) { + return; + } + + auto correctedPose = ovrControllerPoseToHandPose(hand, trackingState.HandPoses[hand]); + static const glm::quat HAND_TO_LASER_ROTATION = glm::rotation(Vectors::UNIT_Z, Vectors::UNIT_NEG_Y); + handPoses[hand] = glm::translate(glm::mat4(), correctedPose.translation) * glm::mat4_cast(correctedPose.rotation * HAND_TO_LASER_ROTATION); + }); + withRenderThreadLock([&] { - // Make controller poses available to the presentation thread - ovr_for_each_hand([&](ovrHandType hand){ - static const auto REQUIRED_HAND_STATUS = ovrStatus_OrientationTracked & ovrStatus_PositionTracked; - if (REQUIRED_HAND_STATUS == (trackingState.HandStatusFlags[hand] & REQUIRED_HAND_STATUS)) { - _handPoses[hand] = toGlm(trackingState.HandPoses[hand].ThePose); - } else { - _handPoses[hand] = glm::mat4(); - } - }); + _handPoses = handPoses; _frameInfos[frameIndex] = _currentRenderFrameInfo; }); return true; diff --git a/plugins/openvr/src/OpenVrDisplayPlugin.cpp b/plugins/openvr/src/OpenVrDisplayPlugin.cpp index 92c01dc0a3..d57dddf512 100644 --- a/plugins/openvr/src/OpenVrDisplayPlugin.cpp +++ b/plugins/openvr/src/OpenVrDisplayPlugin.cpp @@ -18,6 +18,7 @@ #include #include +#include #include #include #include @@ -179,15 +180,26 @@ bool OpenVrDisplayPlugin::beginFrameRender(uint32_t frameIndex) { _currentRenderFrameInfo.renderPose = _trackedDevicePoseMat4[vr::k_unTrackedDeviceIndex_Hmd]; bool keyboardVisible = isOpenVrKeyboardShown(); + + std::array handPoses; + if (!keyboardVisible) { + for (int i = 0; i < 2; ++i) { + if (handIndices[i] == vr::k_unTrackedDeviceIndexInvalid) { + continue; + } + auto deviceIndex = handIndices[i]; + const mat4& mat = _trackedDevicePoseMat4[deviceIndex]; + const vec3& linearVelocity = _trackedDeviceLinearVelocities[deviceIndex]; + const vec3& angularVelocity = _trackedDeviceAngularVelocities[deviceIndex]; + auto correctedPose = openVrControllerPoseToHandPose(i == 0, mat, linearVelocity, angularVelocity); + static const glm::quat HAND_TO_LASER_ROTATION = glm::rotation(Vectors::UNIT_Z, Vectors::UNIT_NEG_Y); + handPoses[i] = glm::translate(glm::mat4(), correctedPose.translation) * glm::mat4_cast(correctedPose.rotation * HAND_TO_LASER_ROTATION); + } + } + withRenderThreadLock([&] { // Make controller poses available to the presentation thread - for (int i = 0; i < 2; ++i) { - if (keyboardVisible || handIndices[i] == vr::k_unTrackedDeviceIndexInvalid) { - _handPoses[i] = glm::mat4(); - } else { - _handPoses[i] = _sensorResetMat * toGlm(_trackedDevicePose[handIndices[i]].mDeviceToAbsoluteTracking); - } - } + _handPoses = handPoses; _frameInfos[frameIndex] = _currentRenderFrameInfo; }); return true; diff --git a/plugins/openvr/src/OpenVrHelpers.cpp b/plugins/openvr/src/OpenVrHelpers.cpp index e4cca6ecd6..4b4eef0538 100644 --- a/plugins/openvr/src/OpenVrHelpers.cpp +++ b/plugins/openvr/src/OpenVrHelpers.cpp @@ -18,8 +18,9 @@ #include #include - #include +#include +#include Q_DECLARE_LOGGING_CATEGORY(displayplugins) Q_LOGGING_CATEGORY(displayplugins, "hifi.plugins.display") @@ -242,3 +243,86 @@ void handleOpenVrEvents() { } +controller::Pose openVrControllerPoseToHandPose(bool isLeftHand, const mat4& mat, const vec3& linearVelocity, const vec3& angularVelocity) { + // When the sensor-to-world rotation is identity the coordinate axes look like this: + // + // user + // forward + // -z + // | + // y| user + // y o----x right + // o-----x user + // | up + // | + // z + // + // Rift + + // From ABOVE the hand canonical axes looks like this: + // + // | | | | y | | | | + // | | | | | | | | | + // | | | | | + // |left | / x---- + \ |right| + // | _/ z \_ | + // | | | | + // | | | | + // + + // So when the user is in Rift space facing the -zAxis with hands outstretched and palms down + // the rotation to align the Touch axes with those of the hands is: + // + // touchToHand = halfTurnAboutY * quaterTurnAboutX + + // Due to how the Touch controllers fit into the palm there is an offset that is different for each hand. + // You can think of this offset as the inverse of the measured rotation when the hands are posed, such that + // the combination (measurement * offset) is identity at this orientation. + // + // Qoffset = glm::inverse(deltaRotation when hand is posed fingers forward, palm down) + // + // An approximate offset for the Touch can be obtained by inspection: + // + // Qoffset = glm::inverse(glm::angleAxis(sign * PI/2.0f, zAxis) * glm::angleAxis(PI/4.0f, xAxis)) + // + // So the full equation is: + // + // Q = combinedMeasurement * touchToHand + // + // Q = (deltaQ * QOffset) * (yFlip * quarterTurnAboutX) + // + // Q = (deltaQ * inverse(deltaQForAlignedHand)) * (yFlip * quarterTurnAboutX) + static const glm::quat yFlip = glm::angleAxis(PI, Vectors::UNIT_Y); + static const glm::quat quarterX = glm::angleAxis(PI_OVER_TWO, Vectors::UNIT_X); + static const glm::quat touchToHand = yFlip * quarterX; + + static const glm::quat leftQuarterZ = glm::angleAxis(-PI_OVER_TWO, Vectors::UNIT_Z); + static const glm::quat rightQuarterZ = glm::angleAxis(PI_OVER_TWO, Vectors::UNIT_Z); + static const glm::quat eighthX = glm::angleAxis(PI / 4.0f, Vectors::UNIT_X); + + static const glm::quat leftRotationOffset = glm::inverse(leftQuarterZ * eighthX) * touchToHand; + static const glm::quat rightRotationOffset = glm::inverse(rightQuarterZ * eighthX) * touchToHand; + + static const float CONTROLLER_LENGTH_OFFSET = 0.0762f; // three inches + static const glm::vec3 CONTROLLER_OFFSET = glm::vec3(CONTROLLER_LENGTH_OFFSET / 2.0f, + CONTROLLER_LENGTH_OFFSET / 2.0f, + CONTROLLER_LENGTH_OFFSET * 2.0f); + static const glm::vec3 leftTranslationOffset = glm::vec3(-1.0f, 1.0f, 1.0f) * CONTROLLER_OFFSET; + static const glm::vec3 rightTranslationOffset = CONTROLLER_OFFSET; + + auto translationOffset = (isLeftHand ? leftTranslationOffset : rightTranslationOffset); + auto rotationOffset = (isLeftHand ? leftRotationOffset : rightRotationOffset); + + glm::vec3 position = extractTranslation(mat); + glm::quat rotation = glm::normalize(glm::quat_cast(mat)); + + position += rotation * translationOffset; + rotation = rotation * rotationOffset; + + // transform into avatar frame + auto result = controller::Pose(position, rotation); + // handle change in velocity due to translationOffset + result.velocity = linearVelocity + glm::cross(angularVelocity, position - extractTranslation(mat)); + result.angularVelocity = angularVelocity; + return result; +} \ No newline at end of file diff --git a/plugins/openvr/src/OpenVrHelpers.h b/plugins/openvr/src/OpenVrHelpers.h index db8bb4f2e8..131db517ab 100644 --- a/plugins/openvr/src/OpenVrHelpers.h +++ b/plugins/openvr/src/OpenVrHelpers.h @@ -12,6 +12,8 @@ #include #include +#include + bool openVrSupported(); vr::IVRSystem* acquireOpenVrSystem(); @@ -55,3 +57,5 @@ inline vr::HmdMatrix34_t toOpenVr(const mat4& m) { } return result; } + +controller::Pose openVrControllerPoseToHandPose(bool isLeftHand, const mat4& mat, const vec3& linearVelocity, const vec3& angularVelocity); diff --git a/plugins/openvr/src/ViveControllerManager.cpp b/plugins/openvr/src/ViveControllerManager.cpp index 4e17a2edf4..83b72c5c08 100644 --- a/plugins/openvr/src/ViveControllerManager.cpp +++ b/plugins/openvr/src/ViveControllerManager.cpp @@ -37,10 +37,6 @@ vr::IVRSystem* acquireOpenVrSystem(); void releaseOpenVrSystem(); -static const float CONTROLLER_LENGTH_OFFSET = 0.0762f; // three inches -static const glm::vec3 CONTROLLER_OFFSET = glm::vec3(CONTROLLER_LENGTH_OFFSET / 2.0f, - CONTROLLER_LENGTH_OFFSET / 2.0f, - CONTROLLER_LENGTH_OFFSET * 2.0f); static const char* CONTROLLER_MODEL_STRING = "vr_controller_05_wireless_b"; static const QString MENU_PARENT = "Avatar"; @@ -382,86 +378,11 @@ void ViveControllerManager::InputDevice::handleButtonEvent(float deltaTime, uint void ViveControllerManager::InputDevice::handlePoseEvent(float deltaTime, const controller::InputCalibrationData& inputCalibrationData, const mat4& mat, const vec3& linearVelocity, const vec3& angularVelocity, bool isLeftHand) { - // When the sensor-to-world rotation is identity the coordinate axes look like this: - // - // user - // forward - // -z - // | - // y| user - // y o----x right - // o-----x user - // | up - // | - // z - // - // Vive - // - - // From ABOVE the hand canonical axes looks like this: - // - // | | | | y | | | | - // | | | | | | | | | - // | | | | | - // |left | / x---- + \ |right| - // | _/ z \_ | - // | | | | - // | | | | - // - - // So when the user is standing in Vive space facing the -zAxis with hands outstretched and palms down - // the rotation to align the Vive axes with those of the hands is: - // - // QviveToHand = halfTurnAboutY * quaterTurnAboutX - - // Due to how the Vive controllers fit into the palm there is an offset that is different for each hand. - // You can think of this offset as the inverse of the measured rotation when the hands are posed, such that - // the combination (measurement * offset) is identity at this orientation. - // - // Qoffset = glm::inverse(deltaRotation when hand is posed fingers forward, palm down) - // - // An approximate offset for the Vive can be obtained by inspection: - // - // Qoffset = glm::inverse(glm::angleAxis(sign * PI/4.0f, zAxis) * glm::angleAxis(PI/2.0f, xAxis)) - // - // So the full equation is: - // - // Q = combinedMeasurement * viveToHand - // - // Q = (deltaQ * QOffset) * (yFlip * quarterTurnAboutX) - // - // Q = (deltaQ * inverse(deltaQForAlignedHand)) * (yFlip * quarterTurnAboutX) - - static const glm::quat yFlip = glm::angleAxis(PI, Vectors::UNIT_Y); - static const glm::quat quarterX = glm::angleAxis(PI_OVER_TWO, Vectors::UNIT_X); - static const glm::quat viveToHand = yFlip * quarterX; - - static const glm::quat leftQuaterZ = glm::angleAxis(-PI_OVER_TWO, Vectors::UNIT_Z); - static const glm::quat rightQuaterZ = glm::angleAxis(PI_OVER_TWO, Vectors::UNIT_Z); - static const glm::quat eighthX = glm::angleAxis(PI / 4.0f, Vectors::UNIT_X); - - static const glm::quat leftRotationOffset = glm::inverse(leftQuaterZ * eighthX) * viveToHand; - static const glm::quat rightRotationOffset = glm::inverse(rightQuaterZ * eighthX) * viveToHand; - - static const glm::vec3 leftTranslationOffset = glm::vec3(-1.0f, 1.0f, 1.0f) * CONTROLLER_OFFSET; - static const glm::vec3 rightTranslationOffset = CONTROLLER_OFFSET; - - auto translationOffset = (isLeftHand ? leftTranslationOffset : rightTranslationOffset); - auto rotationOffset = (isLeftHand ? leftRotationOffset : rightRotationOffset); - - glm::vec3 position = extractTranslation(mat); - glm::quat rotation = glm::normalize(glm::quat_cast(mat)); - - position += rotation * translationOffset; - rotation = rotation * rotationOffset; + auto pose = openVrControllerPoseToHandPose(isLeftHand, mat, linearVelocity, angularVelocity); // transform into avatar frame glm::mat4 controllerToAvatar = glm::inverse(inputCalibrationData.avatarMat) * inputCalibrationData.sensorToWorldMat; - auto avatarPose = controller::Pose(position, rotation); - // handle change in velocity due to translationOffset - avatarPose.velocity = linearVelocity + glm::cross(angularVelocity, position - extractTranslation(mat)); - avatarPose.angularVelocity = angularVelocity; - _poseStateMap[isLeftHand ? controller::LEFT_HAND : controller::RIGHT_HAND] = avatarPose.transform(controllerToAvatar); + _poseStateMap[isLeftHand ? controller::LEFT_HAND : controller::RIGHT_HAND] = pose.transform(controllerToAvatar); } bool ViveControllerManager::InputDevice::triggerHapticPulse(float strength, float duration, controller::Hand hand) { From f3c47acbb240871a9889606fe1b0f6127dd3f160 Mon Sep 17 00:00:00 2001 From: Bradley Austin Davis Date: Mon, 13 Jun 2016 18:20:55 -0700 Subject: [PATCH 34/35] Fix offset when UI transform is not identity --- .../src/display-plugins/hmd/HmdDisplayPlugin.cpp | 4 +++- .../src/display-plugins/hmd/HmdDisplayPlugin.h | 2 ++ plugins/oculus/src/OculusBaseDisplayPlugin.cpp | 2 ++ plugins/openvr/src/OpenVrDisplayPlugin.cpp | 2 ++ 4 files changed, 9 insertions(+), 1 deletion(-) diff --git a/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp index 698e19fcab..6801d94f2f 100644 --- a/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp @@ -415,9 +415,11 @@ bool HmdDisplayPlugin::setHandLaser(uint32_t hands, HandLaserMode mode, const ve void HmdDisplayPlugin::compositeExtra() { std::array handLasers; std::array renderHandPoses; + Transform uiModelTransform; withPresentThreadLock([&] { handLasers = _handLasers; renderHandPoses = _handPoses; + uiModelTransform = _uiModelTransform; }); // If neither hand laser is activated, exit @@ -457,7 +459,7 @@ void HmdDisplayPlugin::compositeExtra() { // Find the intersection of the laser with he UI and use it to scale the model matrix float distance; - if (!glm::intersectRaySphere(vec3(renderHandPoses[i][3]), castDirection, vec3(0), uiRadius * uiRadius, distance)) { + if (!glm::intersectRaySphere(vec3(renderHandPoses[i][3]), castDirection, uiModelTransform.getTranslation(), uiRadius * uiRadius, distance)) { continue; } diff --git a/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.h b/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.h index 738028d684..fada15d864 100644 --- a/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.h +++ b/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.h @@ -10,6 +10,7 @@ #include #include +#include #include "../OpenGLDisplayPlugin.h" @@ -59,6 +60,7 @@ protected: } }; + Transform _uiModelTransform; std::array _handLasers; std::array _handPoses; std::array _eyeOffsets; diff --git a/plugins/oculus/src/OculusBaseDisplayPlugin.cpp b/plugins/oculus/src/OculusBaseDisplayPlugin.cpp index 61c4696f51..e188bea52e 100644 --- a/plugins/oculus/src/OculusBaseDisplayPlugin.cpp +++ b/plugins/oculus/src/OculusBaseDisplayPlugin.cpp @@ -9,6 +9,7 @@ #include #include +#include #include "OculusHelpers.h" @@ -40,6 +41,7 @@ bool OculusBaseDisplayPlugin::beginFrameRender(uint32_t frameIndex) { }); withRenderThreadLock([&] { + _uiModelTransform = DependencyManager::get()->getModelTransform(); _handPoses = handPoses; _frameInfos[frameIndex] = _currentRenderFrameInfo; }); diff --git a/plugins/openvr/src/OpenVrDisplayPlugin.cpp b/plugins/openvr/src/OpenVrDisplayPlugin.cpp index d57dddf512..3a5f027013 100644 --- a/plugins/openvr/src/OpenVrDisplayPlugin.cpp +++ b/plugins/openvr/src/OpenVrDisplayPlugin.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #include "OpenVrHelpers.h" @@ -198,6 +199,7 @@ bool OpenVrDisplayPlugin::beginFrameRender(uint32_t frameIndex) { } withRenderThreadLock([&] { + _uiModelTransform = DependencyManager::get()->getModelTransform(); // Make controller poses available to the presentation thread _handPoses = handPoses; _frameInfos[frameIndex] = _currentRenderFrameInfo; From 5759c2d29d1c058b8190ee0fff6b5662939fbc73 Mon Sep 17 00:00:00 2001 From: howard-stearns Date: Tue, 14 Jun 2016 11:28:44 -0700 Subject: [PATCH 35/35] final --- scripts/system/controllers/handControllerPointer.js | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/scripts/system/controllers/handControllerPointer.js b/scripts/system/controllers/handControllerPointer.js index f5c0c4bb7c..7046ed16a5 100644 --- a/scripts/system/controllers/handControllerPointer.js +++ b/scripts/system/controllers/handControllerPointer.js @@ -364,13 +364,12 @@ Script.scriptEnding.connect(function () { overlays.forEach(Overlays.deleteOverlay); }); var visualizationIsShowing = false; // Not whether it desired, but simply whether it is. Just an optimziation. -var SYSTEM_LASER_DIRECTION = Vec3.normalize({x: 0, y: -1, z: -1}); // Guessing 45 degrees. +var SYSTEM_LASER_DIRECTION = {x: 0, y: 0, z: -1}; var systemLaserOn = false; function clearSystemLaser() { if (!systemLaserOn) { return; } - print('FIXME remove: disableHandLasers', BOTH_HUD_LASERS); HMD.disableHandLasers(BOTH_HUD_LASERS); systemLaserOn = false; } @@ -379,13 +378,9 @@ function turnOffVisualization(optionalEnableClicks) { // because we're showing c expireMouseCursor(); clearSystemLaser(); } else if (!systemLaserOn) { - print('FIXME remove: setHandLasers', activeHudLaser, true, JSON.stringify(LASER_COLOR_XYZW), JSON.stringify(SYSTEM_LASER_DIRECTION)); // If the active plugin doesn't implement hand lasers, show the mouse reticle instead. - /*Reticle.visible = !*/HMD.setHandLasers(activeHudLaser, true, LASER_COLOR_XYZW, SYSTEM_LASER_DIRECTION); - Reticle.visible = true; // FIXME: just for now, while hand lasers has the bug that requires this. - systemLaserOn = true; - } else { - Reticle.visible = true; + systemLaserOn = HMD.setHandLasers(activeHudLaser, true, LASER_COLOR_XYZW, SYSTEM_LASER_DIRECTION); + Reticle.visible = !systemLaserOn; } if (!visualizationIsShowing) { return;