From 30248747d6475bed432318f8fee77a7741cd8d46 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Fri, 18 Apr 2014 14:26:34 -0700 Subject: [PATCH 01/35] Provide a means of visualizing the joint constraints. --- interface/src/Menu.cpp | 1 + interface/src/Menu.h | 1 + interface/src/avatar/MyAvatar.cpp | 3 ++ interface/src/avatar/SkeletonModel.cpp | 61 ++++++++++++++++++++++++++ interface/src/avatar/SkeletonModel.h | 4 ++ 5 files changed, 70 insertions(+) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index b05e5c91bc..bb20a469b4 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -330,6 +330,7 @@ Menu::Menu() : addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::DisplayHandTargets, 0, false); addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::PlaySlaps, 0, false); addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::HandsCollideWithSelf, 0, false); + addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::ShowIKConstraints, 0, false); addDisabledActionAndSeparator(developerMenu, "Testing"); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index c17c9cc507..710cc5d78b 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -348,6 +348,7 @@ namespace MenuOption { const QString SettingsImport = "Import Settings"; const QString Shadows = "Shadows"; const QString ShowCulledSharedFaces = "Show Culled Shared Voxel Faces"; + const QString ShowIKConstraints = "Show IK Constraints"; const QString Stars = "Stars"; const QString Stats = "Stats"; const QString StopAllScripts = "Stop All Scripts"; diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 8229611646..a8d6dfa242 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -460,6 +460,9 @@ void MyAvatar::render(const glm::vec3& cameraPosition, RenderMode renderMode) { return; // exit early } Avatar::render(cameraPosition, renderMode); + if (Menu::getInstance()->isOptionChecked(MenuOption::ShowIKConstraints)) { + _skeletonModel.renderIKConstraints(); + } } void MyAvatar::renderHeadMouse() const { diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index b9ac280711..8d593a9c02 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -103,6 +103,11 @@ void SkeletonModel::getBodyShapes(QVector& shapes) const { shapes.push_back(&_boundingShape); } +void SkeletonModel::renderIKConstraints() { + renderJointConstraints(getRightHandJointIndex()); + renderJointConstraints(getLeftHandJointIndex()); +} + class IndexValue { public: int index; @@ -210,3 +215,59 @@ void SkeletonModel::maybeUpdateLeanRotation(const JointState& parentState, const glm::normalize(inverse * axes[0])) * joint.rotation; } +void SkeletonModel::renderJointConstraints(int jointIndex) { + if (jointIndex == -1) { + return; + } + const FBXGeometry& geometry = _geometry->getFBXGeometry(); + const float BASE_DIRECTION_SIZE = 300.0f; + float directionSize = BASE_DIRECTION_SIZE * extractUniformScale(_scale); + glLineWidth(3.0f); + do { + const FBXJoint& joint = geometry.joints.at(jointIndex); + const JointState& jointState = _jointStates.at(jointIndex); + glm::vec3 position = extractTranslation(jointState.transform) + _translation; + + glPushMatrix(); + glTranslatef(position.x, position.y, position.z); + glm::quat parentRotation = (joint.parentIndex == -1) ? _rotation : _jointStates.at(joint.parentIndex).combinedRotation; + glm::vec3 rotationAxis = glm::axis(parentRotation); + glRotatef(glm::degrees(glm::angle(parentRotation)), rotationAxis.x, rotationAxis.y, rotationAxis.z); + float fanScale = directionSize * 0.75f; + glScalef(fanScale, fanScale, fanScale); + const int AXIS_COUNT = 3; + for (int i = 0; i < AXIS_COUNT; i++) { + if (joint.rotationMin[i] <= -PI + EPSILON && joint.rotationMax[i] >= PI - EPSILON) { + continue; // unconstrained + } + glm::vec3 axis; + axis[i] = 1.0f; + + glm::vec3 otherAxis; + if (i == 0) { + otherAxis.y = 1.0f; + } else { + otherAxis.x = 1.0f; + } + glColor4f(otherAxis.r, otherAxis.g, otherAxis.b, 0.75f); + + glBegin(GL_TRIANGLE_FAN); + glVertex3f(0.0f, 0.0f, 0.0f); + const int FAN_SEGMENTS = 16; + for (int j = 0; j < FAN_SEGMENTS; j++) { + glm::vec3 rotated = glm::angleAxis(glm::mix(joint.rotationMin[i], joint.rotationMax[i], + (float)j / (FAN_SEGMENTS - 1)), axis) * otherAxis; + glVertex3f(rotated.x, rotated.y, rotated.z); + } + glEnd(); + } + glPopMatrix(); + + renderOrientationDirections(position, jointState.combinedRotation, directionSize); + jointIndex = joint.parentIndex; + + } while (jointIndex != -1 && geometry.joints.at(jointIndex).isFree); + + glLineWidth(1.0f); +} + diff --git a/interface/src/avatar/SkeletonModel.h b/interface/src/avatar/SkeletonModel.h index 2020ccf3b2..0a87fcf89d 100644 --- a/interface/src/avatar/SkeletonModel.h +++ b/interface/src/avatar/SkeletonModel.h @@ -33,6 +33,8 @@ public: /// \param shapes[out] list of shapes for body collisions void getBodyShapes(QVector& shapes) const; + void renderIKConstraints(); + protected: void applyHandPosition(int jointIndex, const glm::vec3& position); @@ -46,6 +48,8 @@ protected: virtual void maybeUpdateLeanRotation(const JointState& parentState, const FBXJoint& joint, JointState& state); private: + + void renderJointConstraints(int jointIndex); Avatar* _owningAvatar; }; From 6add0dfb4271360d1d3dff82fbf4f61a67041934 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Fri, 18 Apr 2014 15:04:42 -0700 Subject: [PATCH 02/35] Tweaked Hydra "IK" to propagate delta rotations up the hierarchy while preserving joint constraints. --- interface/src/avatar/SkeletonModel.cpp | 7 ++++--- interface/src/renderer/Model.cpp | 13 ++++++++++--- interface/src/renderer/Model.h | 2 +- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index 8d593a9c02..1c6a568754 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -138,7 +138,7 @@ void SkeletonModel::applyHandPosition(int jointIndex, const glm::vec3& position) // align hand with forearm float sign = (jointIndex == geometry.rightHandJointIndex) ? 1.0f : -1.0f; - applyRotationDelta(jointIndex, rotationBetween(handRotation * glm::vec3(-sign, 0.0f, 0.0f), forearmVector), false); + applyRotationDelta(jointIndex, rotationBetween(handRotation * glm::vec3(-sign, 0.0f, 0.0f), forearmVector)); } void SkeletonModel::applyPalmData(int jointIndex, const QVector& fingerJointIndices, @@ -156,7 +156,7 @@ void SkeletonModel::applyPalmData(int jointIndex, const QVector& fingerJoin // rotate forearm to align with palm direction glm::quat palmRotation; getJointRotation(parentJointIndex, palmRotation, true); - applyRotationDelta(parentJointIndex, rotationBetween(palmRotation * geometry.palmDirection, palm.getNormal()), false); + applyRotationDelta(parentJointIndex, rotationBetween(palmRotation * geometry.palmDirection, palm.getNormal()), true, true); getJointRotation(parentJointIndex, palmRotation, true); // sort the finger indices by raw x, get the average direction @@ -178,7 +178,8 @@ void SkeletonModel::applyPalmData(int jointIndex, const QVector& fingerJoin float directionLength = glm::length(direction); const unsigned int MIN_ROTATION_FINGERS = 3; if (directionLength > EPSILON && palm.getNumFingers() >= MIN_ROTATION_FINGERS) { - applyRotationDelta(parentJointIndex, rotationBetween(palmRotation * glm::vec3(-sign, 0.0f, 0.0f), direction), false); + applyRotationDelta(parentJointIndex, rotationBetween(palmRotation * glm::vec3(-sign, 0.0f, 0.0f), direction), + true, true); getJointRotation(parentJointIndex, palmRotation, true); } diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index f8de7210ea..36088dec70 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -997,9 +997,10 @@ float Model::getLimbLength(int jointIndex) const { return length; } -void Model::applyRotationDelta(int jointIndex, const glm::quat& delta, bool constrain) { +void Model::applyRotationDelta(int jointIndex, const glm::quat& delta, bool constrain, bool propagate) { JointState& state = _jointStates[jointIndex]; - const FBXJoint& joint = _geometry->getFBXGeometry().joints[jointIndex]; + const FBXGeometry& geometry = _geometry->getFBXGeometry(); + const FBXJoint& joint = geometry.joints[jointIndex]; if (!constrain || (joint.rotationMin == glm::vec3(-PI, -PI, -PI) && joint.rotationMax == glm::vec3(PI, PI, PI))) { // no constraints @@ -1007,10 +1008,16 @@ void Model::applyRotationDelta(int jointIndex, const glm::quat& delta, bool cons state.combinedRotation = delta * state.combinedRotation; return; } + glm::quat targetRotation = delta * state.combinedRotation; glm::quat newRotation = glm::quat(glm::clamp(safeEulerAngles(state.rotation * - glm::inverse(state.combinedRotation) * delta * state.combinedRotation), joint.rotationMin, joint.rotationMax)); + glm::inverse(state.combinedRotation) * targetRotation), joint.rotationMin, joint.rotationMax)); state.combinedRotation = state.combinedRotation * glm::inverse(state.rotation) * newRotation; state.rotation = newRotation; + + if (propagate && targetRotation != state.combinedRotation && + joint.parentIndex != -1 && geometry.joints[joint.parentIndex].isFree) { + applyRotationDelta(joint.parentIndex, targetRotation * glm::inverse(state.combinedRotation), true, true); + } } const int BALL_SUBDIVISIONS = 10; diff --git a/interface/src/renderer/Model.h b/interface/src/renderer/Model.h index 65b79fffdd..b472e17b20 100644 --- a/interface/src/renderer/Model.h +++ b/interface/src/renderer/Model.h @@ -256,7 +256,7 @@ protected: /// first free ancestor. float getLimbLength(int jointIndex) const; - void applyRotationDelta(int jointIndex, const glm::quat& delta, bool constrain = true); + void applyRotationDelta(int jointIndex, const glm::quat& delta, bool constrain = true, bool propagate = false); private: From 743034c986fffd65bd564176239b3de019836367 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Fri, 18 Apr 2014 15:09:37 -0700 Subject: [PATCH 03/35] Need to transfer parent rotation to child. --- interface/src/renderer/Model.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 36088dec70..17d3dd783c 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -1017,6 +1017,7 @@ void Model::applyRotationDelta(int jointIndex, const glm::quat& delta, bool cons if (propagate && targetRotation != state.combinedRotation && joint.parentIndex != -1 && geometry.joints[joint.parentIndex].isFree) { applyRotationDelta(joint.parentIndex, targetRotation * glm::inverse(state.combinedRotation), true, true); + state.combinedRotation = _jointStates.at(joint.parentIndex).combinedRotation * state.rotation; } } From e2558bdac088908ed755fcdb3d3175932567d9a6 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Fri, 18 Apr 2014 17:16:20 -0700 Subject: [PATCH 04/35] Experimenting with tweaking the Euler angles so that z, rather than y, is in [-pi/2, pi/2]. --- interface/src/renderer/Model.cpp | 11 ++++++--- libraries/shared/src/SharedUtil.cpp | 38 ++++++++++++++++++++++++++--- 2 files changed, 43 insertions(+), 6 deletions(-) diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 17d3dd783c..2ff8a0fee9 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -892,6 +892,11 @@ bool Model::setJointPosition(int jointIndex, const glm::vec3& position, int last lastFreeIndex = freeLineage.last(); } + // now update the joint states from the top + for (int j = freeLineage.size() - 1; j >= 0; j--) { + updateJointState(freeLineage.at(j)); + } + // this is a cyclic coordinate descent algorithm: see // http://www.ryanjuckett.com/programming/animation/21-cyclic-coordinate-descent-in-2d const int ITERATION_COUNT = 1; @@ -1009,13 +1014,13 @@ void Model::applyRotationDelta(int jointIndex, const glm::quat& delta, bool cons return; } glm::quat targetRotation = delta * state.combinedRotation; - glm::quat newRotation = glm::quat(glm::clamp(safeEulerAngles(state.rotation * - glm::inverse(state.combinedRotation) * targetRotation), joint.rotationMin, joint.rotationMax)); + glm::vec3 eulers = safeEulerAngles(state.rotation * glm::inverse(state.combinedRotation) * targetRotation); + glm::quat newRotation = glm::quat(glm::clamp(eulers, joint.rotationMin, joint.rotationMax)); state.combinedRotation = state.combinedRotation * glm::inverse(state.rotation) * newRotation; state.rotation = newRotation; if (propagate && targetRotation != state.combinedRotation && - joint.parentIndex != -1 && geometry.joints[joint.parentIndex].isFree) { + joint.parentIndex != -1 && geometry.joints.at(joint.parentIndex).isFree) { applyRotationDelta(joint.parentIndex, targetRotation * glm::inverse(state.combinedRotation), true, true); state.combinedRotation = _jointStates.at(joint.parentIndex).combinedRotation * state.rotation; } diff --git a/libraries/shared/src/SharedUtil.cpp b/libraries/shared/src/SharedUtil.cpp index f4e4b28f93..69381a07ae 100644 --- a/libraries/shared/src/SharedUtil.cpp +++ b/libraries/shared/src/SharedUtil.cpp @@ -640,27 +640,59 @@ void debug::checkDeadBeef(void* memoryVoid, int size) { // https://github.com/threerings/clyde/blob/master/src/main/java/com/threerings/math/Quaternion.java) glm::vec3 safeEulerAngles(const glm::quat& q) { float sy = 2.0f * (q.y * q.w - q.x * q.z); + glm::vec3 eulers; if (sy < 1.0f - EPSILON) { if (sy > -1.0f + EPSILON) { - return glm::vec3( + eulers = glm::vec3( atan2f(q.y * q.z + q.x * q.w, 0.5f - (q.x * q.x + q.y * q.y)), asinf(sy), atan2f(q.x * q.y + q.z * q.w, 0.5f - (q.y * q.y + q.z * q.z))); } else { // not a unique solution; x + z = atan2(-m21, m11) - return glm::vec3( + eulers = glm::vec3( 0.0f, - PI_OVER_TWO, atan2f(q.x * q.w - q.y * q.z, 0.5f - (q.x * q.x + q.z * q.z))); } } else { // not a unique solution; x - z = atan2(-m21, m11) - return glm::vec3( + eulers = glm::vec3( 0.0f, PI_OVER_TWO, -atan2f(q.x * q.w - q.y * q.z, 0.5f - (q.x * q.x + q.z * q.z))); } + + // adjust so that z, rather than y, is in [-pi/2, pi/2] + if (eulers.z < -PI_OVER_TWO) { + if (eulers.x < 0.0f) { + eulers.x += PI; + } else { + eulers.x -= PI; + } + eulers.y = -eulers.y; + if (eulers.y < 0.0f) { + eulers.y += PI; + } else { + eulers.y -= PI; + } + eulers.z += PI; + + } else if (eulers.z > PI_OVER_TWO) { + if (eulers.x < 0.0f) { + eulers.x += PI; + } else { + eulers.x -= PI; + } + eulers.y = -eulers.y; + if (eulers.y < 0.0f) { + eulers.y += PI; + } else { + eulers.y -= PI; + } + eulers.z -= PI; + } + return eulers; } // Helper function returns the positive angle (in radians) between two 3D vectors From 241df7a7675c83ab7fbbabaf6c9903ac398d667d Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 21 Apr 2014 10:27:20 -0700 Subject: [PATCH 05/35] Move AABox from octree lib to shared lib Stubbed out Shape vs Octree collisions --- libraries/octree/src/Octree.cpp | 58 ++++++++++++++++++++-- libraries/octree/src/Octree.h | 5 ++ libraries/octree/src/OctreeElement.cpp | 2 +- libraries/octree/src/OctreeElement.h | 3 +- libraries/octree/src/ViewFrustum.h | 2 +- libraries/{octree => shared}/src/AABox.cpp | 2 +- libraries/{octree => shared}/src/AABox.h | 2 +- libraries/shared/src/ShapeCollider.cpp | 5 ++ libraries/shared/src/ShapeCollider.h | 7 +++ libraries/voxels/src/VoxelTreeElement.h | 2 +- 10 files changed, 79 insertions(+), 9 deletions(-) rename libraries/{octree => shared}/src/AABox.cpp (99%) rename libraries/{octree => shared}/src/AABox.h (98%) diff --git a/libraries/octree/src/Octree.cpp b/libraries/octree/src/Octree.cpp index 696a65b4b5..a06b8a41bb 100644 --- a/libraries/octree/src/Octree.cpp +++ b/libraries/octree/src/Octree.cpp @@ -20,18 +20,20 @@ #include -#include "CoverageMap.h" #include -#include "OctalCode.h" +#include #include #include +#include +#include //#include "Tags.h" -#include "ViewFrustum.h" +#include "CoverageMap.h" #include "OctreeConstants.h" #include "OctreeElementBag.h" #include "Octree.h" +#include "ViewFrustum.h" float boundaryDistanceForRenderLevel(unsigned int renderLevel, float voxelSizeScale) { return voxelSizeScale / powf(2, renderLevel); @@ -676,6 +678,13 @@ public: bool found; }; +class ShapeArgs { +public: + const Shape* shape; + CollisionList& collisions; + bool found; +}; + bool findCapsulePenetrationOp(OctreeElement* node, void* extraData) { CapsuleArgs* args = static_cast(extraData); @@ -697,6 +706,24 @@ bool findCapsulePenetrationOp(OctreeElement* node, void* extraData) { return false; } +bool findShapeCollisionsOp(OctreeElement* node, void* extraData) { + const ShapeArgs* args = static_cast(extraData); + + // coarse check against bounds + AABox box = node->getAABox(); + box.scale(TREE_SCALE); + if (!box.expandedContains(args->shape->getPosition(), args->shape->getBoundingRadius())) { + return false; + } + if (!node->isLeaf()) { + return true; // recurse on children + } + if (node->hasContent()) { + return ShapeCollider::collideShapeWithBox(args->shape, box, args->collisions); + } + return false; +} + bool Octree::findCapsulePenetration(const glm::vec3& start, const glm::vec3& end, float radius, glm::vec3& penetration, Octree::lockType lockType) { @@ -727,6 +754,31 @@ bool Octree::findCapsulePenetration(const glm::vec3& start, const glm::vec3& end return args.found; } +bool Octree::findShapeCollisions(const Shape* shape, CollisionList& collisions, Octree::lockType lockType) { + + ShapeArgs args = { shape, + collisions, + false }; + + bool gotLock = false; + if (lockType == Octree::Lock) { + lockForRead(); + gotLock = true; + } else if (lockType == Octree::TryLock) { + gotLock = tryLockForRead(); + if (!gotLock) { + return args.found; // if we wanted to tryLock, and we couldn't then just bail... + } + } + + recurseTreeWithOperation(findShapeCollisionsOp, &args); + + if (gotLock) { + unlock(); + } + return args.found; +} + class GetElementEnclosingArgs { public: OctreeElement* element; diff --git a/libraries/octree/src/Octree.h b/libraries/octree/src/Octree.h index 839e61d1c2..4c47c0ce9f 100644 --- a/libraries/octree/src/Octree.h +++ b/libraries/octree/src/Octree.h @@ -21,6 +21,7 @@ class Octree; class OctreeElement; class OctreeElementBag; class OctreePacketData; +class Shape; #include "JurisdictionMap.h" @@ -30,6 +31,8 @@ class OctreePacketData; #include "OctreePacketData.h" #include "OctreeSceneStats.h" +#include + #include #include @@ -246,6 +249,8 @@ public: bool findCapsulePenetration(const glm::vec3& start, const glm::vec3& end, float radius, glm::vec3& penetration, Octree::lockType lockType = Octree::TryLock); + bool findShapeCollisions(const Shape* shape, CollisionList& collisions, Octree::lockType = Octree::TryLock); + OctreeElement* getElementEnclosingPoint(const glm::vec3& point, Octree::lockType lockType = Octree::TryLock); // Note: this assumes the fileFormat is the HIO individual voxels code files diff --git a/libraries/octree/src/OctreeElement.cpp b/libraries/octree/src/OctreeElement.cpp index e21148df5e..c951803247 100644 --- a/libraries/octree/src/OctreeElement.cpp +++ b/libraries/octree/src/OctreeElement.cpp @@ -15,11 +15,11 @@ #include +#include #include #include #include -#include "AABox.h" #include "OctalCode.h" #include "SharedUtil.h" #include "OctreeConstants.h" diff --git a/libraries/octree/src/OctreeElement.h b/libraries/octree/src/OctreeElement.h index 682516cf0a..15d5063818 100644 --- a/libraries/octree/src/OctreeElement.h +++ b/libraries/octree/src/OctreeElement.h @@ -18,8 +18,9 @@ #include +#include #include -#include "AABox.h" + #include "ViewFrustum.h" #include "OctreeConstants.h" //#include "Octree.h" diff --git a/libraries/octree/src/ViewFrustum.h b/libraries/octree/src/ViewFrustum.h index 5c9d7f06c2..43812827f5 100644 --- a/libraries/octree/src/ViewFrustum.h +++ b/libraries/octree/src/ViewFrustum.h @@ -17,7 +17,7 @@ #include #include -#include "AABox.h" +#include #include "Plane.h" #include "OctreeConstants.h" diff --git a/libraries/octree/src/AABox.cpp b/libraries/shared/src/AABox.cpp similarity index 99% rename from libraries/octree/src/AABox.cpp rename to libraries/shared/src/AABox.cpp index 51b31d4466..ed99a24d38 100644 --- a/libraries/octree/src/AABox.cpp +++ b/libraries/shared/src/AABox.cpp @@ -1,6 +1,6 @@ // // AABox.cpp -// libraries/octree/src +// libraries/shared/src // // Created by Brad Hefta-Gaub on 04/11/13. // Copyright 2013 High Fidelity, Inc. diff --git a/libraries/octree/src/AABox.h b/libraries/shared/src/AABox.h similarity index 98% rename from libraries/octree/src/AABox.h rename to libraries/shared/src/AABox.h index 1aa0849b70..6531db4250 100644 --- a/libraries/octree/src/AABox.h +++ b/libraries/shared/src/AABox.h @@ -1,6 +1,6 @@ // // AABox.h -// libraries/octree/src +// libraries/shared/src // // Created by Brad Hefta-Gaub on 04/11/13. // Copyright 2013 High Fidelity, Inc. diff --git a/libraries/shared/src/ShapeCollider.cpp b/libraries/shared/src/ShapeCollider.cpp index c53c7fab7d..0eddc80c62 100644 --- a/libraries/shared/src/ShapeCollider.cpp +++ b/libraries/shared/src/ShapeCollider.cpp @@ -92,6 +92,11 @@ bool collideShapesCoarse(const QVector& shapesA, const QVectorgetPosition() - sphereA->getPosition(); float distanceSquared = glm::dot(BA, BA); diff --git a/libraries/shared/src/ShapeCollider.h b/libraries/shared/src/ShapeCollider.h index d554775e7b..a020050662 100644 --- a/libraries/shared/src/ShapeCollider.h +++ b/libraries/shared/src/ShapeCollider.h @@ -12,6 +12,7 @@ #ifndef hifi_ShapeCollider_h #define hifi_ShapeCollider_h +#include "AABox.h" #include "CapsuleShape.h" #include "CollisionInfo.h" #include "ListShape.h" @@ -33,6 +34,12 @@ namespace ShapeCollider { /// \return true if any shapes collide bool collideShapesCoarse(const QVector& shapesA, const QVector& shapesB, CollisionInfo& collision); + /// \param shapeA a pointer to a shape + /// \param boxB an axis aligned box + /// \param collisions[out] average collision details + /// \return true if shapeA collides with boxB + bool collideShapeWithBox(const Shape* shapeA, const AABox& boxB, CollisionList& collisions); + /// \param sphereA pointer to first shape /// \param sphereB pointer to second shape /// \param[out] collisions where to append collision details diff --git a/libraries/voxels/src/VoxelTreeElement.h b/libraries/voxels/src/VoxelTreeElement.h index 140744afb0..8733987df4 100644 --- a/libraries/voxels/src/VoxelTreeElement.h +++ b/libraries/voxels/src/VoxelTreeElement.h @@ -18,10 +18,10 @@ #include +#include #include #include -#include "AABox.h" #include "ViewFrustum.h" #include "VoxelConstants.h" From 06784aa960b46612dceed11a13a2398666012600 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 21 Apr 2014 14:07:40 -0700 Subject: [PATCH 06/35] move AABox back to octree lib Fleshing out ShapeCollider::collideShapeWithAACube() --- libraries/{shared => octree}/src/AABox.cpp | 0 libraries/{shared => octree}/src/AABox.h | 0 libraries/octree/src/Octree.cpp | 8 +-- libraries/octree/src/OctreeElement.cpp | 4 +- libraries/octree/src/OctreeElement.h | 2 +- libraries/octree/src/ViewFrustum.h | 3 +- libraries/shared/src/ShapeCollider.cpp | 80 +++++++++++++++++++++- libraries/shared/src/ShapeCollider.h | 22 ++++-- 8 files changed, 104 insertions(+), 15 deletions(-) rename libraries/{shared => octree}/src/AABox.cpp (100%) rename libraries/{shared => octree}/src/AABox.h (100%) diff --git a/libraries/shared/src/AABox.cpp b/libraries/octree/src/AABox.cpp similarity index 100% rename from libraries/shared/src/AABox.cpp rename to libraries/octree/src/AABox.cpp diff --git a/libraries/shared/src/AABox.h b/libraries/octree/src/AABox.h similarity index 100% rename from libraries/shared/src/AABox.h rename to libraries/octree/src/AABox.h diff --git a/libraries/octree/src/Octree.cpp b/libraries/octree/src/Octree.cpp index a06b8a41bb..83b84b3c50 100644 --- a/libraries/octree/src/Octree.cpp +++ b/libraries/octree/src/Octree.cpp @@ -710,16 +710,16 @@ bool findShapeCollisionsOp(OctreeElement* node, void* extraData) { const ShapeArgs* args = static_cast(extraData); // coarse check against bounds - AABox box = node->getAABox(); - box.scale(TREE_SCALE); - if (!box.expandedContains(args->shape->getPosition(), args->shape->getBoundingRadius())) { + AABox cube = node->getAABox(); + cube.scale(TREE_SCALE); + if (!cube.expandedContains(args->shape->getPosition(), args->shape->getBoundingRadius())) { return false; } if (!node->isLeaf()) { return true; // recurse on children } if (node->hasContent()) { - return ShapeCollider::collideShapeWithBox(args->shape, box, args->collisions); + return ShapeCollider::collideShapeWithAACube(args->shape, cube.calcCenter(), cube.getScale(), args->collisions); } return false; } diff --git a/libraries/octree/src/OctreeElement.cpp b/libraries/octree/src/OctreeElement.cpp index c951803247..7ca15eddb5 100644 --- a/libraries/octree/src/OctreeElement.cpp +++ b/libraries/octree/src/OctreeElement.cpp @@ -15,16 +15,16 @@ #include -#include #include #include #include +#include "AABox.h" #include "OctalCode.h" -#include "SharedUtil.h" #include "OctreeConstants.h" #include "OctreeElement.h" #include "Octree.h" +#include "SharedUtil.h" quint64 OctreeElement::_voxelMemoryUsage = 0; quint64 OctreeElement::_octcodeMemoryUsage = 0; diff --git a/libraries/octree/src/OctreeElement.h b/libraries/octree/src/OctreeElement.h index 15d5063818..c5eec1c9e2 100644 --- a/libraries/octree/src/OctreeElement.h +++ b/libraries/octree/src/OctreeElement.h @@ -18,9 +18,9 @@ #include -#include #include +#include "AABox.h" #include "ViewFrustum.h" #include "OctreeConstants.h" //#include "Octree.h" diff --git a/libraries/octree/src/ViewFrustum.h b/libraries/octree/src/ViewFrustum.h index 43812827f5..acd5c639f7 100644 --- a/libraries/octree/src/ViewFrustum.h +++ b/libraries/octree/src/ViewFrustum.h @@ -17,9 +17,8 @@ #include #include -#include +#include "AABox.h" #include "Plane.h" - #include "OctreeConstants.h" #include "OctreeProjectedPolygon.h" diff --git a/libraries/shared/src/ShapeCollider.cpp b/libraries/shared/src/ShapeCollider.cpp index 0eddc80c62..1b49caab22 100644 --- a/libraries/shared/src/ShapeCollider.cpp +++ b/libraries/shared/src/ShapeCollider.cpp @@ -92,8 +92,26 @@ bool collideShapesCoarse(const QVector& shapesA, const QVectorgetType(); + if (typeA == Shape::SPHERE_SHAPE) { + return sphereAACube(static_cast(shapeA), cubeCenter, cubeSide, collisions); + } else if (typeA == Shape::CAPSULE_SHAPE) { + return capsuleAACube(static_cast(shapeA), cubeCenter, cubeSide, collisions); + } else if (typeA == Shape::LIST_SHAPE) { + const ListShape* listA = static_cast(shapeA); + bool touching = false; + for (int i = 0; i < listA->size() && !collisions.isFull(); ++i) { + const Shape* subShape = listA->getSubShape(i); + int subType = subShape->getType(); + if (subType == Shape::SPHERE_SHAPE) { + touching = sphereAACube(static_cast(subShape), cubeCenter, cubeSide, collisions) || touching; + } else if (subType == Shape::CAPSULE_SHAPE) { + touching = capsuleAACube(static_cast(subShape), cubeCenter, cubeSide, collisions) || touching; + } + } + return touching; + } return false; } @@ -572,4 +590,62 @@ bool listList(const ListShape* listA, const ListShape* listB, CollisionList& col return touching; } +// helper function +bool sphereAACube(const glm::vec3& sphereCenter, float sphereRadius, const glm::vec3& cubeCenter, float cubeSide, CollisionList& collisions) { + glm::vec3 BA = cubeCenter - sphereCenter; + float distance = glm::length(BA); + if (distance > EPSILON) { + BA /= distance; // BA is now normalized + // compute the nearest point on sphere + glm::vec3 surfaceA = sphereCenter + sphereRadius * BA; + // compute the nearest point on cube + float maxBA = glm::max(glm::max(fabs(BA.x), fabs(BA.y)), fabs(BA.z)); + glm::vec3 surfaceB = cubeCenter - (0.5f * cubeSide / maxBA) * BA; + // collision happens when "vector to surfaceB from surfaceA" dots with BA to produce a positive value + glm::vec3 surfaceBA = surfaceB - surfaceA; + if (glm::dot(surfaceBA, BA) > 0.f) { + CollisionInfo* collision = collisions.getNewCollision(); + if (collision) { + collision->_penetration = surfaceBA; + // contactPoint is on surface of A + collision->_contactPoint = surfaceA; + return true; + } + } + } else if (sphereRadius + 0.5f * cubeSide > distance) { + // NOTE: for cocentric approximation we collide sphere and cube as two spheres which means + // this algorithm will probably be wrong when both sphere and cube are very small (both ~EPSILON) + CollisionInfo* collision = collisions.getNewCollision(); + if (collision) { + // the penetration and contactPoint are undefined, so we pick a penetration direction (-yAxis) + collision->_penetration = (sphereRadius + 0.5f * cubeSide) * glm::vec3(0.0f, -1.0f, 0.0f); + // contactPoint is on surface of A + collision->_contactPoint = sphereCenter + collision->_penetration; + return true; + } + } + return false; +} + +bool sphereAACube(const SphereShape* sphereA, const glm::vec3& cubeCenter, float cubeSide, CollisionList& collisions) { + return sphereAACube(sphereA->getPosition(), sphereA->getRadius(), cubeCenter, cubeSide, collisions); +} + +bool capsuleAACube(const CapsuleShape* capsuleA, const glm::vec3& cubeCenter, float cubeSide, CollisionList& collisions) { + // find nerest approach of capsule line segment to cube + glm::vec3 capsuleAxis; + capsuleA->computeNormalizedAxis(capsuleAxis); + float offset = glm::dot(cubeCenter - capsuleA->getPosition(), capsuleAxis); + float halfHeight = capsuleA->getHalfHeight(); + if (offset > halfHeight) { + offset = halfHeight; + } else if (offset < -halfHeight) { + offset = -halfHeight; + } + glm::vec3 nearestApproach = capsuleA->getPosition() + offset * capsuleAxis; + // collide nearest approach like a sphere at that point + return sphereAACube(nearestApproach, capsuleA->getRadius(), cubeCenter, cubeSide, collisions); +} + + } // namespace ShapeCollider diff --git a/libraries/shared/src/ShapeCollider.h b/libraries/shared/src/ShapeCollider.h index a020050662..9e83e31571 100644 --- a/libraries/shared/src/ShapeCollider.h +++ b/libraries/shared/src/ShapeCollider.h @@ -12,7 +12,6 @@ #ifndef hifi_ShapeCollider_h #define hifi_ShapeCollider_h -#include "AABox.h" #include "CapsuleShape.h" #include "CollisionInfo.h" #include "ListShape.h" @@ -35,10 +34,11 @@ namespace ShapeCollider { bool collideShapesCoarse(const QVector& shapesA, const QVector& shapesB, CollisionInfo& collision); /// \param shapeA a pointer to a shape - /// \param boxB an axis aligned box + /// \param cubeCenter center of cube + /// \param cubeSide lenght of side of cube /// \param collisions[out] average collision details - /// \return true if shapeA collides with boxB - bool collideShapeWithBox(const Shape* shapeA, const AABox& boxB, CollisionList& collisions); + /// \return true if shapeA collides with axis aligned cube + bool collideShapeWithAACube(const Shape* shapeA, const glm::vec3& cubeCenter, float cubeSide, CollisionList& collisions); /// \param sphereA pointer to first shape /// \param sphereB pointer to second shape @@ -136,6 +136,20 @@ namespace ShapeCollider { /// \return true if shapes collide bool listList(const ListShape* listA, const ListShape* listB, CollisionList& collisions); + /// \param sphereA pointer to sphere + /// \param cubeCenter center of cube + /// \param cubeSide lenght of side of cube + /// \param[out] collisions where to append collision details + /// \return true if sphereA collides with axis aligned cube + bool sphereAACube(const SphereShape* sphereA, const glm::vec3& cubeCenter, float cubeSide, CollisionList& collisions); + + /// \param capsuleA pointer to capsule + /// \param cubeCenter center of cube + /// \param cubeSide lenght of side of cube + /// \param[out] collisions where to append collision details + /// \return true if capsuleA collides with axis aligned cube + bool capsuleAACube(const CapsuleShape* capsuleA, const glm::vec3& cubeCenter, float cubeSide, CollisionList& collisions); + } // namespace ShapeCollider #endif // hifi_ShapeCollider_h From 8d6fa8f90471a5cc60ea444e52c1e03e2614d562 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 21 Apr 2014 18:19:59 -0700 Subject: [PATCH 07/35] fix sphere-vs-axis-aligned-cube logic --- libraries/shared/src/ShapeCollider.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libraries/shared/src/ShapeCollider.cpp b/libraries/shared/src/ShapeCollider.cpp index 1b49caab22..c0de3cb90b 100644 --- a/libraries/shared/src/ShapeCollider.cpp +++ b/libraries/shared/src/ShapeCollider.cpp @@ -15,6 +15,7 @@ #include "GeometryUtil.h" #include "ShapeCollider.h" +#include "StreamUtils.h" // NOTE: // @@ -601,9 +602,9 @@ bool sphereAACube(const glm::vec3& sphereCenter, float sphereRadius, const glm:: // compute the nearest point on cube float maxBA = glm::max(glm::max(fabs(BA.x), fabs(BA.y)), fabs(BA.z)); glm::vec3 surfaceB = cubeCenter - (0.5f * cubeSide / maxBA) * BA; - // collision happens when "vector to surfaceB from surfaceA" dots with BA to produce a positive value + // collision happens when "vector to surfaceB from surfaceA" dots with BA to produce a negative value glm::vec3 surfaceBA = surfaceB - surfaceA; - if (glm::dot(surfaceBA, BA) > 0.f) { + if (glm::dot(surfaceBA, BA) < 0.f) { CollisionInfo* collision = collisions.getNewCollision(); if (collision) { collision->_penetration = surfaceBA; From 1782e803c9d7c82a50f04fdeb99aa950c860a1ec Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 21 Apr 2014 18:21:39 -0700 Subject: [PATCH 08/35] remove include StreamUtils.h --- libraries/shared/src/ShapeCollider.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/shared/src/ShapeCollider.cpp b/libraries/shared/src/ShapeCollider.cpp index c0de3cb90b..16624f9fec 100644 --- a/libraries/shared/src/ShapeCollider.cpp +++ b/libraries/shared/src/ShapeCollider.cpp @@ -15,7 +15,6 @@ #include "GeometryUtil.h" #include "ShapeCollider.h" -#include "StreamUtils.h" // NOTE: // From 63c02f2b04e846bb861b1176d39710a992999b7a Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 21 Apr 2014 18:22:34 -0700 Subject: [PATCH 09/35] add subscript operator for CollisionList --- libraries/shared/src/CollisionInfo.cpp | 3 +++ libraries/shared/src/CollisionInfo.h | 2 ++ 2 files changed, 5 insertions(+) diff --git a/libraries/shared/src/CollisionInfo.cpp b/libraries/shared/src/CollisionInfo.cpp index 5a4188a1ef..6b2f48f4d0 100644 --- a/libraries/shared/src/CollisionInfo.cpp +++ b/libraries/shared/src/CollisionInfo.cpp @@ -48,3 +48,6 @@ void CollisionList::clear() { _size = 0; } +const CollisionInfo* CollisionList::operator[](int index) const { + return (index > -1 && index < _size) ? &(_collisions[index]) : NULL; +} diff --git a/libraries/shared/src/CollisionInfo.h b/libraries/shared/src/CollisionInfo.h index f575dd8595..209a7e6127 100644 --- a/libraries/shared/src/CollisionInfo.h +++ b/libraries/shared/src/CollisionInfo.h @@ -95,6 +95,8 @@ public: /// Clear valid collisions. void clear(); + const CollisionInfo* operator[](int index) const; + private: int _maxSize; // the container cannot get larger than this int _size; // the current number of valid collisions in the list From 06794f33f3a4b480ec8158656af4e40c4ac7c472 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 21 Apr 2014 18:23:19 -0700 Subject: [PATCH 10/35] add accessor for Model::_boundingShape --- interface/src/renderer/Model.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/interface/src/renderer/Model.h b/interface/src/renderer/Model.h index 65b79fffdd..a14b58c11a 100644 --- a/interface/src/renderer/Model.h +++ b/interface/src/renderer/Model.h @@ -193,6 +193,8 @@ public: /// Sets blended vertices computed in a separate thread. void setBlendedVertices(const QVector& vertices, const QVector& normals); + const CapsuleShape& getBoundingShape() const { return _boundingShape; } + protected: QSharedPointer _geometry; From 7cb6856415178e09a01c4e38e712f65c56143400 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 22 Apr 2014 10:44:41 -0700 Subject: [PATCH 11/35] Adding some collision tests for sphere-vs-AACube --- tests/physics/src/ShapeColliderTests.cpp | 113 +++++++++++++++++++++++ tests/physics/src/ShapeColliderTests.h | 3 + 2 files changed, 116 insertions(+) diff --git a/tests/physics/src/ShapeColliderTests.cpp b/tests/physics/src/ShapeColliderTests.cpp index f9e76bac0b..fe1d79b456 100644 --- a/tests/physics/src/ShapeColliderTests.cpp +++ b/tests/physics/src/ShapeColliderTests.cpp @@ -699,6 +699,116 @@ void ShapeColliderTests::capsuleTouchesCapsule() { } } +void ShapeColliderTests::sphereTouchesAACube() { + CollisionList collisions(16); + + glm::vec3 cubeCenter(1.23f, 4.56f, 7.89f); + float cubeSide = 2.0f; + + float sphereRadius = 1.0f; + glm::vec3 sphereCenter(0.f); + SphereShape sphere(sphereRadius, sphereCenter); + + float sphereOffset = (0.5f * cubeSide + sphereRadius - 0.25f); + + // top + sphereCenter = cubeCenter + sphereOffset * yAxis; + sphere.setPosition(sphereCenter); + if (!ShapeCollider::sphereAACube(&sphere, cubeCenter, cubeSide, collisions)){ + std::cout << __FILE__ << ":" << __LINE__ << " ERROR: sphere should collide with cube" << std::endl; + } + + // bottom + sphereCenter = cubeCenter - sphereOffset * yAxis; + sphere.setPosition(sphereCenter); + if (!ShapeCollider::sphereAACube(&sphere, cubeCenter, cubeSide, collisions)){ + std::cout << __FILE__ << ":" << __LINE__ << " ERROR: sphere should collide with cube" << std::endl; + } + + // left + sphereCenter = cubeCenter + sphereOffset * xAxis; + sphere.setPosition(sphereCenter); + if (!ShapeCollider::sphereAACube(&sphere, cubeCenter, cubeSide, collisions)){ + std::cout << __FILE__ << ":" << __LINE__ << " ERROR: sphere should collide with cube" << std::endl; + } + + // right + sphereCenter = cubeCenter - sphereOffset * xAxis; + sphere.setPosition(sphereCenter); + if (!ShapeCollider::sphereAACube(&sphere, cubeCenter, cubeSide, collisions)){ + std::cout << __FILE__ << ":" << __LINE__ << " ERROR: sphere should collide with cube" << std::endl; + } + + // forward + sphereCenter = cubeCenter + sphereOffset * zAxis; + sphere.setPosition(sphereCenter); + if (!ShapeCollider::sphereAACube(&sphere, cubeCenter, cubeSide, collisions)){ + std::cout << __FILE__ << ":" << __LINE__ << " ERROR: sphere should collide with cube" << std::endl; + } + + // back + sphereCenter = cubeCenter - sphereOffset * zAxis; + sphere.setPosition(sphereCenter); + if (!ShapeCollider::sphereAACube(&sphere, cubeCenter, cubeSide, collisions)){ + std::cout << __FILE__ << ":" << __LINE__ << " ERROR: sphere should collide with cube" << std::endl; + } +} + +void ShapeColliderTests::sphereMissesAACube() { + CollisionList collisions(16); + + glm::vec3 cubeCenter(1.23f, 4.56f, 7.89f); + float cubeSide = 2.0f; + + float sphereRadius = 1.0f; + glm::vec3 sphereCenter(0.0f); + SphereShape sphere(sphereRadius, sphereCenter); + + float sphereOffset = (0.5f * cubeSide + sphereRadius + 0.25f); + + // top + sphereCenter = cubeCenter + sphereOffset * yAxis; + sphere.setPosition(sphereCenter); + if (ShapeCollider::sphereAACube(&sphere, cubeCenter, cubeSide, collisions)){ + std::cout << __FILE__ << ":" << __LINE__ << " ERROR: sphere should NOT collide with cube" << std::endl; + } + + // bottom + sphereCenter = cubeCenter - sphereOffset * yAxis; + sphere.setPosition(sphereCenter); + if (ShapeCollider::sphereAACube(&sphere, cubeCenter, cubeSide, collisions)){ + std::cout << __FILE__ << ":" << __LINE__ << " ERROR: sphere should NOT collide with cube" << std::endl; + } + + // left + sphereCenter = cubeCenter + sphereOffset * xAxis; + sphere.setPosition(sphereCenter); + if (ShapeCollider::sphereAACube(&sphere, cubeCenter, cubeSide, collisions)){ + std::cout << __FILE__ << ":" << __LINE__ << " ERROR: sphere should NOT collide with cube" << std::endl; + } + + // right + sphereCenter = cubeCenter - sphereOffset * xAxis; + sphere.setPosition(sphereCenter); + if (ShapeCollider::sphereAACube(&sphere, cubeCenter, cubeSide, collisions)){ + std::cout << __FILE__ << ":" << __LINE__ << " ERROR: sphere should NOT collide with cube" << std::endl; + } + + // forward + sphereCenter = cubeCenter + sphereOffset * zAxis; + sphere.setPosition(sphereCenter); + if (ShapeCollider::sphereAACube(&sphere, cubeCenter, cubeSide, collisions)){ + std::cout << __FILE__ << ":" << __LINE__ << " ERROR: sphere should NOT collide with cube" << std::endl; + } + + // back + sphereCenter = cubeCenter - sphereOffset * zAxis; + sphere.setPosition(sphereCenter); + if (ShapeCollider::sphereAACube(&sphere, cubeCenter, cubeSide, collisions)){ + std::cout << __FILE__ << ":" << __LINE__ << " ERROR: sphere should NOT collide with cube" << std::endl; + } +} + void ShapeColliderTests::runAllTests() { sphereMissesSphere(); @@ -709,4 +819,7 @@ void ShapeColliderTests::runAllTests() { capsuleMissesCapsule(); capsuleTouchesCapsule(); + + sphereTouchesAACube(); + sphereMissesAACube(); } diff --git a/tests/physics/src/ShapeColliderTests.h b/tests/physics/src/ShapeColliderTests.h index 1d468a65d2..a94f5050ff 100644 --- a/tests/physics/src/ShapeColliderTests.h +++ b/tests/physics/src/ShapeColliderTests.h @@ -23,6 +23,9 @@ namespace ShapeColliderTests { void capsuleMissesCapsule(); void capsuleTouchesCapsule(); + void sphereTouchesAACube(); + void sphereMissesAACube(); + void runAllTests(); } From a45bc6c110355a5d187b7906a55e6c550b7c36b7 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 22 Apr 2014 10:48:05 -0700 Subject: [PATCH 12/35] remove const from CollisionList subscript operator --- libraries/octree/src/Octree.cpp | 7 +++++-- libraries/shared/src/CollisionInfo.cpp | 2 +- libraries/shared/src/CollisionInfo.h | 2 +- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/libraries/octree/src/Octree.cpp b/libraries/octree/src/Octree.cpp index 83b84b3c50..4bd37d873a 100644 --- a/libraries/octree/src/Octree.cpp +++ b/libraries/octree/src/Octree.cpp @@ -707,7 +707,7 @@ bool findCapsulePenetrationOp(OctreeElement* node, void* extraData) { } bool findShapeCollisionsOp(OctreeElement* node, void* extraData) { - const ShapeArgs* args = static_cast(extraData); + ShapeArgs* args = static_cast(extraData); // coarse check against bounds AABox cube = node->getAABox(); @@ -719,7 +719,10 @@ bool findShapeCollisionsOp(OctreeElement* node, void* extraData) { return true; // recurse on children } if (node->hasContent()) { - return ShapeCollider::collideShapeWithAACube(args->shape, cube.calcCenter(), cube.getScale(), args->collisions); + if (ShapeCollider::collideShapeWithAACube(args->shape, cube.calcCenter(), cube.getScale(), args->collisions)) { + args->found = true; + return true; + } } return false; } diff --git a/libraries/shared/src/CollisionInfo.cpp b/libraries/shared/src/CollisionInfo.cpp index 6b2f48f4d0..5d97842530 100644 --- a/libraries/shared/src/CollisionInfo.cpp +++ b/libraries/shared/src/CollisionInfo.cpp @@ -48,6 +48,6 @@ void CollisionList::clear() { _size = 0; } -const CollisionInfo* CollisionList::operator[](int index) const { +CollisionInfo* CollisionList::operator[](int index) { return (index > -1 && index < _size) ? &(_collisions[index]) : NULL; } diff --git a/libraries/shared/src/CollisionInfo.h b/libraries/shared/src/CollisionInfo.h index 209a7e6127..7db965fe64 100644 --- a/libraries/shared/src/CollisionInfo.h +++ b/libraries/shared/src/CollisionInfo.h @@ -95,7 +95,7 @@ public: /// Clear valid collisions. void clear(); - const CollisionInfo* operator[](int index) const; + CollisionInfo* operator[](int index); private: int _maxSize; // the container cannot get larger than this From 7537d240bb7a43db04d7020eb9ce02da5c1de142 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 22 Apr 2014 10:48:42 -0700 Subject: [PATCH 13/35] toward working avatar-vs-voxel collisions again --- interface/src/avatar/MyAvatar.cpp | 28 ++++++++++++++++++++++++++ libraries/shared/src/ShapeCollider.cpp | 14 ++++++++----- 2 files changed, 37 insertions(+), 5 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 8229611646..4ce1c2ad39 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include @@ -795,7 +796,33 @@ void MyAvatar::updateCollisionWithEnvironment(float deltaTime, float radius) { } } +static CollisionList myCollisions(64); + void MyAvatar::updateCollisionWithVoxels(float deltaTime, float radius) { + static int foo = 0; + ++foo; + +// const float VOXEL_ELASTICITY = 0.4f; +// const float VOXEL_DAMPING = 0.0f; + const float VOXEL_COLLISION_FREQUENCY = 0.5f; + + myCollisions.clear(); + const CapsuleShape& boundingShape = _skeletonModel.getBoundingShape(); + if (Application::getInstance()->getVoxelTree()->findShapeCollisions(&boundingShape, myCollisions)) { + for (int i = 0; i < myCollisions.size(); ++i) { + CollisionInfo* collision = myCollisions[i]; + //if (0 == (foo % 100)) { + std::cout << "adebug " << myCollisions.size() << " collisions p = " << collision->_penetration << std::endl; // adebug + //} + //applyHardCollision(collision->_penetration, VOXEL_ELASTICITY, VOXEL_DAMPING); + } + updateCollisionSound(myCollisions[0]->_penetration, deltaTime, VOXEL_COLLISION_FREQUENCY); + } else if (myCollisions.size() == 0) { + if (0 == (foo % 100)) { + std::cout << "adebug 0 collisions capC = " << boundingShape.getPosition() << " capR = " << boundingShape.getRadius() << std::endl; // adebug + } + } + /* const float VOXEL_ELASTICITY = 0.4f; const float VOXEL_DAMPING = 0.0f; const float VOXEL_COLLISION_FREQUENCY = 0.5f; @@ -808,6 +835,7 @@ void MyAvatar::updateCollisionWithVoxels(float deltaTime, float radius) { updateCollisionSound(penetration, deltaTime, VOXEL_COLLISION_FREQUENCY); applyHardCollision(penetration, VOXEL_ELASTICITY, VOXEL_DAMPING); } + */ } void MyAvatar::applyHardCollision(const glm::vec3& penetration, float elasticity, float damping) { diff --git a/libraries/shared/src/ShapeCollider.cpp b/libraries/shared/src/ShapeCollider.cpp index 16624f9fec..30bea1fef1 100644 --- a/libraries/shared/src/ShapeCollider.cpp +++ b/libraries/shared/src/ShapeCollider.cpp @@ -15,6 +15,7 @@ #include "GeometryUtil.h" #include "ShapeCollider.h" +#include "StreamUtils.h" // NOTE: // @@ -601,14 +602,17 @@ bool sphereAACube(const glm::vec3& sphereCenter, float sphereRadius, const glm:: // compute the nearest point on cube float maxBA = glm::max(glm::max(fabs(BA.x), fabs(BA.y)), fabs(BA.z)); glm::vec3 surfaceB = cubeCenter - (0.5f * cubeSide / maxBA) * BA; - // collision happens when "vector to surfaceB from surfaceA" dots with BA to produce a negative value - glm::vec3 surfaceBA = surfaceB - surfaceA; - if (glm::dot(surfaceBA, BA) < 0.f) { + // collision happens when "vector to surfaceA from surfaceB" dots with BA to produce a positive value + glm::vec3 surfaceAB = surfaceA - surfaceB; + if (glm::dot(surfaceAB, BA) > 0.f) { CollisionInfo* collision = collisions.getNewCollision(); if (collision) { - collision->_penetration = surfaceBA; + glm::vec3 normal(floorf(BA.x/maxBA), floorf(BA.y/maxBA), floorf(BA.z/maxBA)); + std::cout << "adebug normal = " << normal << std::endl; // adebug + normal = glm::normalize(normal); + collision->_penetration = glm::dot(surfaceAB, normal) * normal; // contactPoint is on surface of A - collision->_contactPoint = surfaceA; + collision->_contactPoint = sphereCenter - sphereRadius * normal; return true; } } From 65d3b4dc39ebe0887d52943f74f1ddf2e0c92370 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 22 Apr 2014 11:43:23 -0700 Subject: [PATCH 14/35] fix penetration direction for sphere-vs-AACube --- libraries/shared/src/ShapeCollider.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/libraries/shared/src/ShapeCollider.cpp b/libraries/shared/src/ShapeCollider.cpp index 30bea1fef1..b4a1aaf90c 100644 --- a/libraries/shared/src/ShapeCollider.cpp +++ b/libraries/shared/src/ShapeCollider.cpp @@ -607,12 +607,15 @@ bool sphereAACube(const glm::vec3& sphereCenter, float sphereRadius, const glm:: if (glm::dot(surfaceAB, BA) > 0.f) { CollisionInfo* collision = collisions.getNewCollision(); if (collision) { - glm::vec3 normal(floorf(BA.x/maxBA), floorf(BA.y/maxBA), floorf(BA.z/maxBA)); - std::cout << "adebug normal = " << normal << std::endl; // adebug - normal = glm::normalize(normal); - collision->_penetration = glm::dot(surfaceAB, normal) * normal; + // penetration is parallel to box side direction + glm::vec3 direction; + modff(BA.x/maxBA, &(direction.x)); + modff(BA.y/maxBA, &(direction.y)); + modff(BA.z/maxBA, &(direction.z)); + direction = glm::normalize(direction); + collision->_penetration = glm::dot(surfaceAB, direction) * direction; // contactPoint is on surface of A - collision->_contactPoint = sphereCenter - sphereRadius * normal; + collision->_contactPoint = sphereCenter - sphereRadius * direction; return true; } } From 62121b1232e8d8c55f873fae2ec00129f540daed Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 22 Apr 2014 11:46:15 -0700 Subject: [PATCH 15/35] remove include of StreamUtils.h again --- libraries/shared/src/ShapeCollider.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/shared/src/ShapeCollider.cpp b/libraries/shared/src/ShapeCollider.cpp index b4a1aaf90c..458c355221 100644 --- a/libraries/shared/src/ShapeCollider.cpp +++ b/libraries/shared/src/ShapeCollider.cpp @@ -15,7 +15,6 @@ #include "GeometryUtil.h" #include "ShapeCollider.h" -#include "StreamUtils.h" // NOTE: // From 0b9ebe4c081670c1d09a94e7033a62e2940a2fb9 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 22 Apr 2014 11:51:36 -0700 Subject: [PATCH 16/35] avatar-voxels collisions work again --- interface/src/avatar/MyAvatar.cpp | 35 +++++-------------------------- 1 file changed, 5 insertions(+), 30 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 99e6cba0c2..b7290641cb 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -799,43 +799,18 @@ void MyAvatar::updateCollisionWithEnvironment(float deltaTime, float radius) { static CollisionList myCollisions(64); void MyAvatar::updateCollisionWithVoxels(float deltaTime, float radius) { - static int foo = 0; - ++foo; - -// const float VOXEL_ELASTICITY = 0.4f; -// const float VOXEL_DAMPING = 0.0f; - const float VOXEL_COLLISION_FREQUENCY = 0.5f; - myCollisions.clear(); const CapsuleShape& boundingShape = _skeletonModel.getBoundingShape(); if (Application::getInstance()->getVoxelTree()->findShapeCollisions(&boundingShape, myCollisions)) { + const float VOXEL_ELASTICITY = 0.4f; + const float VOXEL_DAMPING = 0.0f; for (int i = 0; i < myCollisions.size(); ++i) { CollisionInfo* collision = myCollisions[i]; - //if (0 == (foo % 100)) { - std::cout << "adebug " << myCollisions.size() << " collisions p = " << collision->_penetration << std::endl; // adebug - //} - //applyHardCollision(collision->_penetration, VOXEL_ELASTICITY, VOXEL_DAMPING); + applyHardCollision(collision->_penetration, VOXEL_ELASTICITY, VOXEL_DAMPING); } + const float VOXEL_COLLISION_FREQUENCY = 0.5f; updateCollisionSound(myCollisions[0]->_penetration, deltaTime, VOXEL_COLLISION_FREQUENCY); - } else if (myCollisions.size() == 0) { - if (0 == (foo % 100)) { - std::cout << "adebug 0 collisions capC = " << boundingShape.getPosition() << " capR = " << boundingShape.getRadius() << std::endl; // adebug - } - } - /* - const float VOXEL_ELASTICITY = 0.4f; - const float VOXEL_DAMPING = 0.0f; - const float VOXEL_COLLISION_FREQUENCY = 0.5f; - glm::vec3 penetration; - float pelvisFloatingHeight = getPelvisFloatingHeight(); - if (Application::getInstance()->getVoxelTree()->findCapsulePenetration( - _position - glm::vec3(0.0f, pelvisFloatingHeight - radius, 0.0f), - _position + glm::vec3(0.0f, getSkeletonHeight() - pelvisFloatingHeight + radius, 0.0f), radius, penetration)) { - _lastCollisionPosition = _position; - updateCollisionSound(penetration, deltaTime, VOXEL_COLLISION_FREQUENCY); - applyHardCollision(penetration, VOXEL_ELASTICITY, VOXEL_DAMPING); - } - */ + } } void MyAvatar::applyHardCollision(const glm::vec3& penetration, float elasticity, float damping) { From 364431328f25893420da51f25762830da3925309 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 22 Apr 2014 14:26:40 -0700 Subject: [PATCH 17/35] remove include StreamUtils.h --- interface/src/avatar/MyAvatar.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index b7290641cb..c5639d5f00 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -23,7 +23,6 @@ #include #include #include -#include #include From f3fd81ca59fbe54d59dcd6c0ac3a3190cd4993e6 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 22 Apr 2014 14:26:52 -0700 Subject: [PATCH 18/35] use glm::modf() for less code --- libraries/shared/src/ShapeCollider.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/libraries/shared/src/ShapeCollider.cpp b/libraries/shared/src/ShapeCollider.cpp index 458c355221..3cd21cbcba 100644 --- a/libraries/shared/src/ShapeCollider.cpp +++ b/libraries/shared/src/ShapeCollider.cpp @@ -607,10 +607,9 @@ bool sphereAACube(const glm::vec3& sphereCenter, float sphereRadius, const glm:: CollisionInfo* collision = collisions.getNewCollision(); if (collision) { // penetration is parallel to box side direction + BA /= maxBA; glm::vec3 direction; - modff(BA.x/maxBA, &(direction.x)); - modff(BA.y/maxBA, &(direction.y)); - modff(BA.z/maxBA, &(direction.z)); + glm::modf(BA, direction); direction = glm::normalize(direction); collision->_penetration = glm::dot(surfaceAB, direction) * direction; // contactPoint is on surface of A From 1986ac6be334933c2b3bbba5e78c79fb4c2f8d3f Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 22 Apr 2014 20:53:12 -0700 Subject: [PATCH 19/35] collisions with cube get rounded normals at edges --- libraries/shared/src/ShapeCollider.cpp | 36 ++++++++++++++++++++++---- 1 file changed, 31 insertions(+), 5 deletions(-) diff --git a/libraries/shared/src/ShapeCollider.cpp b/libraries/shared/src/ShapeCollider.cpp index 3cd21cbcba..256c1aa388 100644 --- a/libraries/shared/src/ShapeCollider.cpp +++ b/libraries/shared/src/ShapeCollider.cpp @@ -606,11 +606,37 @@ bool sphereAACube(const glm::vec3& sphereCenter, float sphereRadius, const glm:: if (glm::dot(surfaceAB, BA) > 0.f) { CollisionInfo* collision = collisions.getNewCollision(); if (collision) { - // penetration is parallel to box side direction - BA /= maxBA; - glm::vec3 direction; - glm::modf(BA, direction); - direction = glm::normalize(direction); + // At this point imagine that sphereCenter touches a "normalized" cube with rounded edges. + // This cube has a sidelength of 2 and its smoothing radius is sphereRadius/maxBA. + // We're going to try to compute the "negative normal" (and hence direction of penetration) + // of this surface. + + float radius = sphereRadius / (distance * maxBA); // normalized radius + float shortLength = maxBA - radius; + glm::vec3 direction = BA; + if (shortLength > 0.0f) { + direction = glm::abs(BA) - glm::vec3(shortLength); + // Set any negative components to zero, and adopt the sign of the original BA component. + // Unfortunately there isn't an easy way to make this fast. + if (direction.x < 0.0f) { + direction.x = 0.f; + } else if (BA.x < 0.f) { + direction.x = -direction.x; + } + if (direction.y < 0.0f) { + direction.y = 0.f; + } else if (BA.y < 0.f) { + direction.y = -direction.y; + } + if (direction.z < 0.0f) { + direction.z = 0.f; + } else if (BA.z < 0.f) { + direction.z = -direction.z; + } + } + direction = glm::normalize(direction); + + // penetration is the projection of surfaceAB on direction collision->_penetration = glm::dot(surfaceAB, direction) * direction; // contactPoint is on surface of A collision->_contactPoint = sphereCenter - sphereRadius * direction; From 5992651c278e7e911525a3c9253dad13571163c1 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 22 Apr 2014 20:55:28 -0700 Subject: [PATCH 20/35] update avatar collision shapes when necessary --- interface/src/avatar/MyAvatar.cpp | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index c5639d5f00..e1d7463aa3 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -335,15 +335,17 @@ void MyAvatar::simulate(float deltaTime) { radius = myCamera->getAspectRatio() * (myCamera->getNearClip() / cos(myCamera->getFieldOfView() / 2.0f)); radius *= COLLISION_RADIUS_SCALAR; } - - if (_collisionFlags & COLLISION_GROUP_ENVIRONMENT) { - updateCollisionWithEnvironment(deltaTime, radius); - } - if (_collisionFlags & COLLISION_GROUP_VOXELS) { - updateCollisionWithVoxels(deltaTime, radius); - } - if (_collisionFlags & COLLISION_GROUP_AVATARS) { - updateCollisionWithAvatars(deltaTime); + if (_collisionFlags) { + updateShapePositions(); + if (_collisionFlags & COLLISION_GROUP_ENVIRONMENT) { + updateCollisionWithEnvironment(deltaTime, radius); + } + if (_collisionFlags & COLLISION_GROUP_VOXELS) { + updateCollisionWithVoxels(deltaTime, radius); + } + if (_collisionFlags & COLLISION_GROUP_AVATARS) { + updateCollisionWithAvatars(deltaTime); + } } } @@ -914,7 +916,6 @@ void MyAvatar::updateCollisionWithAvatars(float deltaTime) { // no need to compute a bunch of stuff if we have one or fewer avatars return; } - updateShapePositions(); float myBoundingRadius = getBoundingRadius(); const float BODY_COLLISION_RESOLUTION_FACTOR = glm::max(1.0f, deltaTime / BODY_COLLISION_RESOLUTION_TIMESCALE); From 7464ca0879bf8eb71a31e15ba61936ad6cf1b836 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 23 Apr 2014 08:38:58 -0700 Subject: [PATCH 21/35] non-rounded collision solution in comments --- libraries/shared/src/ShapeCollider.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/libraries/shared/src/ShapeCollider.cpp b/libraries/shared/src/ShapeCollider.cpp index 256c1aa388..31d57f14ad 100644 --- a/libraries/shared/src/ShapeCollider.cpp +++ b/libraries/shared/src/ShapeCollider.cpp @@ -606,6 +606,16 @@ bool sphereAACube(const glm::vec3& sphereCenter, float sphereRadius, const glm:: if (glm::dot(surfaceAB, BA) > 0.f) { CollisionInfo* collision = collisions.getNewCollision(); if (collision) { + /* KEEP THIS CODE -- this is how to collide the cube with stark face normals (no rounding). + * We might want to use this code later for sealing boundaries between adjacent voxels. + // penetration is parallel to box side direction + BA /= maxBA; + glm::vec3 direction; + glm::modf(BA, direction); + direction = glm::normalize(direction); + */ + + // For rounded normals at edges and corners: // At this point imagine that sphereCenter touches a "normalized" cube with rounded edges. // This cube has a sidelength of 2 and its smoothing radius is sphereRadius/maxBA. // We're going to try to compute the "negative normal" (and hence direction of penetration) From da5ac3d6645665b5e1443c666396ec5b922da2ea Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 23 Apr 2014 08:47:25 -0700 Subject: [PATCH 22/35] remove warning about signed/unsigned comparison --- domain-server/src/DomainServer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index eb62dacf79..e65f3968e0 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -449,7 +449,7 @@ void DomainServer::sendDomainListToNode(const SharedNodePointer& node, const Hif if (nodeInterestList.size() > 0) { DTLSServerSession* dtlsSession = _isUsingDTLS ? _dtlsSessions[senderSockAddr] : NULL; - unsigned int dataMTU = dtlsSession ? gnutls_dtls_get_data_mtu(*dtlsSession->getGnuTLSSession()) : MAX_PACKET_SIZE; + int dataMTU = dtlsSession ? (int)gnutls_dtls_get_data_mtu(*dtlsSession->getGnuTLSSession()) : MAX_PACKET_SIZE; // if the node has any interest types, send back those nodes as well foreach (const SharedNodePointer& otherNode, nodeList->getNodeHash()) { From bfe1ee377ba16d3d3b9f377b4c912fa25caf0dd5 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 23 Apr 2014 08:56:53 -0700 Subject: [PATCH 23/35] remove warning about signed/unsigned comparison Also change n.f to be n.0f as per coding standard --- interface/src/Audio.cpp | 53 +++++++++++++++++++---------------------- 1 file changed, 25 insertions(+), 28 deletions(-) diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index eb4a751356..0aba5a8ae5 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -480,7 +480,7 @@ void Audio::handleAudioInput() { float thisSample = 0; int samplesOverNoiseGate = 0; - const float NOISE_GATE_HEIGHT = 7.f; + const float NOISE_GATE_HEIGHT = 7.0f; const int NOISE_GATE_WIDTH = 5; const int NOISE_GATE_CLOSE_FRAME_DELAY = 5; const int NOISE_GATE_FRAMES_TO_AVERAGE = 5; @@ -490,7 +490,7 @@ void Audio::handleAudioInput() { // // Check clipping, adjust DC offset, and check if should open noise gate // - float measuredDcOffset = 0.f; + float measuredDcOffset = 0.0f; // Increment the time since the last clip if (_timeSinceLastClip >= 0.0f) { _timeSinceLastClip += (float) NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL / (float) SAMPLE_RATE; @@ -500,7 +500,7 @@ void Audio::handleAudioInput() { measuredDcOffset += monoAudioSamples[i]; monoAudioSamples[i] -= (int16_t) _dcOffset; thisSample = fabsf(monoAudioSamples[i]); - if (thisSample >= (32767.f * CLIPPING_THRESHOLD)) { + if (thisSample >= (32767.0f * CLIPPING_THRESHOLD)) { _timeSinceLastClip = 0.0f; } loudness += thisSample; @@ -511,18 +511,18 @@ void Audio::handleAudioInput() { } measuredDcOffset /= NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL; - if (_dcOffset == 0.f) { + if (_dcOffset == 0.0f) { // On first frame, copy over measured offset _dcOffset = measuredDcOffset; } else { - _dcOffset = DC_OFFSET_AVERAGING * _dcOffset + (1.f - DC_OFFSET_AVERAGING) * measuredDcOffset; + _dcOffset = DC_OFFSET_AVERAGING * _dcOffset + (1.0f - DC_OFFSET_AVERAGING) * measuredDcOffset; } // Add tone injection if enabled - const float TONE_FREQ = 220.f / SAMPLE_RATE * TWO_PI; - const float QUARTER_VOLUME = 8192.f; + const float TONE_FREQ = 220.0f / SAMPLE_RATE * TWO_PI; + const float QUARTER_VOLUME = 8192.0f; if (_toneInjectionEnabled) { - loudness = 0.f; + loudness = 0.0f; for (int i = 0; i < NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL; i++) { monoAudioSamples[i] = QUARTER_VOLUME * sinf(TONE_FREQ * (float)(i + _proceduralEffectSample)); loudness += fabsf(monoAudioSamples[i]); @@ -532,7 +532,7 @@ void Audio::handleAudioInput() { // If Noise Gate is enabled, check and turn the gate on and off if (!_toneInjectionEnabled && _noiseGateEnabled) { - float averageOfAllSampleFrames = 0.f; + float averageOfAllSampleFrames = 0.0f; _noiseSampleFrames[_noiseGateSampleCounter++] = _lastInputLoudness; if (_noiseGateSampleCounter == NUMBER_OF_NOISE_SAMPLE_FRAMES) { float smallestSample = FLT_MAX; @@ -660,9 +660,9 @@ void Audio::addReceivedAudioToBuffer(const QByteArray& audioByteArray) { _stdev.reset(); // Set jitter buffer to be a multiple of the measured standard deviation const int MAX_JITTER_BUFFER_SAMPLES = _ringBuffer.getSampleCapacity() / 2; - const float NUM_STANDARD_DEVIATIONS = 3.f; + const float NUM_STANDARD_DEVIATIONS = 3.0f; if (Menu::getInstance()->getAudioJitterBufferSamples() == 0) { - float newJitterBufferSamples = (NUM_STANDARD_DEVIATIONS * _measuredJitter) / 1000.f * SAMPLE_RATE; + float newJitterBufferSamples = (NUM_STANDARD_DEVIATIONS * _measuredJitter) / 1000.0f * SAMPLE_RATE; setJitterBufferSamples(glm::clamp((int)newJitterBufferSamples, 0, MAX_JITTER_BUFFER_SAMPLES)); } } @@ -903,10 +903,10 @@ void Audio::toggleAudioSpatialProcessing() { void Audio::addProceduralSounds(int16_t* monoInput, int numSamples) { float sample; const float COLLISION_SOUND_CUTOFF_LEVEL = 0.01f; - const float COLLISION_SOUND_MAX_VOLUME = 1000.f; + const float COLLISION_SOUND_MAX_VOLUME = 1000.0f; const float UP_MAJOR_FIFTH = powf(1.5f, 4.0f); - const float DOWN_TWO_OCTAVES = 4.f; - const float DOWN_FOUR_OCTAVES = 16.f; + const float DOWN_TWO_OCTAVES = 4.0f; + const float DOWN_FOUR_OCTAVES = 16.0f; float t; if (_collisionSoundMagnitude > COLLISION_SOUND_CUTOFF_LEVEL) { for (int i = 0; i < numSamples; i++) { @@ -936,12 +936,12 @@ void Audio::addProceduralSounds(int16_t* monoInput, int numSamples) { _proceduralEffectSample += numSamples; // Add a drum sound - const float MAX_VOLUME = 32000.f; - const float MAX_DURATION = 2.f; + const float MAX_VOLUME = 32000.0f; + const float MAX_DURATION = 2.0f; const float MIN_AUDIBLE_VOLUME = 0.001f; const float NOISE_MAGNITUDE = 0.02f; float frequency = (_drumSoundFrequency / SAMPLE_RATE) * TWO_PI; - if (_drumSoundVolume > 0.f) { + if (_drumSoundVolume > 0.0f) { for (int i = 0; i < numSamples; i++) { t = (float) _drumSoundSample + (float) i; sample = sinf(t * frequency); @@ -961,12 +961,12 @@ void Audio::addProceduralSounds(int16_t* monoInput, int numSamples) { _localProceduralSamples[i] = glm::clamp(_localProceduralSamples[i] + collisionSample, MIN_SAMPLE_VALUE, MAX_SAMPLE_VALUE); - _drumSoundVolume *= (1.f - _drumSoundDecay); + _drumSoundVolume *= (1.0f - _drumSoundDecay); } _drumSoundSample += numSamples; - _drumSoundDuration = glm::clamp(_drumSoundDuration - (AUDIO_CALLBACK_MSECS / 1000.f), 0.f, MAX_DURATION); - if (_drumSoundDuration == 0.f || (_drumSoundVolume < MIN_AUDIBLE_VOLUME)) { - _drumSoundVolume = 0.f; + _drumSoundDuration = glm::clamp(_drumSoundDuration - (AUDIO_CALLBACK_MSECS / 1000.0f), 0.0f, MAX_DURATION); + if (_drumSoundDuration == 0.0f || (_drumSoundVolume < MIN_AUDIBLE_VOLUME)) { + _drumSoundVolume = 0.0f; } } } @@ -999,7 +999,7 @@ void Audio::renderToolBox(int x, int y, bool boxed) { if (boxed) { - bool isClipping = ((getTimeSinceLastClip() > 0.f) && (getTimeSinceLastClip() < 1.f)); + bool isClipping = ((getTimeSinceLastClip() > 0.0f) && (getTimeSinceLastClip() < 1.0f)); const int BOX_LEFT_PADDING = 5; const int BOX_TOP_PADDING = 10; const int BOX_WIDTH = 266; @@ -1010,9 +1010,9 @@ void Audio::renderToolBox(int x, int y, bool boxed) { glBindTexture(GL_TEXTURE_2D, _boxTextureId); if (isClipping) { - glColor3f(1.f,0.f,0.f); + glColor3f(1.0f, 0.0f, 0.0f); } else { - glColor3f(.41f,.41f,.41f); + glColor3f(0.41f, 0.41f, 0.41f); } glBegin(GL_QUADS); @@ -1089,10 +1089,8 @@ void Audio::addBufferToScope( // Short int pointer to mapped samples in byte array int16_t* destination = (int16_t*) byteArray.data(); - for (int i = 0; i < NETWORK_SAMPLES_PER_FRAME; i++) { - + for (unsigned int i = 0; i < NETWORK_SAMPLES_PER_FRAME; i++) { sample = (float)source[i * sourceNumberOfChannels + sourceChannel]; - if (sample > 0) { value = (int16_t)(multiplier * logf(sample)); } else if (sample < 0) { @@ -1100,7 +1098,6 @@ void Audio::addBufferToScope( } else { value = 0; } - destination[i + frameOffset] = value; } } From a7771bc142e48d2ebf022445f78878346315fce0 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 23 Apr 2014 09:05:11 -0700 Subject: [PATCH 24/35] repair header comments for AABox.* --- libraries/octree/src/AABox.cpp | 2 +- libraries/octree/src/AABox.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/octree/src/AABox.cpp b/libraries/octree/src/AABox.cpp index ed99a24d38..51b31d4466 100644 --- a/libraries/octree/src/AABox.cpp +++ b/libraries/octree/src/AABox.cpp @@ -1,6 +1,6 @@ // // AABox.cpp -// libraries/shared/src +// libraries/octree/src // // Created by Brad Hefta-Gaub on 04/11/13. // Copyright 2013 High Fidelity, Inc. diff --git a/libraries/octree/src/AABox.h b/libraries/octree/src/AABox.h index 6531db4250..1aa0849b70 100644 --- a/libraries/octree/src/AABox.h +++ b/libraries/octree/src/AABox.h @@ -1,6 +1,6 @@ // // AABox.h -// libraries/shared/src +// libraries/octree/src // // Created by Brad Hefta-Gaub on 04/11/13. // Copyright 2013 High Fidelity, Inc. From f46a5dc96670f77ece6acf7c189db2ba4cb53624 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 23 Apr 2014 10:13:05 -0700 Subject: [PATCH 25/35] fix #2718 for warning about unused variable --- interface/src/ui/ScriptEditorWidget.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/interface/src/ui/ScriptEditorWidget.cpp b/interface/src/ui/ScriptEditorWidget.cpp index 1765a5ea1a..3f9b0137ef 100644 --- a/interface/src/ui/ScriptEditorWidget.cpp +++ b/interface/src/ui/ScriptEditorWidget.cpp @@ -39,7 +39,8 @@ ScriptEditorWidget::ScriptEditorWidget() : setTitleBarWidget(new QWidget()); QFontMetrics fm(_scriptEditorWidgetUI->scriptEdit->font()); _scriptEditorWidgetUI->scriptEdit->setTabStopWidth(fm.width('0') * 4); - ScriptHighlighting* highlighting = new ScriptHighlighting(_scriptEditorWidgetUI->scriptEdit->document()); + // We create a new ScriptHighligting QObject and provide it with a parent so this is NOT a memory leak. + new ScriptHighlighting(_scriptEditorWidgetUI->scriptEdit->document()); QTimer::singleShot(0, _scriptEditorWidgetUI->scriptEdit, SLOT(setFocus())); } From f7bc1ae62c310de94375629d63bce7cbad257561 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 23 Apr 2014 10:47:24 -0700 Subject: [PATCH 26/35] Working on integrating rotation into IK. --- interface/src/avatar/SkeletonModel.cpp | 25 +++++------------- interface/src/renderer/Model.cpp | 36 +++++++++++++++++--------- interface/src/renderer/Model.h | 5 ++-- 3 files changed, 34 insertions(+), 32 deletions(-) diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index 1c6a568754..6581bc1841 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -148,17 +148,12 @@ void SkeletonModel::applyPalmData(int jointIndex, const QVector& fingerJoin } const FBXGeometry& geometry = _geometry->getFBXGeometry(); float sign = (jointIndex == geometry.rightHandJointIndex) ? 1.0f : -1.0f; - int parentJointIndex = geometry.joints.at(jointIndex).parentIndex; - if (parentJointIndex == -1) { - return; - } - // rotate forearm to align with palm direction + // rotate palm to align with palm direction glm::quat palmRotation; - getJointRotation(parentJointIndex, palmRotation, true); - applyRotationDelta(parentJointIndex, rotationBetween(palmRotation * geometry.palmDirection, palm.getNormal()), true, true); - getJointRotation(parentJointIndex, palmRotation, true); - + getJointRotation(jointIndex, palmRotation, true); + palmRotation = rotationBetween(palmRotation * geometry.palmDirection, palm.getNormal()) * palmRotation; + // sort the finger indices by raw x, get the average direction QVector fingerIndices; glm::vec3 direction; @@ -178,18 +173,12 @@ void SkeletonModel::applyPalmData(int jointIndex, const QVector& fingerJoin float directionLength = glm::length(direction); const unsigned int MIN_ROTATION_FINGERS = 3; if (directionLength > EPSILON && palm.getNumFingers() >= MIN_ROTATION_FINGERS) { - applyRotationDelta(parentJointIndex, rotationBetween(palmRotation * glm::vec3(-sign, 0.0f, 0.0f), direction), - true, true); - getJointRotation(parentJointIndex, palmRotation, true); + palmRotation = rotationBetween(palmRotation * glm::vec3(-sign, 0.0f, 0.0f), direction) * palmRotation; } - // let wrist inherit forearm rotation - _jointStates[jointIndex].rotation = glm::quat(); - - // set elbow position from wrist position + // set hand position, rotation glm::vec3 forearmVector = palmRotation * glm::vec3(sign, 0.0f, 0.0f); - setJointPosition(parentJointIndex, palm.getPosition() + forearmVector * - geometry.joints.at(jointIndex).distanceToParent * extractUniformScale(_scale)); + setJointPosition(jointIndex, palm.getPosition(), palmRotation); } void SkeletonModel::updateJointState(int index) { diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index b373ffa545..9aa5bd8227 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -882,12 +882,12 @@ bool Model::getJointRotation(int jointIndex, glm::quat& rotation, bool fromBind) return true; } -bool Model::setJointPosition(int jointIndex, const glm::vec3& position, int lastFreeIndex, - bool allIntermediatesFree, const glm::vec3& alignment) { +bool Model::setJointPosition(int jointIndex, const glm::vec3& translation, const glm::quat& rotation, bool useRotation, + int lastFreeIndex, bool allIntermediatesFree, const glm::vec3& alignment) { if (jointIndex == -1 || _jointStates.isEmpty()) { return false; } - glm::vec3 relativePosition = position - _translation; + glm::vec3 relativePosition = translation - _translation; const FBXGeometry& geometry = _geometry->getFBXGeometry(); const QVector& freeLineage = geometry.joints.at(jointIndex).freeLineage; if (freeLineage.isEmpty()) { @@ -897,17 +897,20 @@ bool Model::setJointPosition(int jointIndex, const glm::vec3& position, int last lastFreeIndex = freeLineage.last(); } - // now update the joint states from the top - for (int j = freeLineage.size() - 1; j >= 0; j--) { - updateJointState(freeLineage.at(j)); - } - // this is a cyclic coordinate descent algorithm: see // http://www.ryanjuckett.com/programming/animation/21-cyclic-coordinate-descent-in-2d const int ITERATION_COUNT = 1; glm::vec3 worldAlignment = _rotation * alignment; for (int i = 0; i < ITERATION_COUNT; i++) { - // first, we go from the joint upwards, rotating the end as close as possible to the target + // first, try to rotate the end effector as close as possible to the target rotation, if any + glm::quat endRotation; + if (useRotation) { + getJointRotation(jointIndex, endRotation, true); + applyRotationDelta(jointIndex, rotation * glm::inverse(endRotation)); + getJointRotation(jointIndex, endRotation, true); + } + + // then, we go from the joint upwards, rotating the end as close as possible to the target glm::vec3 endPosition = extractTranslation(_jointStates[jointIndex].transform); for (int j = 1; freeLineage.at(j - 1) != lastFreeIndex; j++) { int index = freeLineage.at(j); @@ -919,8 +922,17 @@ bool Model::setJointPosition(int jointIndex, const glm::vec3& position, int last glm::vec3 jointPosition = extractTranslation(state.transform); glm::vec3 jointVector = endPosition - jointPosition; glm::quat oldCombinedRotation = state.combinedRotation; - applyRotationDelta(index, rotationBetween(jointVector, relativePosition - jointPosition)); - endPosition = state.combinedRotation * glm::inverse(oldCombinedRotation) * jointVector + jointPosition; + if (useRotation) { + applyRotationDelta(index, safeMix(rotationBetween(jointVector, relativePosition - jointPosition), + rotation * glm::inverse(endRotation), 0.5f)); + glm::quat actualDelta = state.combinedRotation * glm::inverse(oldCombinedRotation); + endRotation = actualDelta * endRotation; + endPosition = actualDelta * jointVector + jointPosition; + + } else { + applyRotationDelta(index, rotationBetween(jointVector, relativePosition - jointPosition)); + endPosition = state.combinedRotation * glm::inverse(oldCombinedRotation) * jointVector + jointPosition; + } if (alignment != glm::vec3() && j > 1) { jointVector = endPosition - jointPosition; glm::vec3 positionSum; @@ -1154,7 +1166,7 @@ void Model::applyCollision(CollisionInfo& collision) { getJointPosition(jointIndex, end); glm::vec3 newEnd = start + glm::angleAxis(angle, axis) * (end - start); // try to move it - setJointPosition(jointIndex, newEnd, -1, true); + setJointPosition(jointIndex, newEnd, glm::quat(), false, -1, true); } } } diff --git a/interface/src/renderer/Model.h b/interface/src/renderer/Model.h index b472e17b20..10e9e2a66a 100644 --- a/interface/src/renderer/Model.h +++ b/interface/src/renderer/Model.h @@ -240,8 +240,9 @@ protected: bool getJointPosition(int jointIndex, glm::vec3& position) const; bool getJointRotation(int jointIndex, glm::quat& rotation, bool fromBind = false) const; - bool setJointPosition(int jointIndex, const glm::vec3& position, int lastFreeIndex = -1, - bool allIntermediatesFree = false, const glm::vec3& alignment = glm::vec3(0.0f, -1.0f, 0.0f)); + bool setJointPosition(int jointIndex, const glm::vec3& translation, const glm::quat& rotation = glm::quat(), + bool useRotation = false, int lastFreeIndex = -1, bool allIntermediatesFree = false, + const glm::vec3& alignment = glm::vec3(0.0f, -1.0f, 0.0f)); bool setJointRotation(int jointIndex, const glm::quat& rotation, bool fromBind = false); void setJointTranslation(int jointIndex, const glm::vec3& translation); From 511fc8367f425eb0c6c9f4f55221cf0747555d7b Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 23 Apr 2014 11:34:34 -0700 Subject: [PATCH 27/35] More work on IK. --- interface/src/avatar/SkeletonModel.cpp | 3 +-- interface/src/renderer/Model.cpp | 26 +++++++++++++++----------- 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index 6581bc1841..f52858b4ff 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -177,8 +177,7 @@ void SkeletonModel::applyPalmData(int jointIndex, const QVector& fingerJoin } // set hand position, rotation - glm::vec3 forearmVector = palmRotation * glm::vec3(sign, 0.0f, 0.0f); - setJointPosition(jointIndex, palm.getPosition(), palmRotation); + setJointPosition(jointIndex, palm.getPosition(), palmRotation, true); } void SkeletonModel::updateJointState(int index) { diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 9aa5bd8227..77d9743cd5 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -896,6 +896,7 @@ bool Model::setJointPosition(int jointIndex, const glm::vec3& translation, const if (lastFreeIndex == -1) { lastFreeIndex = freeLineage.last(); } + float baseWeight = 1.0f / (freeLineage.indexOf(lastFreeIndex) + (useRotation ? 1 : 0)); // this is a cyclic coordinate descent algorithm: see // http://www.ryanjuckett.com/programming/animation/21-cyclic-coordinate-descent-in-2d @@ -906,7 +907,7 @@ bool Model::setJointPosition(int jointIndex, const glm::vec3& translation, const glm::quat endRotation; if (useRotation) { getJointRotation(jointIndex, endRotation, true); - applyRotationDelta(jointIndex, rotation * glm::inverse(endRotation)); + applyRotationDelta(jointIndex, safeMix(glm::quat(), rotation * glm::inverse(endRotation), baseWeight)); getJointRotation(jointIndex, endRotation, true); } @@ -922,17 +923,13 @@ bool Model::setJointPosition(int jointIndex, const glm::vec3& translation, const glm::vec3 jointPosition = extractTranslation(state.transform); glm::vec3 jointVector = endPosition - jointPosition; glm::quat oldCombinedRotation = state.combinedRotation; + glm::quat combinedDelta; + float combinedWeight = 0.0f; if (useRotation) { - applyRotationDelta(index, safeMix(rotationBetween(jointVector, relativePosition - jointPosition), - rotation * glm::inverse(endRotation), 0.5f)); - glm::quat actualDelta = state.combinedRotation * glm::inverse(oldCombinedRotation); - endRotation = actualDelta * endRotation; - endPosition = actualDelta * jointVector + jointPosition; - - } else { - applyRotationDelta(index, rotationBetween(jointVector, relativePosition - jointPosition)); - endPosition = state.combinedRotation * glm::inverse(oldCombinedRotation) * jointVector + jointPosition; + combinedDelta = safeMix(combinedDelta, rotation * glm::inverse(endRotation), baseWeight / (combinedWeight += 1.0f)); } + combinedDelta = safeMix(combinedDelta, rotationBetween(jointVector, relativePosition - jointPosition), + baseWeight / (combinedWeight += 1.0f)); if (alignment != glm::vec3() && j > 1) { jointVector = endPosition - jointPosition; glm::vec3 positionSum; @@ -946,9 +943,16 @@ bool Model::setJointPosition(int jointIndex, const glm::vec3& translation, const glm::vec3 projectedAlignment = glm::cross(jointVector, glm::cross(worldAlignment, jointVector)); const float LENGTH_EPSILON = 0.001f; if (glm::length(projectedCenterOfMass) > LENGTH_EPSILON && glm::length(projectedAlignment) > LENGTH_EPSILON) { - applyRotationDelta(index, rotationBetween(projectedCenterOfMass, projectedAlignment)); + combinedDelta = safeMix(combinedDelta, rotationBetween(projectedCenterOfMass, projectedAlignment), + baseWeight / (combinedWeight += 1.0f)); } } + applyRotationDelta(index, combinedDelta); + glm::quat actualDelta = state.combinedRotation * glm::inverse(oldCombinedRotation); + endPosition = actualDelta * jointVector + jointPosition; + if (useRotation) { + endRotation = actualDelta * endRotation; + } } } From 523498ee5b918b4cbc5a0930522fddd09dc51274 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 23 Apr 2014 11:52:22 -0700 Subject: [PATCH 28/35] Revert to using weight that doesn't depend on number of free joints. --- interface/src/renderer/Model.cpp | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 77d9743cd5..143b6a8109 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -896,8 +896,7 @@ bool Model::setJointPosition(int jointIndex, const glm::vec3& translation, const if (lastFreeIndex == -1) { lastFreeIndex = freeLineage.last(); } - float baseWeight = 1.0f / (freeLineage.indexOf(lastFreeIndex) + (useRotation ? 1 : 0)); - + // this is a cyclic coordinate descent algorithm: see // http://www.ryanjuckett.com/programming/animation/21-cyclic-coordinate-descent-in-2d const int ITERATION_COUNT = 1; @@ -907,7 +906,7 @@ bool Model::setJointPosition(int jointIndex, const glm::vec3& translation, const glm::quat endRotation; if (useRotation) { getJointRotation(jointIndex, endRotation, true); - applyRotationDelta(jointIndex, safeMix(glm::quat(), rotation * glm::inverse(endRotation), baseWeight)); + applyRotationDelta(jointIndex, rotation * glm::inverse(endRotation)); getJointRotation(jointIndex, endRotation, true); } @@ -924,12 +923,15 @@ bool Model::setJointPosition(int jointIndex, const glm::vec3& translation, const glm::vec3 jointVector = endPosition - jointPosition; glm::quat oldCombinedRotation = state.combinedRotation; glm::quat combinedDelta; - float combinedWeight = 0.0f; + float combinedWeight; if (useRotation) { - combinedDelta = safeMix(combinedDelta, rotation * glm::inverse(endRotation), baseWeight / (combinedWeight += 1.0f)); + combinedDelta = rotation * glm::inverse(endRotation); + combinedWeight = 1.0f; + } else { + combinedDelta = safeMix(rotation * glm::inverse(endRotation), + rotationBetween(jointVector, relativePosition - jointPosition), 0.5f); + combinedWeight = 2.0f; } - combinedDelta = safeMix(combinedDelta, rotationBetween(jointVector, relativePosition - jointPosition), - baseWeight / (combinedWeight += 1.0f)); if (alignment != glm::vec3() && j > 1) { jointVector = endPosition - jointPosition; glm::vec3 positionSum; @@ -944,7 +946,7 @@ bool Model::setJointPosition(int jointIndex, const glm::vec3& translation, const const float LENGTH_EPSILON = 0.001f; if (glm::length(projectedCenterOfMass) > LENGTH_EPSILON && glm::length(projectedAlignment) > LENGTH_EPSILON) { combinedDelta = safeMix(combinedDelta, rotationBetween(projectedCenterOfMass, projectedAlignment), - baseWeight / (combinedWeight += 1.0f)); + 1.0f / (combinedWeight + 1.0f)); } } applyRotationDelta(index, combinedDelta); From 09bb51261a14b471804611403c9228a56880de7d Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 23 Apr 2014 11:55:16 -0700 Subject: [PATCH 29/35] Got that backwards. --- interface/src/renderer/Model.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 143b6a8109..26e59635bb 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -925,12 +925,13 @@ bool Model::setJointPosition(int jointIndex, const glm::vec3& translation, const glm::quat combinedDelta; float combinedWeight; if (useRotation) { - combinedDelta = rotation * glm::inverse(endRotation); - combinedWeight = 1.0f; - } else { combinedDelta = safeMix(rotation * glm::inverse(endRotation), rotationBetween(jointVector, relativePosition - jointPosition), 0.5f); combinedWeight = 2.0f; + + } else { + combinedDelta = rotationBetween(jointVector, relativePosition - jointPosition); + combinedWeight = 1.0f; } if (alignment != glm::vec3() && j > 1) { jointVector = endPosition - jointPosition; From 0386dec2a67e0f8d450d7f49c8643bb82c9427ba Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 23 Apr 2014 12:09:54 -0700 Subject: [PATCH 30/35] Provide option to align wrists with forearms. --- interface/src/Menu.cpp | 1 + interface/src/Menu.h | 1 + interface/src/avatar/SkeletonModel.cpp | 20 ++++++++++++++++++-- 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 0a0bd599eb..a7012d838d 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -336,6 +336,7 @@ Menu::Menu() : addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::PlaySlaps, 0, false); addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::HandsCollideWithSelf, 0, false); addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::ShowIKConstraints, 0, false); + addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::AlignForearmsWithWrists, 0, true); addDisabledActionAndSeparator(developerMenu, "Testing"); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index f9f97be379..09b5fabfc8 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -256,6 +256,7 @@ private: namespace MenuOption { const QString AboutApp = "About Interface"; + const QString AlignForearmsWithWrists = "Align Forearms with Wrists"; const QString AmbientOcclusion = "Ambient Occlusion"; const QString Atmosphere = "Atmosphere"; const QString AudioNoiseReduction = "Audio Noise Reduction"; diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index f52858b4ff..4bb7814300 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -148,10 +148,18 @@ void SkeletonModel::applyPalmData(int jointIndex, const QVector& fingerJoin } const FBXGeometry& geometry = _geometry->getFBXGeometry(); float sign = (jointIndex == geometry.rightHandJointIndex) ? 1.0f : -1.0f; + int parentJointIndex = geometry.joints.at(jointIndex).parentIndex; + if (parentJointIndex == -1) { + return; + } // rotate palm to align with palm direction glm::quat palmRotation; - getJointRotation(jointIndex, palmRotation, true); + if (Menu::getInstance()->isOptionChecked(MenuOption::AlignForearmsWithWrists)) { + getJointRotation(parentJointIndex, palmRotation, true); + } else { + getJointRotation(jointIndex, palmRotation, true); + } palmRotation = rotationBetween(palmRotation * geometry.palmDirection, palm.getNormal()) * palmRotation; // sort the finger indices by raw x, get the average direction @@ -177,7 +185,15 @@ void SkeletonModel::applyPalmData(int jointIndex, const QVector& fingerJoin } // set hand position, rotation - setJointPosition(jointIndex, palm.getPosition(), palmRotation, true); + if (Menu::getInstance()->isOptionChecked(MenuOption::AlignForearmsWithWrists)) { + glm::vec3 forearmVector = palmRotation * glm::vec3(sign, 0.0f, 0.0f); + setJointPosition(parentJointIndex, palm.getPosition() + forearmVector * + geometry.joints.at(jointIndex).distanceToParent * extractUniformScale(_scale), palmRotation, true); + _jointStates[jointIndex].rotation = glm::quat(); + + } else { + setJointPosition(jointIndex, palm.getPosition(), palmRotation, true); + } } void SkeletonModel::updateJointState(int index) { From 141250d51c0a2153461a3f3ce1156c11123ce21e Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 23 Apr 2014 12:22:24 -0700 Subject: [PATCH 31/35] Don't constrain elbow when rotating forearm with wrist. --- interface/src/avatar/SkeletonModel.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index 4bb7814300..f8ebba676f 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -188,7 +188,8 @@ void SkeletonModel::applyPalmData(int jointIndex, const QVector& fingerJoin if (Menu::getInstance()->isOptionChecked(MenuOption::AlignForearmsWithWrists)) { glm::vec3 forearmVector = palmRotation * glm::vec3(sign, 0.0f, 0.0f); setJointPosition(parentJointIndex, palm.getPosition() + forearmVector * - geometry.joints.at(jointIndex).distanceToParent * extractUniformScale(_scale), palmRotation, true); + geometry.joints.at(jointIndex).distanceToParent * extractUniformScale(_scale)); + setJointRotation(parentJointIndex, palmRotation, true); _jointStates[jointIndex].rotation = glm::quat(); } else { From c8c3cf3664ced00de93a0a23d059b7cbbe0c697d Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 23 Apr 2014 12:29:01 -0700 Subject: [PATCH 32/35] Remove unused propagate option for applyRotationDelta. --- interface/src/renderer/Model.cpp | 8 +------- interface/src/renderer/Model.h | 2 +- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 26e59635bb..9c7dc9a6a1 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -1026,7 +1026,7 @@ float Model::getLimbLength(int jointIndex) const { return length; } -void Model::applyRotationDelta(int jointIndex, const glm::quat& delta, bool constrain, bool propagate) { +void Model::applyRotationDelta(int jointIndex, const glm::quat& delta, bool constrain) { JointState& state = _jointStates[jointIndex]; const FBXGeometry& geometry = _geometry->getFBXGeometry(); const FBXJoint& joint = geometry.joints[jointIndex]; @@ -1042,12 +1042,6 @@ void Model::applyRotationDelta(int jointIndex, const glm::quat& delta, bool cons glm::quat newRotation = glm::quat(glm::clamp(eulers, joint.rotationMin, joint.rotationMax)); state.combinedRotation = state.combinedRotation * glm::inverse(state.rotation) * newRotation; state.rotation = newRotation; - - if (propagate && targetRotation != state.combinedRotation && - joint.parentIndex != -1 && geometry.joints.at(joint.parentIndex).isFree) { - applyRotationDelta(joint.parentIndex, targetRotation * glm::inverse(state.combinedRotation), true, true); - state.combinedRotation = _jointStates.at(joint.parentIndex).combinedRotation * state.rotation; - } } const int BALL_SUBDIVISIONS = 10; diff --git a/interface/src/renderer/Model.h b/interface/src/renderer/Model.h index 10e9e2a66a..335071d669 100644 --- a/interface/src/renderer/Model.h +++ b/interface/src/renderer/Model.h @@ -257,7 +257,7 @@ protected: /// first free ancestor. float getLimbLength(int jointIndex) const; - void applyRotationDelta(int jointIndex, const glm::quat& delta, bool constrain = true, bool propagate = false); + void applyRotationDelta(int jointIndex, const glm::quat& delta, bool constrain = true); private: From 2bac8024079ce096462acaf8538c67aaf3bc9815 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 23 Apr 2014 12:30:39 -0700 Subject: [PATCH 33/35] One more unused variable. --- interface/src/renderer/Model.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 9c7dc9a6a1..3484ac5fc8 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -1028,8 +1028,7 @@ float Model::getLimbLength(int jointIndex) const { void Model::applyRotationDelta(int jointIndex, const glm::quat& delta, bool constrain) { JointState& state = _jointStates[jointIndex]; - const FBXGeometry& geometry = _geometry->getFBXGeometry(); - const FBXJoint& joint = geometry.joints[jointIndex]; + const FBXJoint& joint = _geometry->getFBXGeometry().joints[jointIndex]; if (!constrain || (joint.rotationMin == glm::vec3(-PI, -PI, -PI) && joint.rotationMax == glm::vec3(PI, PI, PI))) { // no constraints From fe42f66cc9afc856a850ab5944c498a061dae79d Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 23 Apr 2014 13:27:43 -0700 Subject: [PATCH 34/35] change x.f to be x.0f as per the coding standard --- tests/physics/src/ShapeColliderTests.cpp | 112 ++++++++++------------- 1 file changed, 47 insertions(+), 65 deletions(-) diff --git a/tests/physics/src/ShapeColliderTests.cpp b/tests/physics/src/ShapeColliderTests.cpp index fe1d79b456..3f952236e2 100644 --- a/tests/physics/src/ShapeColliderTests.cpp +++ b/tests/physics/src/ShapeColliderTests.cpp @@ -23,18 +23,18 @@ #include "ShapeColliderTests.h" -const glm::vec3 origin(0.f); -static const glm::vec3 xAxis(1.f, 0.f, 0.f); -static const glm::vec3 yAxis(0.f, 1.f, 0.f); -static const glm::vec3 zAxis(0.f, 0.f, 1.f); +const glm::vec3 origin(0.0f); +static const glm::vec3 xAxis(1.0f, 0.0f, 0.0f); +static const glm::vec3 yAxis(0.0f, 1.0f, 0.0f); +static const glm::vec3 zAxis(0.0f, 0.0f, 1.0f); void ShapeColliderTests::sphereMissesSphere() { // non-overlapping spheres of unequal size - float radiusA = 7.f; - float radiusB = 3.f; + float radiusA = 7.0f; + float radiusB = 3.0f; float alpha = 1.2f; float beta = 1.3f; - glm::vec3 offsetDirection = glm::normalize(glm::vec3(1.f, 2.f, 3.f)); + glm::vec3 offsetDirection = glm::normalize(glm::vec3(1.0f, 2.0f, 3.0f)); float offsetDistance = alpha * radiusA + beta * radiusB; SphereShape sphereA(radiusA, origin); @@ -77,13 +77,13 @@ void ShapeColliderTests::sphereMissesSphere() { void ShapeColliderTests::sphereTouchesSphere() { // overlapping spheres of unequal size - float radiusA = 7.f; - float radiusB = 3.f; + float radiusA = 7.0f; + float radiusB = 3.0f; float alpha = 0.2f; float beta = 0.3f; - glm::vec3 offsetDirection = glm::normalize(glm::vec3(1.f, 2.f, 3.f)); + glm::vec3 offsetDirection = glm::normalize(glm::vec3(1.0f, 2.0f, 3.0f)); float offsetDistance = alpha * radiusA + beta * radiusB; - float expectedPenetrationDistance = (1.f - alpha) * radiusA + (1.f - beta) * radiusB; + float expectedPenetrationDistance = (1.0f - alpha) * radiusA + (1.0f - beta) * radiusB; glm::vec3 expectedPenetration = expectedPenetrationDistance * offsetDirection; SphereShape sphereA(radiusA, origin); @@ -118,8 +118,7 @@ void ShapeColliderTests::sphereTouchesSphere() { if (fabs(inaccuracy) > EPSILON) { std::cout << __FILE__ << ":" << __LINE__ << " ERROR: bad penetration: expected = " << expectedPenetration - << " actual = " << collision->_penetration - << std::endl; + << " actual = " << collision->_penetration; } // contactPoint is on surface of sphereA @@ -129,8 +128,7 @@ void ShapeColliderTests::sphereTouchesSphere() { if (fabs(inaccuracy) > EPSILON) { std::cout << __FILE__ << ":" << __LINE__ << " ERROR: bad contactPoint: expected = " << expectedContactPoint - << " actual = " << collision->_contactPoint - << std::endl; + << " actual = " << collision->_contactPoint; } } @@ -150,8 +148,7 @@ void ShapeColliderTests::sphereTouchesSphere() { if (fabs(inaccuracy) > EPSILON) { std::cout << __FILE__ << ":" << __LINE__ << " ERROR: bad penetration: expected = " << expectedPenetration - << " actual = " << collision->_penetration - << std::endl; + << " actual = " << collision->_penetration; } // contactPoint is on surface of sphereA @@ -161,8 +158,7 @@ void ShapeColliderTests::sphereTouchesSphere() { if (fabs(inaccuracy) > EPSILON) { std::cout << __FILE__ << ":" << __LINE__ << " ERROR: bad contactPoint: expected = " << expectedContactPoint - << " actual = " << collision->_contactPoint - << std::endl; + << " actual = " << collision->_contactPoint; } } } @@ -181,7 +177,7 @@ void ShapeColliderTests::sphereMissesCapsule() { // give the capsule some arbirary transform float angle = 37.8f; - glm::vec3 axis = glm::normalize( glm::vec3(-7.f, 2.8f, 9.3f) ); + glm::vec3 axis = glm::normalize( glm::vec3(-7.0f, 2.8f, 9.3f) ); glm::quat rotation = glm::angleAxis(angle, axis); glm::vec3 translation(15.1f, -27.1f, -38.6f); capsuleB.setRotation(rotation); @@ -190,7 +186,7 @@ void ShapeColliderTests::sphereMissesCapsule() { CollisionList collisions(16); // walk sphereA along the local yAxis next to, but not touching, capsuleB - glm::vec3 localStartPosition(radialOffset, axialOffset, 0.f); + glm::vec3 localStartPosition(radialOffset, axialOffset, 0.0f); int numberOfSteps = 10; float delta = 1.3f * (totalRadius + halfHeightB) / (numberOfSteps - 1); for (int i = 0; i < numberOfSteps; ++i) { @@ -224,10 +220,10 @@ void ShapeColliderTests::sphereMissesCapsule() { void ShapeColliderTests::sphereTouchesCapsule() { // overlapping sphere and capsule - float radiusA = 2.f; - float radiusB = 1.f; + float radiusA = 2.0f; + float radiusB = 1.0f; float totalRadius = radiusA + radiusB; - float halfHeightB = 2.f; + float halfHeightB = 2.0f; float alpha = 0.5f; float beta = 0.5f; float radialOffset = alpha * radiusA + beta * radiusB; @@ -257,8 +253,7 @@ void ShapeColliderTests::sphereTouchesCapsule() { if (fabs(inaccuracy) > EPSILON) { std::cout << __FILE__ << ":" << __LINE__ << " ERROR: bad penetration: expected = " << expectedPenetration - << " actual = " << collision->_penetration - << std::endl; + << " actual = " << collision->_penetration; } // contactPoint is on surface of sphereA @@ -267,8 +262,7 @@ void ShapeColliderTests::sphereTouchesCapsule() { if (fabs(inaccuracy) > EPSILON) { std::cout << __FILE__ << ":" << __LINE__ << " ERROR: bad contactPoint: expected = " << expectedContactPoint - << " actual = " << collision->_contactPoint - << std::endl; + << " actual = " << collision->_contactPoint; } // capsuleB collides with sphereA @@ -288,8 +282,7 @@ void ShapeColliderTests::sphereTouchesCapsule() { if (fabs(inaccuracy) > EPSILON) { std::cout << __FILE__ << ":" << __LINE__ << " ERROR: bad penetration: expected = " << expectedPenetration - << " actual = " << collision->_penetration - << std::endl; + << " actual = " << collision->_penetration; } // contactPoint is on surface of capsuleB @@ -300,8 +293,7 @@ void ShapeColliderTests::sphereTouchesCapsule() { if (fabs(inaccuracy) > EPSILON) { std::cout << __FILE__ << ":" << __LINE__ << " ERROR: bad contactPoint: expected = " << expectedContactPoint - << " actual = " << collision->_contactPoint - << std::endl; + << " actual = " << collision->_contactPoint; } } { // sphereA hits end cap at axis @@ -319,13 +311,12 @@ void ShapeColliderTests::sphereTouchesCapsule() { // penetration points from sphereA into capsuleB CollisionInfo* collision = collisions.getCollision(numCollisions - 1); - glm::vec3 expectedPenetration = - ((1.f - alpha) * radiusA + (1.f - beta) * radiusB) * yAxis; + glm::vec3 expectedPenetration = - ((1.0f - alpha) * radiusA + (1.0f - beta) * radiusB) * yAxis; float inaccuracy = glm::length(collision->_penetration - expectedPenetration); if (fabs(inaccuracy) > EPSILON) { std::cout << __FILE__ << ":" << __LINE__ << " ERROR: bad penetration: expected = " << expectedPenetration - << " actual = " << collision->_penetration - << std::endl; + << " actual = " << collision->_penetration; } // contactPoint is on surface of sphereA @@ -334,8 +325,7 @@ void ShapeColliderTests::sphereTouchesCapsule() { if (fabs(inaccuracy) > EPSILON) { std::cout << __FILE__ << ":" << __LINE__ << " ERROR: bad contactPoint: expected = " << expectedContactPoint - << " actual = " << collision->_contactPoint - << std::endl; + << " actual = " << collision->_contactPoint; } // capsuleB collides with sphereA @@ -350,13 +340,12 @@ void ShapeColliderTests::sphereTouchesCapsule() { // penetration points from sphereA into capsuleB collision = collisions.getCollision(numCollisions - 1); - expectedPenetration = ((1.f - alpha) * radiusA + (1.f - beta) * radiusB) * yAxis; + expectedPenetration = ((1.0f - alpha) * radiusA + (1.0f - beta) * radiusB) * yAxis; inaccuracy = glm::length(collision->_penetration - expectedPenetration); if (fabs(inaccuracy) > EPSILON) { std::cout << __FILE__ << ":" << __LINE__ << " ERROR: bad penetration: expected = " << expectedPenetration - << " actual = " << collision->_penetration - << std::endl; + << " actual = " << collision->_penetration; } // contactPoint is on surface of capsuleB @@ -367,8 +356,7 @@ void ShapeColliderTests::sphereTouchesCapsule() { if (fabs(inaccuracy) > EPSILON) { std::cout << __FILE__ << ":" << __LINE__ << " ERROR: bad contactPoint: expected = " << expectedContactPoint - << " actual = " << collision->_contactPoint - << std::endl; + << " actual = " << collision->_contactPoint; } } { // sphereA hits start cap at axis @@ -386,13 +374,12 @@ void ShapeColliderTests::sphereTouchesCapsule() { // penetration points from sphereA into capsuleB CollisionInfo* collision = collisions.getCollision(numCollisions - 1); - glm::vec3 expectedPenetration = ((1.f - alpha) * radiusA + (1.f - beta) * radiusB) * yAxis; + glm::vec3 expectedPenetration = ((1.0f - alpha) * radiusA + (1.0f - beta) * radiusB) * yAxis; float inaccuracy = glm::length(collision->_penetration - expectedPenetration); if (fabs(inaccuracy) > EPSILON) { std::cout << __FILE__ << ":" << __LINE__ << " ERROR: bad penetration: expected = " << expectedPenetration - << " actual = " << collision->_penetration - << std::endl; + << " actual = " << collision->_penetration; } // contactPoint is on surface of sphereA @@ -401,8 +388,7 @@ void ShapeColliderTests::sphereTouchesCapsule() { if (fabs(inaccuracy) > EPSILON) { std::cout << __FILE__ << ":" << __LINE__ << " ERROR: bad contactPoint: expected = " << expectedContactPoint - << " actual = " << collision->_contactPoint - << std::endl; + << " actual = " << collision->_contactPoint; } // capsuleB collides with sphereA @@ -417,13 +403,12 @@ void ShapeColliderTests::sphereTouchesCapsule() { // penetration points from sphereA into capsuleB collision = collisions.getCollision(numCollisions - 1); - expectedPenetration = - ((1.f - alpha) * radiusA + (1.f - beta) * radiusB) * yAxis; + expectedPenetration = - ((1.0f - alpha) * radiusA + (1.0f - beta) * radiusB) * yAxis; inaccuracy = glm::length(collision->_penetration - expectedPenetration); if (fabs(inaccuracy) > EPSILON) { std::cout << __FILE__ << ":" << __LINE__ << " ERROR: bad penetration: expected = " << expectedPenetration - << " actual = " << collision->_penetration - << std::endl; + << " actual = " << collision->_penetration; } // contactPoint is on surface of capsuleB @@ -434,8 +419,7 @@ void ShapeColliderTests::sphereTouchesCapsule() { if (fabs(inaccuracy) > EPSILON) { std::cout << __FILE__ << ":" << __LINE__ << " ERROR: bad contactPoint: expected = " << expectedContactPoint - << " actual = " << collision->_contactPoint - << std::endl; + << " actual = " << collision->_contactPoint; } } if (collisions.size() != numCollisions) { @@ -447,10 +431,10 @@ void ShapeColliderTests::sphereTouchesCapsule() { void ShapeColliderTests::capsuleMissesCapsule() { // non-overlapping capsules - float radiusA = 2.f; - float halfHeightA = 3.f; - float radiusB = 3.f; - float halfHeightB = 4.f; + float radiusA = 2.0f; + float halfHeightA = 3.0f; + float radiusB = 3.0f; + float halfHeightB = 4.0f; float totalRadius = radiusA + radiusB; float totalHalfLength = totalRadius + halfHeightA + halfHeightB; @@ -516,10 +500,10 @@ void ShapeColliderTests::capsuleMissesCapsule() { void ShapeColliderTests::capsuleTouchesCapsule() { // overlapping capsules - float radiusA = 2.f; - float halfHeightA = 3.f; - float radiusB = 3.f; - float halfHeightB = 4.f; + float radiusA = 2.0f; + float halfHeightA = 3.0f; + float radiusB = 3.0f; + float halfHeightB = 4.0f; float totalRadius = radiusA + radiusB; float totalHalfLength = totalRadius + halfHeightA + halfHeightB; @@ -617,8 +601,7 @@ void ShapeColliderTests::capsuleTouchesCapsule() { if (fabs(inaccuracy) > EPSILON) { std::cout << __FILE__ << ":" << __LINE__ << " ERROR: bad penetration: expected = " << expectedPenetration - << " actual = " << collision->_penetration - << std::endl; + << " actual = " << collision->_penetration; } glm::vec3 expectedContactPoint = capsuleA.getPosition() + radiusA * xAxis; @@ -626,8 +609,7 @@ void ShapeColliderTests::capsuleTouchesCapsule() { if (fabs(inaccuracy) > EPSILON) { std::cout << __FILE__ << ":" << __LINE__ << " ERROR: bad contactPoint: expected = " << expectedContactPoint - << " actual = " << collision->_contactPoint - << std::endl; + << " actual = " << collision->_contactPoint; } // capsuleB vs capsuleA @@ -706,7 +688,7 @@ void ShapeColliderTests::sphereTouchesAACube() { float cubeSide = 2.0f; float sphereRadius = 1.0f; - glm::vec3 sphereCenter(0.f); + glm::vec3 sphereCenter(0.0f); SphereShape sphere(sphereRadius, sphereCenter); float sphereOffset = (0.5f * cubeSide + sphereRadius - 0.25f); From c5f1a8abd67228477dc90a361f55f47b542d23c9 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 23 Apr 2014 13:37:13 -0700 Subject: [PATCH 35/35] formatting --- libraries/octree/src/Octree.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/libraries/octree/src/Octree.cpp b/libraries/octree/src/Octree.cpp index 06db337b70..ebfb954bd8 100644 --- a/libraries/octree/src/Octree.cpp +++ b/libraries/octree/src/Octree.cpp @@ -759,9 +759,7 @@ bool Octree::findCapsulePenetration(const glm::vec3& start, const glm::vec3& end bool Octree::findShapeCollisions(const Shape* shape, CollisionList& collisions, Octree::lockType lockType) { - ShapeArgs args = { shape, - collisions, - false }; + ShapeArgs args = { shape, collisions, false }; bool gotLock = false; if (lockType == Octree::Lock) {