Showing the changes to interface/src/avatar/SkeletonModel.cpp (1 of 181 files). Show all
Unified · Split
| @@ -12,9 +12,7 @@ · 11 unmodified lines | |||
| 12 | #include <glm/gtx/transform.hpp> | 12 | #include <glm/gtx/transform.hpp> |
| 13 | #include <QMultiMap> | 13 | #include <QMultiMap> |
| 14 | 14 | ||
| 15 | #include <CapsuleShape.h> | ||
| 16 | #include <DeferredLightingEffect.h> | 15 | #include <DeferredLightingEffect.h> |
| 17 | #include <SphereShape.h> | ||
| 18 | 16 | ||
| 19 | #include "Application.h" | 17 | #include "Application.h" |
| 20 | #include "Avatar.h" | 18 | #include "Avatar.h" |
| @@ -24,29 +22,47 @@ · 3 unmodified lines | |||
| 24 | #include "Util.h" | 22 | #include "Util.h" |
| 25 | #include "InterfaceLogging.h" | 23 | #include "InterfaceLogging.h" |
| 26 | 24 | ||
| 27 | SkeletonModel::SkeletonModel(Avatar* owningAvatar, QObject* parent) : | 25 | SkeletonModel::SkeletonModel(Avatar* owningAvatar, QObject* parent, RigPointer rig) : |
| 28 | Model(parent), | 26 | Model(rig, parent), |
| 29 | _triangleFanID(DependencyManager::get<GeometryCache>()->allocateID()), | 27 | _triangleFanID(DependencyManager::get<GeometryCache>()->allocateID()), |
| 30 | _owningAvatar(owningAvatar), | 28 | _owningAvatar(owningAvatar), |
| 31 | _boundingShape(), | 29 | _boundingCapsuleLocalOffset(0.0f), |
| 32 | _boundingShapeLocalOffset(0.0f), | 30 | _boundingCapsuleRadius(0.0f), |
| 31 | _boundingCapsuleHeight(0.0f), | ||
| 33 | _defaultEyeModelPosition(glm::vec3(0.0f, 0.0f, 0.0f)), | 32 | _defaultEyeModelPosition(glm::vec3(0.0f, 0.0f, 0.0f)), |
| 34 | _headClipDistance(DEFAULT_NEAR_CLIP), | 33 | _headClipDistance(DEFAULT_NEAR_CLIP) |
| 35 | _isFirstPerson(false) | ||
| 36 | { | 34 | { |
| 35 | assert(_rig); | ||
| 37 | assert(_owningAvatar); | 36 | assert(_owningAvatar); |
| 38 | _enableShapes = true; | ||
| 39 | } | 37 | } |
| 40 | 38 | ||
| 41 | SkeletonModel::~SkeletonModel() { | 39 | SkeletonModel::~SkeletonModel() { |
| 42 | } | 40 | } |
| 43 | 41 | ||
| 44 | void SkeletonModel::initJointStates(QVector<JointState> states) { | 42 | void SkeletonModel::initJointStates(QVector<JointState> states) { |
| 45 | Model::initJointStates(states); | 43 | const FBXGeometry& geometry = _geometry->getFBXGeometry(); |
| 44 | glm::mat4 parentTransform = glm::scale(_scale) * glm::translate(_offset) * geometry.offset; | ||
| 45 | |||
| 46 | int rootJointIndex = geometry.rootJointIndex; | ||
| 47 | int leftHandJointIndex = geometry.leftHandJointIndex; | ||
| 48 | int leftElbowJointIndex = leftHandJointIndex >= 0 ? geometry.joints.at(leftHandJointIndex).parentIndex : -1; | ||
| 49 | int leftShoulderJointIndex = leftElbowJointIndex >= 0 ? geometry.joints.at(leftElbowJointIndex).parentIndex : -1; | ||
| 50 | int rightHandJointIndex = geometry.rightHandJointIndex; | ||
| 51 | int rightElbowJointIndex = rightHandJointIndex >= 0 ? geometry.joints.at(rightHandJointIndex).parentIndex : -1; | ||
| 52 | int rightShoulderJointIndex = rightElbowJointIndex >= 0 ? geometry.joints.at(rightElbowJointIndex).parentIndex : -1; | ||
| 53 | |||
| 54 | _boundingRadius = _rig->initJointStates(states, parentTransform, | ||
| 55 | rootJointIndex, | ||
| 56 | leftHandJointIndex, | ||
| 57 | leftElbowJointIndex, | ||
| 58 | leftShoulderJointIndex, | ||
| 59 | rightHandJointIndex, | ||
| 60 | rightElbowJointIndex, | ||
| 61 | rightShoulderJointIndex); | ||
| 46 | 62 | ||
| 47 | // Determine the default eye position for avatar scale = 1.0 | 63 | // Determine the default eye position for avatar scale = 1.0 |
| 48 | int headJointIndex = _geometry->getFBXGeometry().headJointIndex; | 64 | int headJointIndex = _geometry->getFBXGeometry().headJointIndex; |
| 49 | if (0 <= headJointIndex && headJointIndex < _jointStates.size()) { | 65 | if (0 <= headJointIndex && headJointIndex < _rig->getJointStateCount()) { |
| 50 | 66 | ||
| 51 | glm::vec3 leftEyePosition, rightEyePosition; | 67 | glm::vec3 leftEyePosition, rightEyePosition; |
| 52 | getEyeModelPositions(leftEyePosition, rightEyePosition); | 68 | getEyeModelPositions(leftEyePosition, rightEyePosition); |
| @@ -66,14 +82,11 @@ void SkeletonModel::initJointStates(QVector<JointState> states) { · 13 unmodified lines | |||
| 66 | // the SkeletonModel override of updateJointState() will clear the translation part | 82 | // the SkeletonModel override of updateJointState() will clear the translation part |
| 67 | // of its root joint and we need that done before we try to build shapes hence we | 83 | // of its root joint and we need that done before we try to build shapes hence we |
| 68 | // recompute all joint transforms at this time. | 84 | // recompute all joint transforms at this time. |
| 69 | for (int i = 0; i < _jointStates.size(); i++) { | 85 | for (int i = 0; i < _rig->getJointStateCount(); i++) { |
| 70 | updateJointState(i); | 86 | _rig->updateJointState(i, parentTransform); |
| 71 | } | 87 | } |
| 72 | 88 | ||
| 73 | clearShapes(); | 89 | buildShapes(); |
| 74 | if (_enableShapes) { | ||
| 75 | buildShapes(); | ||
| 76 | } | ||
| 77 | 90 | ||
| 78 | Extents meshExtents = getMeshExtents(); | 91 | Extents meshExtents = getMeshExtents(); |
| 79 | _headClipDistance = -(meshExtents.minimum.z / _scale.z - _defaultEyeModelPosition.z); | 92 | _headClipDistance = -(meshExtents.minimum.z / _scale.z - _defaultEyeModelPosition.z); |
| @@ -84,7 +97,31 @@ void SkeletonModel::initJointStates(QVector<JointState> states) { · 4 unmodified lines | |||
| 84 | } | 97 | } |
| 85 | 98 | ||
| 86 | const float PALM_PRIORITY = DEFAULT_PRIORITY; | 99 | const float PALM_PRIORITY = DEFAULT_PRIORITY; |
| 87 | const float LEAN_PRIORITY = DEFAULT_PRIORITY; | 100 | |
| 101 | void SkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) { | ||
| 102 | if (_owningAvatar->isMyAvatar()) { | ||
| 103 | _rig->computeMotionAnimationState(deltaTime, _owningAvatar->getPosition(), _owningAvatar->getVelocity(), _owningAvatar->getOrientation()); | ||
| 104 | } | ||
| 105 | Model::updateRig(deltaTime, parentTransform); | ||
| 106 | if (_owningAvatar->isMyAvatar()) { | ||
| 107 | const FBXGeometry& geometry = _geometry->getFBXGeometry(); | ||
| 108 | |||
| 109 | Rig::HeadParameters params; | ||
| 110 | params.leanSideways = _owningAvatar->getHead()->getFinalLeanSideways(); | ||
| 111 | params.leanForward = _owningAvatar->getHead()->getFinalLeanSideways(); | ||
| 112 | params.torsoTwist = _owningAvatar->getHead()->getTorsoTwist(); | ||
| 113 | params.localHeadOrientation = _owningAvatar->getHead()->getFinalOrientationInLocalFrame(); | ||
| 114 | params.worldHeadOrientation = _owningAvatar->getHead()->getFinalOrientationInWorldFrame(); | ||
| 115 | params.eyeLookAt = _owningAvatar->getHead()->getCorrectedLookAtPosition(); | ||
| 116 | params.eyeSaccade = _owningAvatar->getHead()->getSaccade(); | ||
| 117 | params.leanJointIndex = geometry.leanJointIndex; | ||
| 118 | params.neckJointIndex = geometry.neckJointIndex; | ||
| 119 | params.leftEyeJointIndex = geometry.leftEyeJointIndex; | ||
| 120 | params.rightEyeJointIndex = geometry.rightEyeJointIndex; | ||
| 121 | |||
| 122 | _rig->updateFromHeadParameters(params); | ||
| 123 | } | ||
| 124 | } | ||
| 88 | 125 | ||
| 89 | void SkeletonModel::simulate(float deltaTime, bool fullUpdate) { | 126 | void SkeletonModel::simulate(float deltaTime, bool fullUpdate) { |
| 90 | setTranslation(_owningAvatar->getSkeletonPosition()); | 127 | setTranslation(_owningAvatar->getSkeletonPosition()); |
| @@ -141,49 +178,6 @@ void SkeletonModel::simulate(float deltaTime, bool fullUpdate) { · 50 unmodified lines | |||
| 141 | restoreRightHandPosition(HAND_RESTORATION_RATE, PALM_PRIORITY); | 178 | restoreRightHandPosition(HAND_RESTORATION_RATE, PALM_PRIORITY); |
| 142 | } | 179 | } |
| 143 | } | 180 | } |
| 144 | |||
| 145 | if (_isFirstPerson) { | ||
| 146 | cauterizeHead(); | ||
| 147 | updateClusterMatrices(); | ||
| 148 | } | ||
| 149 | |||
| 150 | _boundingShape.setTranslation(_translation + _rotation * _boundingShapeLocalOffset); | ||
| 151 | _boundingShape.setRotation(_rotation); | ||
| 152 | } | ||
| 153 | |||
| 154 | void SkeletonModel::getHandShapes(int jointIndex, QVector<const Shape*>& shapes) const { | ||
| 155 | if (jointIndex < 0 || jointIndex >= int(_shapes.size())) { | ||
| 156 | return; | ||
| 157 | } | ||
| 158 | if (jointIndex == getLeftHandJointIndex() | ||
| 159 | || jointIndex == getRightHandJointIndex()) { | ||
| 160 | // get all shapes that have this hand as an ancestor in the skeleton heirarchy | ||
| 161 | const FBXGeometry& geometry = _geometry->getFBXGeometry(); | ||
| 162 | for (int i = 0; i < _jointStates.size(); i++) { | ||
| 163 | const FBXJoint& joint = geometry.joints[i]; | ||
| 164 | int parentIndex = joint.parentIndex; | ||
| 165 | Shape* shape = _shapes[i]; | ||
| 166 | if (i == jointIndex) { | ||
| 167 | // this shape is the hand | ||
| 168 | if (shape) { | ||
| 169 | shapes.push_back(shape); | ||
| 170 | } | ||
| 171 | if (parentIndex != -1 && _shapes[parentIndex]) { | ||
| 172 | // also add the forearm | ||
| 173 | shapes.push_back(_shapes[parentIndex]); | ||
| 174 | } | ||
| 175 | } else if (shape) { | ||
| 176 | while (parentIndex != -1) { | ||
| 177 | if (parentIndex == jointIndex) { | ||
| 178 | // this shape is a child of the hand | ||
| 179 | shapes.push_back(shape); | ||
| 180 | break; | ||
| 181 | } | ||
| 182 | parentIndex = geometry.joints[parentIndex].parentIndex; | ||
| 183 | } | ||
| 184 | } | ||
| 185 | } | ||
| 186 | } | ||
| 187 | } | 181 | } |
| 188 | 182 | ||
| 189 | void SkeletonModel::renderIKConstraints(gpu::Batch& batch) { | 183 | void SkeletonModel::renderIKConstraints(gpu::Batch& batch) { |
| @@ -202,7 +196,7 @@ bool operator<(const IndexValue& firstIndex, const IndexValue& secondIndex) { · 12 unmodified lines | |||
| 202 | } | 196 | } |
| 203 | 197 | ||
| 204 | void SkeletonModel::applyHandPosition(int jointIndex, const glm::vec3& position) { | 198 | void SkeletonModel::applyHandPosition(int jointIndex, const glm::vec3& position) { |
| 205 | if (jointIndex == -1 || jointIndex >= _jointStates.size()) { | 199 | if (jointIndex == -1 || jointIndex >= _rig->getJointStateCount()) { |
| 206 | return; | 200 | return; |
| 207 | } | 201 | } |
| 208 | // NOTE: 'position' is in model-frame | 202 | // NOTE: 'position' is in model-frame |
| @@ -217,16 +211,20 @@ void SkeletonModel::applyHandPosition(int jointIndex, const glm::vec3& position) · 8 unmodified lines | |||
| 217 | if (forearmLength < EPSILON) { | 211 | if (forearmLength < EPSILON) { |
| 218 | return; | 212 | return; |
| 219 | } | 213 | } |
| 220 | JointState& state = _jointStates[jointIndex]; | 214 | glm::quat handRotation; |
| 221 | glm::quat handRotation = state.getRotation(); | 215 | if (!_rig->getJointStateRotation(jointIndex, handRotation)) { |
| 216 | return; | ||
| 217 | } | ||
| 222 | 218 | ||
| 223 | // align hand with forearm | 219 | // align hand with forearm |
| 224 | float sign = (jointIndex == geometry.rightHandJointIndex) ? 1.0f : -1.0f; | 220 | float sign = (jointIndex == geometry.rightHandJointIndex) ? 1.0f : -1.0f; |
| 225 | state.applyRotationDelta(rotationBetween(handRotation * glm::vec3(-sign, 0.0f, 0.0f), forearmVector), true, PALM_PRIORITY); | 221 | _rig->applyJointRotationDelta(jointIndex, |
| 222 | rotationBetween(handRotation * glm::vec3(-sign, 0.0f, 0.0f), forearmVector), | ||
| 223 | true, PALM_PRIORITY); | ||
| 226 | } | 224 | } |
| 227 | 225 | ||
| 228 | void SkeletonModel::applyPalmData(int jointIndex, PalmData& palm) { | 226 | void SkeletonModel::applyPalmData(int jointIndex, PalmData& palm) { |
| 229 | if (jointIndex == -1 || jointIndex >= _jointStates.size()) { | 227 | if (jointIndex == -1 || jointIndex >= _rig->getJointStateCount()) { |
| 230 | return; | 228 | return; |
| 231 | } | 229 | } |
| 232 | const FBXGeometry& geometry = _geometry->getFBXGeometry(); | 230 | const FBXGeometry& geometry = _geometry->getFBXGeometry(); |
| @@ -246,85 +244,36 @@ void SkeletonModel::applyPalmData(int jointIndex, PalmData& palm) { · 13 unmodified lines | |||
| 246 | palmRotation = rotationBetween(palmRotation * glm::vec3(-sign, 0.0f, 0.0f), fingerDirection) * palmRotation; | 244 | palmRotation = rotationBetween(palmRotation * glm::vec3(-sign, 0.0f, 0.0f), fingerDirection) * palmRotation; |
| 247 | 245 | ||
| 248 | if (Menu::getInstance()->isOptionChecked(MenuOption::AlternateIK)) { | 246 | if (Menu::getInstance()->isOptionChecked(MenuOption::AlternateIK)) { |
| 249 | setHandPosition(jointIndex, palmPosition, palmRotation); | 247 | _rig->setHandPosition(jointIndex, palmPosition, palmRotation, extractUniformScale(_scale), PALM_PRIORITY); |
| 250 | } else if (Menu::getInstance()->isOptionChecked(MenuOption::AlignForearmsWithWrists)) { | 248 | } else if (Menu::getInstance()->isOptionChecked(MenuOption::AlignForearmsWithWrists)) { |
| 251 | float forearmLength = geometry.joints.at(jointIndex).distanceToParent * extractUniformScale(_scale); | 249 | float forearmLength = geometry.joints.at(jointIndex).distanceToParent * extractUniformScale(_scale); |
| 252 | glm::vec3 forearm = palmRotation * glm::vec3(sign * forearmLength, 0.0f, 0.0f); | 250 | glm::vec3 forearm = palmRotation * glm::vec3(sign * forearmLength, 0.0f, 0.0f); |
| 253 | setJointPosition(parentJointIndex, palmPosition + forearm, | 251 | setJointPosition(parentJointIndex, palmPosition + forearm, |
| 254 | glm::quat(), false, -1, false, glm::vec3(0.0f, -1.0f, 0.0f), PALM_PRIORITY); | 252 | glm::quat(), false, -1, false, glm::vec3(0.0f, -1.0f, 0.0f), PALM_PRIORITY); |
| 255 | JointState& parentState = _jointStates[parentJointIndex]; | 253 | _rig->setJointRotationInBindFrame(parentJointIndex, palmRotation, PALM_PRIORITY); |
| 256 | parentState.setRotationInBindFrame(palmRotation, PALM_PRIORITY); | ||
| 257 | // lock hand to forearm by slamming its rotation (in parent-frame) to identity | 254 | // lock hand to forearm by slamming its rotation (in parent-frame) to identity |
| 258 | _jointStates[jointIndex].setRotationInConstrainedFrame(glm::quat(), PALM_PRIORITY); | 255 | _rig->setJointRotationInConstrainedFrame(jointIndex, glm::quat(), PALM_PRIORITY); |
| 259 | } else { | 256 | } else { |
| 260 | inverseKinematics(jointIndex, palmPosition, palmRotation, PALM_PRIORITY); | 257 | inverseKinematics(jointIndex, palmPosition, palmRotation, PALM_PRIORITY); |
| 261 | } | 258 | } |
| 262 | } | 259 | } |
| 263 | 260 | ||
| 264 | void SkeletonModel::updateJointState(int index) { | ||
| 265 | if (index < 0 && index >= _jointStates.size()) { | ||
| 266 | return; // bail | ||
| 267 | } | ||
| 268 | JointState& state = _jointStates[index]; | ||
| 269 | const FBXJoint& joint = state.getFBXJoint(); | ||
| 270 | if (joint.parentIndex >= 0 && joint.parentIndex < _jointStates.size()) { | ||
| 271 | const JointState& parentState = _jointStates.at(joint.parentIndex); | ||
| 272 | const FBXGeometry& geometry = _geometry->getFBXGeometry(); | ||
| 273 | if (index == geometry.leanJointIndex) { | ||
| 274 | maybeUpdateLeanRotation(parentState, state); | ||
| 275 | |||
| 276 | } else if (index == geometry.neckJointIndex) { | ||
| 277 | maybeUpdateNeckRotation(parentState, joint, state); | ||
| 278 | |||
| 279 | } else if (index == geometry.leftEyeJointIndex || index == geometry.rightEyeJointIndex) { | ||
| 280 | maybeUpdateEyeRotation(parentState, joint, state); | ||
| 281 | } | ||
| 282 | } | ||
| 283 | |||
| 284 | Model::updateJointState(index); | ||
| 285 | |||
| 286 | if (index == _geometry->getFBXGeometry().rootJointIndex) { | ||
| 287 | state.clearTransformTranslation(); | ||
| 288 | } | ||
| 289 | } | ||
| 290 | |||
| 291 | void SkeletonModel::maybeUpdateLeanRotation(const JointState& parentState, JointState& state) { | ||
| 292 | if (!_owningAvatar->isMyAvatar()) { | ||
| 293 | return; | ||
| 294 | } | ||
| 295 | // get the rotation axes in joint space and use them to adjust the rotation | ||
| 296 | glm::vec3 xAxis(1.0f, 0.0f, 0.0f); | ||
| 297 | glm::vec3 yAxis(0.0f, 1.0f, 0.0f); | ||
| 298 | glm::vec3 zAxis(0.0f, 0.0f, 1.0f); | ||
| 299 | glm::quat inverse = glm::inverse(parentState.getRotation() * state.getDefaultRotationInParentFrame()); | ||
| 300 | state.setRotationInConstrainedFrame( | ||
| 301 | glm::angleAxis(- RADIANS_PER_DEGREE * _owningAvatar->getHead()->getFinalLeanSideways(), inverse * zAxis) | ||
| 302 | * glm::angleAxis(- RADIANS_PER_DEGREE * _owningAvatar->getHead()->getFinalLeanForward(), inverse * xAxis) | ||
| 303 | * glm::angleAxis(RADIANS_PER_DEGREE * _owningAvatar->getHead()->getTorsoTwist(), inverse * yAxis) | ||
| 304 | * state.getFBXJoint().rotation, LEAN_PRIORITY); | ||
| 305 | } | ||
| 306 | |||
| 307 | void SkeletonModel::maybeUpdateNeckRotation(const JointState& parentState, const FBXJoint& joint, JointState& state) { | ||
| 308 | _owningAvatar->getHead()->getFaceModel().maybeUpdateNeckRotation(parentState, joint, state); | ||
| 309 | } | ||
| 310 | |||
| 311 | void SkeletonModel::maybeUpdateEyeRotation(const JointState& parentState, const FBXJoint& joint, JointState& state) { | ||
| 312 | _owningAvatar->getHead()->getFaceModel().maybeUpdateEyeRotation(this, parentState, joint, state); | ||
| 313 | } | ||
| 314 | |||
| 315 | void SkeletonModel::renderJointConstraints(gpu::Batch& batch, int jointIndex) { | 261 | void SkeletonModel::renderJointConstraints(gpu::Batch& batch, int jointIndex) { |
| 316 | if (jointIndex == -1 || jointIndex >= _jointStates.size()) { | 262 | if (jointIndex == -1 || jointIndex >= _rig->getJointStateCount()) { |
| 317 | return; | 263 | return; |
| 318 | } | 264 | } |
| 319 | const FBXGeometry& geometry = _geometry->getFBXGeometry(); | 265 | const FBXGeometry& geometry = _geometry->getFBXGeometry(); |
| 320 | const float BASE_DIRECTION_SIZE = 0.3f; | 266 | const float BASE_DIRECTION_SIZE = 0.3f; |
| 321 | float directionSize = BASE_DIRECTION_SIZE * extractUniformScale(_scale); | 267 | float directionSize = BASE_DIRECTION_SIZE * extractUniformScale(_scale); |
| 322 | batch._glLineWidth(3.0f); | 268 | // FIXME: THe line width of 3.0f is not supported anymore, we ll need a workaround |
| 269 | |||
| 323 | do { | 270 | do { |
| 324 | const FBXJoint& joint = geometry.joints.at(jointIndex); | 271 | const FBXJoint& joint = geometry.joints.at(jointIndex); |
| 325 | const JointState& jointState = _jointStates.at(jointIndex); | 272 | const JointState& jointState = _rig->getJointState(jointIndex); |
| 326 | glm::vec3 position = _rotation * jointState.getPosition() + _translation; | 273 | glm::vec3 position = _rotation * jointState.getPosition() + _translation; |
| 327 | glm::quat parentRotation = (joint.parentIndex == -1) ? _rotation : _rotation * _jointStates.at(joint.parentIndex).getRotation(); | 274 | glm::quat parentRotation = (joint.parentIndex == -1) ? |
| 275 | _rotation : | ||
| 276 | _rotation * _rig->getJointState(joint.parentIndex).getRotation(); | ||
| 328 | float fanScale = directionSize * 0.75f; | 277 | float fanScale = directionSize * 0.75f; |
| 329 | 278 | ||
| 330 | Transform transform = Transform(); | 279 | Transform transform = Transform(); |
| @@ -401,72 +350,6 @@ void SkeletonModel::renderOrientationDirections(gpu::Batch& batch, int jointInde · 70 unmodified lines | |||
| 401 | geometryCache->renderLine(batch, position, pFront, blue, jointLineIDs._front); | 350 | geometryCache->renderLine(batch, position, pFront, blue, jointLineIDs._front); |
| 402 | } | 351 | } |
| 403 | 352 | ||
| 404 | |||
| 405 | |||
| 406 | void SkeletonModel::setHandPosition(int jointIndex, const glm::vec3& position, const glm::quat& rotation) { | ||
| 407 | // this algorithm is from sample code from sixense | ||
| 408 | const FBXGeometry& geometry = _geometry->getFBXGeometry(); | ||
| 409 | int elbowJointIndex = geometry.joints.at(jointIndex).parentIndex; | ||
| 410 | if (elbowJointIndex == -1) { | ||
| 411 | return; | ||
| 412 | } | ||
| 413 | int shoulderJointIndex = geometry.joints.at(elbowJointIndex).parentIndex; | ||
| 414 | glm::vec3 shoulderPosition; | ||
| 415 | if (!getJointPosition(shoulderJointIndex, shoulderPosition)) { | ||
| 416 | return; | ||
| 417 | } | ||
| 418 | // precomputed lengths | ||
| 419 | float scale = extractUniformScale(_scale); | ||
| 420 | float upperArmLength = geometry.joints.at(elbowJointIndex).distanceToParent * scale; | ||
| 421 | float lowerArmLength = geometry.joints.at(jointIndex).distanceToParent * scale; | ||
| 422 | |||
| 423 | // first set wrist position | ||
| 424 | glm::vec3 wristPosition = position; | ||
| 425 | |||
| 426 | glm::vec3 shoulderToWrist = wristPosition - shoulderPosition; | ||
| 427 | float distanceToWrist = glm::length(shoulderToWrist); | ||
| 428 | |||
| 429 | // prevent gimbal lock | ||
| 430 | if (distanceToWrist > upperArmLength + lowerArmLength - EPSILON) { | ||
| 431 | distanceToWrist = upperArmLength + lowerArmLength - EPSILON; | ||
| 432 | shoulderToWrist = glm::normalize(shoulderToWrist) * distanceToWrist; | ||
| 433 | wristPosition = shoulderPosition + shoulderToWrist; | ||
| 434 | } | ||
| 435 | |||
| 436 | // cosine of angle from upper arm to hand vector | ||
| 437 | float cosA = (upperArmLength * upperArmLength + distanceToWrist * distanceToWrist - lowerArmLength * lowerArmLength) / | ||
| 438 | (2 * upperArmLength * distanceToWrist); | ||
| 439 | float mid = upperArmLength * cosA; | ||
| 440 | float height = sqrt(upperArmLength * upperArmLength + mid * mid - 2 * upperArmLength * mid * cosA); | ||
| 441 | |||
| 442 | // direction of the elbow | ||
| 443 | glm::vec3 handNormal = glm::cross(rotation * glm::vec3(0.0f, 1.0f, 0.0f), shoulderToWrist); // elbow rotating with wrist | ||
| 444 | glm::vec3 relaxedNormal = glm::cross(glm::vec3(0.0f, 1.0f, 0.0f), shoulderToWrist); // elbow pointing straight down | ||
| 445 | const float NORMAL_WEIGHT = 0.5f; | ||
| 446 | glm::vec3 finalNormal = glm::mix(relaxedNormal, handNormal, NORMAL_WEIGHT); | ||
| 447 | |||
| 448 | bool rightHand = (jointIndex == geometry.rightHandJointIndex); | ||
| 449 | if (rightHand ? (finalNormal.y > 0.0f) : (finalNormal.y < 0.0f)) { | ||
| 450 | finalNormal.y = 0.0f; // dont allow elbows to point inward (y is vertical axis) | ||
| 451 | } | ||
| 452 | |||
| 453 | glm::vec3 tangent = glm::normalize(glm::cross(shoulderToWrist, finalNormal)); | ||
| 454 | |||
| 455 | // ik solution | ||
| 456 | glm::vec3 elbowPosition = shoulderPosition + glm::normalize(shoulderToWrist) * mid - tangent * height; | ||
| 457 | glm::vec3 forwardVector(rightHand ? -1.0f : 1.0f, 0.0f, 0.0f); | ||
| 458 | glm::quat shoulderRotation = rotationBetween(forwardVector, elbowPosition - shoulderPosition); | ||
| 459 | |||
| 460 | JointState& shoulderState = _jointStates[shoulderJointIndex]; | ||
| 461 | shoulderState.setRotationInBindFrame(shoulderRotation, PALM_PRIORITY); | ||
| 462 | |||
| 463 | JointState& elbowState = _jointStates[elbowJointIndex]; | ||
| 464 | elbowState.setRotationInBindFrame(rotationBetween(shoulderRotation * forwardVector, wristPosition - elbowPosition) * shoulderRotation, PALM_PRIORITY); | ||
| 465 | |||
| 466 | JointState& handState = _jointStates[jointIndex]; | ||
| 467 | handState.setRotationInBindFrame(rotation, PALM_PRIORITY); | ||
| 468 | } | ||
| 469 | |||
| 470 | bool SkeletonModel::getLeftHandPosition(glm::vec3& position) const { | 353 | bool SkeletonModel::getLeftHandPosition(glm::vec3& position) const { |
| 471 | return getJointPositionInWorldFrame(getLeftHandJointIndex(), position); | 354 | return getJointPositionInWorldFrame(getLeftHandJointIndex(), position); |
| 472 | } | 355 | } |
| @@ -523,7 +406,7 @@ bool SkeletonModel::getNeckParentRotationFromDefaultOrientation(glm::quat& neckP · 50 unmodified lines | |||
| 523 | glm::quat worldFrameRotation; | 406 | glm::quat worldFrameRotation; |
| 524 | bool success = getJointRotationInWorldFrame(parentIndex, worldFrameRotation); | 407 | bool success = getJointRotationInWorldFrame(parentIndex, worldFrameRotation); |
| 525 | if (success) { | 408 | if (success) { |
| 526 | neckParentRotation = worldFrameRotation * _jointStates[parentIndex].getFBXJoint().inverseDefaultRotation; | 409 | neckParentRotation = worldFrameRotation * _rig->getJointState(parentIndex).getFBXJoint().inverseDefaultRotation; |
| 527 | } | 410 | } |
| 528 | return success; | 411 | return success; |
| 529 | } | 412 | } |
| @@ -574,7 +457,7 @@ float VERY_BIG_MASS = 1.0e6f; · 44 unmodified lines | |||
| 574 | 457 | ||
| 575 | // virtual | 458 | // virtual |
| 576 | void SkeletonModel::buildShapes() { | 459 | void SkeletonModel::buildShapes() { |
| 577 | if (_geometry == NULL || _jointStates.isEmpty()) { | 460 | if (_geometry == NULL || _rig->jointStatesEmpty()) { |
| 578 | return; | 461 | return; |
| 579 | } | 462 | } |
| 580 | 463 | ||
| @@ -583,46 +466,12 @@ void SkeletonModel::buildShapes() { · 2 unmodified lines | |||
| 583 | // rootJointIndex == -1 if the avatar model has no skeleton | 466 | // rootJointIndex == -1 if the avatar model has no skeleton |
| 584 | return; | 467 | return; |
| 585 | } | 468 | } |
| 586 | |||
| 587 | float uniformScale = extractUniformScale(_scale); | ||
| 588 | const int numStates = _jointStates.size(); | ||
| 589 | for (int i = 0; i < numStates; i++) { | ||
| 590 | JointState& state = _jointStates[i]; | ||
| 591 | const FBXJoint& joint = state.getFBXJoint(); | ||
| 592 | float radius = uniformScale * joint.boneRadius; | ||
| 593 | float halfHeight = 0.5f * uniformScale * joint.distanceToParent; | ||
| 594 | Shape::Type type = joint.shapeType; | ||
| 595 | int parentIndex = joint.parentIndex; | ||
| 596 | if (parentIndex == -1 || radius < EPSILON) { | ||
| 597 | type = INVALID_SHAPE; | ||
| 598 | } else if (type == CAPSULE_SHAPE && halfHeight < EPSILON) { | ||
| 599 | // this shape is forced to be a sphere | ||
| 600 | type = SPHERE_SHAPE; | ||
| 601 | } | ||
| 602 | Shape* shape = NULL; | ||
| 603 | if (type == SPHERE_SHAPE) { | ||
| 604 | shape = new SphereShape(radius); | ||
| 605 | shape->setEntity(this); | ||
| 606 | } else if (type == CAPSULE_SHAPE) { | ||
| 607 | assert(parentIndex != -1); | ||
| 608 | shape = new CapsuleShape(radius, halfHeight); | ||
| 609 | shape->setEntity(this); | ||
| 610 | } | ||
| 611 | if (shape && parentIndex != -1) { | ||
| 612 | // always disable collisions between joint and its parent | ||
| 613 | disableCollisions(i, parentIndex); | ||
| 614 | } | ||
| 615 | _shapes.push_back(shape); | ||
| 616 | } | ||
| 617 | |||
| 618 | // This method moves the shapes to their default positions in Model frame. | ||
| 619 | computeBoundingShape(geometry); | 469 | computeBoundingShape(geometry); |
| 620 | } | 470 | } |
| 621 | 471 | ||
| 622 | void SkeletonModel::computeBoundingShape(const FBXGeometry& geometry) { | 472 | void SkeletonModel::computeBoundingShape(const FBXGeometry& geometry) { |
| 623 | // compute default joint transforms | 473 | // compute default joint transforms |
| 624 | int numStates = _jointStates.size(); | 474 | int numStates = _rig->getJointStateCount(); |
| 625 | assert(numStates == _shapes.size()); | ||
| 626 | QVector<glm::mat4> transforms; | 475 | QVector<glm::mat4> transforms; |
| 627 | transforms.fill(glm::mat4(), numStates); | 476 | transforms.fill(glm::mat4(), numStates); |
| 628 | 477 | ||
| @@ -632,190 +481,69 @@ void SkeletonModel::computeBoundingShape(const FBXGeometry& geometry) { · 3 unmodified lines | |||
| 632 | totalExtents.addPoint(glm::vec3(0.0f)); | 481 | totalExtents.addPoint(glm::vec3(0.0f)); |
| 633 | for (int i = 0; i < numStates; i++) { | 482 | for (int i = 0; i < numStates; i++) { |
| 634 | // compute the default transform of this joint | 483 | // compute the default transform of this joint |
| 635 | JointState& state = _jointStates[i]; | 484 | const JointState& state = _rig->getJointState(i); |
| 636 | const FBXJoint& joint = state.getFBXJoint(); | 485 | const FBXJoint& joint = state.getFBXJoint(); |
| 637 | int parentIndex = joint.parentIndex; | 486 | int parentIndex = joint.parentIndex; |
| 638 | if (parentIndex == -1) { | 487 | if (parentIndex == -1) { |
| 639 | transforms[i] = _jointStates[i].getTransform(); | 488 | transforms[i] = _rig->getJointTransform(i); |
| 640 | } else { | 489 | } else { |
| 641 | glm::quat modifiedRotation = joint.preRotation * joint.rotation * joint.postRotation; | 490 | glm::quat modifiedRotation = joint.preRotation * joint.rotation * joint.postRotation; |
| 642 | transforms[i] = transforms[parentIndex] * glm::translate(joint.translation) | 491 | transforms[i] = transforms[parentIndex] * glm::translate(joint.translation) |
| 643 | * joint.preTransform * glm::mat4_cast(modifiedRotation) * joint.postTransform; | 492 | * joint.preTransform * glm::mat4_cast(modifiedRotation) * joint.postTransform; |
| 644 | } | 493 | } |
| 645 | 494 | ||
| 646 | // Each joint contributes its point to the bounding box | 495 | // Each joint contributes a sphere at its position |
| 496 | glm::vec3 axis(joint.boneRadius); | ||
| 647 | glm::vec3 jointPosition = extractTranslation(transforms[i]); | 497 | glm::vec3 jointPosition = extractTranslation(transforms[i]); |
| 648 | totalExtents.addPoint(jointPosition); | 498 | totalExtents.addPoint(jointPosition + axis); |
| 649 | 499 | totalExtents.addPoint(jointPosition - axis); | |
| 650 | Shape* shape = _shapes[i]; | ||
| 651 | if (!shape) { | ||
| 652 | continue; | ||
| 653 | } | ||
| 654 | |||
| 655 | // Each joint with a shape contributes to the totalExtents: a box | ||
| 656 | // that contains the sphere centered at the end of the joint with radius of the bone. | ||
| 657 | |||
| 658 | // TODO: skip hand and arm shapes for bounding box calculation | ||
| 659 | int type = shape->getType(); | ||
| 660 | if (type == CAPSULE_SHAPE) { | ||
| 661 | // add the two furthest surface points of the capsule | ||
| 662 | CapsuleShape* capsule = static_cast<CapsuleShape*>(shape); | ||
| 663 | float radius = capsule->getRadius(); | ||
| 664 | glm::vec3 axis(radius); | ||
| 665 | Extents shapeExtents; | ||
| 666 | shapeExtents.reset(); | ||
| 667 | shapeExtents.addPoint(jointPosition + axis); | ||
| 668 | shapeExtents.addPoint(jointPosition - axis); | ||
| 669 | totalExtents.addExtents(shapeExtents); | ||
| 670 | } else if (type == SPHERE_SHAPE) { | ||
| 671 | float radius = shape->getBoundingRadius(); | ||
| 672 | glm::vec3 axis(radius); | ||
| 673 | Extents shapeExtents; | ||
| 674 | shapeExtents.reset(); | ||
| 675 | shapeExtents.addPoint(jointPosition + axis); | ||
| 676 | shapeExtents.addPoint(jointPosition - axis); | ||
| 677 | totalExtents.addExtents(shapeExtents); | ||
| 678 | } | ||
| 679 | } | 500 | } |
| 680 | 501 | ||
| 681 | // compute bounding shape parameters | 502 | // compute bounding shape parameters |
| 682 | // NOTE: we assume that the longest side of totalExtents is the yAxis... | 503 | // NOTE: we assume that the longest side of totalExtents is the yAxis... |
| 683 | glm::vec3 diagonal = totalExtents.maximum - totalExtents.minimum; | 504 | glm::vec3 diagonal = totalExtents.maximum - totalExtents.minimum; |
| 684 | // ... and assume the radius is half the RMS of the X and Z sides: | 505 | // ... and assume the radius is half the RMS of the X and Z sides: |
| 685 | float capsuleRadius = 0.5f * sqrtf(0.5f * (diagonal.x * diagonal.x + diagonal.z * diagonal.z)); | 506 | _boundingCapsuleRadius = 0.5f * sqrtf(0.5f * (diagonal.x * diagonal.x + diagonal.z * diagonal.z)); |
| 686 | _boundingShape.setRadius(capsuleRadius); | 507 | _boundingCapsuleHeight = diagonal.y - 2.0f * _boundingCapsuleRadius; |
| 687 | _boundingShape.setHalfHeight(0.5f * diagonal.y - capsuleRadius); | ||
| 688 | 508 | ||
| 689 | glm::vec3 rootPosition = _jointStates[geometry.rootJointIndex].getPosition(); | 509 | glm::vec3 rootPosition = _rig->getJointState(geometry.rootJointIndex).getPosition(); |
| 690 | _boundingShapeLocalOffset = 0.5f * (totalExtents.maximum + totalExtents.minimum) - rootPosition; | 510 | _boundingCapsuleLocalOffset = 0.5f * (totalExtents.maximum + totalExtents.minimum) - rootPosition; |
| 691 | _boundingRadius = 0.5f * glm::length(diagonal); | 511 | _boundingRadius = 0.5f * glm::length(diagonal); |
| 692 | } | 512 | } |
| 693 | 513 | ||
| 694 | void SkeletonModel::resetShapePositionsToDefaultPose() { | ||
| 695 | // DEBUG method. | ||
| 696 | // Moves shapes to the joint default locations for debug visibility into | ||
| 697 | // how the bounding shape is computed. | ||
| 698 | |||
| 699 | if (!_geometry || _shapes.isEmpty()) { | ||
| 700 | // geometry or joints have not yet been created | ||
| 701 | return; | ||
| 702 | } | ||
| 703 | |||
| 704 | const FBXGeometry& geometry = _geometry->getFBXGeometry(); | ||
| 705 | if (geometry.joints.isEmpty()) { | ||
| 706 | return; | ||
| 707 | } | ||
| 708 | |||
| 709 | // The shapes are moved to their default positions in computeBoundingShape(). | ||
| 710 | computeBoundingShape(geometry); | ||
| 711 | |||
| 712 | // Then we move them into world frame for rendering at the Model's location. | ||
| 713 | for (int i = 0; i < _shapes.size(); i++) { | ||
| 714 | Shape* shape = _shapes[i]; | ||
| 715 | if (shape) { | ||
| 716 | shape->setTranslation(_translation + _rotation * shape->getTranslation()); | ||
| 717 | shape->setRotation(_rotation * shape->getRotation()); | ||
| 718 | } | ||
| 719 | } | ||
| 720 | _boundingShape.setTranslation(_translation + _rotation * _boundingShapeLocalOffset); | ||
| 721 | _boundingShape.setRotation(_rotation); | ||
| 722 | } | ||
| 723 | |||
| 724 | void SkeletonModel::renderBoundingCollisionShapes(gpu::Batch& batch, float alpha) { | 514 | void SkeletonModel::renderBoundingCollisionShapes(gpu::Batch& batch, float alpha) { |
| 725 | const int BALL_SUBDIVISIONS = 10; | 515 | const int BALL_SUBDIVISIONS = 10; |
| 726 | #if 0 | ||
| 727 | if (_shapes.isEmpty()) { | ||
| 728 | // the bounding shape has not been properly computed | ||
| 729 | // so no need to render it | ||
| 730 | return; | ||
| 731 | } | ||
| 732 | 516 | ||
| 733 | auto geometryCache = DependencyManager::get<GeometryCache>(); | 517 | auto geometryCache = DependencyManager::get<GeometryCache>(); |
| 734 | auto deferredLighting = DependencyManager::get<DeferredLightingEffect>(); | 518 | auto deferredLighting = DependencyManager::get<DeferredLightingEffect>(); |
| 735 | Transform transform; // = Transform(); | 519 | Transform transform; // = Transform(); |
| 736 | 520 | ||
| 737 | // draw a blue sphere at the capsule end point | 521 | // draw a blue sphere at the capsule top point |
| 738 | glm::vec3 endPoint; | 522 | glm::vec3 topPoint = _translation + _boundingCapsuleLocalOffset + (0.5f * _boundingCapsuleHeight) * glm::vec3(0.0f, 1.0f, 0.0f); |
| 739 | _boundingShape.getEndPoint(endPoint); | 523 | transform.setTranslation(topPoint); |
| 740 | endPoint = endPoint + _translation; | ||
| 741 | transform.setTranslation(endPoint); | ||
| 742 | batch.setModelTransform(transform); | 524 | batch.setModelTransform(transform); |
| 743 | deferredLighting->bindSimpleProgram(batch); | 525 | deferredLighting->bindSimpleProgram(batch); |
| 744 | geometryCache->renderSphere(batch, _boundingShape.getRadius(), BALL_SUBDIVISIONS, BALL_SUBDIVISIONS, | 526 | geometryCache->renderSphere(batch, _boundingCapsuleRadius, BALL_SUBDIVISIONS, BALL_SUBDIVISIONS, |
| 745 | glm::vec4(0.6f, 0.6f, 0.8f, alpha)); | 527 | glm::vec4(0.6f, 0.6f, 0.8f, alpha)); |
| 746 | 528 | ||
| 747 | // draw a yellow sphere at the capsule start point | 529 | // draw a yellow sphere at the capsule bottom point |
| 748 | glm::vec3 startPoint; | 530 | glm::vec3 bottomPoint = topPoint - glm::vec3(0.0f, -_boundingCapsuleHeight, 0.0f); |
| 749 | _boundingShape.getStartPoint(startPoint); | 531 | glm::vec3 axis = topPoint - bottomPoint; |
| 750 | startPoint = startPoint + _translation; | 532 | transform.setTranslation(bottomPoint); |
| 751 | glm::vec3 axis = endPoint - startPoint; | ||
| 752 | transform.setTranslation(startPoint); | ||
| 753 | batch.setModelTransform(transform); | 533 | batch.setModelTransform(transform); |
| 754 | deferredLighting->bindSimpleProgram(batch); | 534 | deferredLighting->bindSimpleProgram(batch); |
| 755 | geometryCache->renderSphere(batch, _boundingShape.getRadius(), BALL_SUBDIVISIONS, BALL_SUBDIVISIONS, | 535 | geometryCache->renderSphere(batch, _boundingCapsuleRadius, BALL_SUBDIVISIONS, BALL_SUBDIVISIONS, |
| 756 | glm::vec4(0.8f, 0.8f, 0.6f, alpha)); | 536 | glm::vec4(0.8f, 0.8f, 0.6f, alpha)); |
| 757 | 537 | ||
| 758 | // draw a green cylinder between the two points | 538 | // draw a green cylinder between the two points |
| 759 | glm::vec3 origin(0.0f); | 539 | glm::vec3 origin(0.0f); |
| 760 | Avatar::renderJointConnectingCone(batch, origin, axis, _boundingShape.getRadius(), _boundingShape.getRadius(), | 540 | Avatar::renderJointConnectingCone(batch, origin, axis, _boundingCapsuleRadius, _boundingCapsuleRadius, |
| 761 | glm::vec4(0.6f, 0.8f, 0.6f, alpha)); | 541 | glm::vec4(0.6f, 0.8f, 0.6f, alpha)); |
| 762 | #endif | ||
| 763 | } | 542 | } |
| 764 | 543 | ||
| 765 | bool SkeletonModel::hasSkeleton() { | 544 | bool SkeletonModel::hasSkeleton() { |
| 766 | return isActive() ? _geometry->getFBXGeometry().rootJointIndex != -1 : false; | 545 | return isActive() ? _geometry->getFBXGeometry().rootJointIndex != -1 : false; |
| 767 | } | 546 | } |
| 768 | 547 | ||
| 769 | void SkeletonModel::initHeadBones() { | ||
| 770 | _headBones.clear(); | ||
| 771 | const FBXGeometry& fbxGeometry = _geometry->getFBXGeometry(); | ||
| 772 | const int neckJointIndex = fbxGeometry.neckJointIndex; | ||
| 773 | std::queue<int> q; | ||
| 774 | q.push(neckJointIndex); | ||
| 775 | _headBones.push_back(neckJointIndex); | ||
| 776 | |||
| 777 | // fbxJoints only hold links to parents not children, so we have to do a bit of extra work here. | ||
| 778 | while (q.size() > 0) { | ||
| 779 | int jointIndex = q.front(); | ||
| 780 | for (int i = 0; i < fbxGeometry.joints.size(); i++) { | ||
| 781 | const FBXJoint& fbxJoint = fbxGeometry.joints[i]; | ||
| 782 | if (jointIndex == fbxJoint.parentIndex) { | ||
| 783 | _headBones.push_back(i); | ||
| 784 | q.push(i); | ||
| 785 | } | ||
| 786 | } | ||
| 787 | q.pop(); | ||
| 788 | } | ||
| 789 | } | ||
| 790 | |||
| 791 | void SkeletonModel::invalidateHeadBones() { | ||
| 792 | _headBones.clear(); | ||
| 793 | } | ||
| 794 | |||
| 795 | void SkeletonModel::cauterizeHead() { | ||
| 796 | if (isActive()) { | ||
| 797 | const FBXGeometry& geometry = _geometry->getFBXGeometry(); | ||
| 798 | const int neckJointIndex = geometry.neckJointIndex; | ||
| 799 | if (neckJointIndex > 0 && neckJointIndex < _jointStates.size()) { | ||
| 800 | |||
| 801 | // lazy init of headBones | ||
| 802 | if (_headBones.size() == 0) { | ||
| 803 | initHeadBones(); | ||
| 804 | } | ||
| 805 | |||
| 806 | // preserve the translation for the neck | ||
| 807 | glm::vec4 trans = _jointStates[neckJointIndex].getTransform()[3]; | ||
| 808 | glm::vec4 zero(0, 0, 0, 0); | ||
| 809 | for (const int &i : _headBones) { | ||
| 810 | JointState& joint = _jointStates[i]; | ||
| 811 | glm::mat4 newXform(zero, zero, zero, trans); | ||
| 812 | joint.setTransform(newXform); | ||
| 813 | joint.setVisibleTransform(newXform); | ||
| 814 | } | ||
| 815 | } | ||
| 816 | } | ||
| 817 | } | ||
| 818 | |||
| 819 | void SkeletonModel::onInvalidate() { | 548 | void SkeletonModel::onInvalidate() { |
| 820 | invalidateHeadBones(); | ||
| 821 | } | 549 | } |