Showing the changes to interface/src/avatar/SkeletonModel.cpp (1 of 11 files). Show all
Unified · Split
| @@ -86,7 +86,7 @@ void SkeletonModel::initJointStates(QVector<JointState> states) { · 85 unmodified lines | |||
| 86 | _rig->updateJointState(i, rootTransform); | 86 | _rig->updateJointState(i, rootTransform); |
| 87 | } | 87 | } |
| 88 | 88 | ||
| 89 | buildShapes(); | 89 | computeBoundingShape(); |
| 90 | 90 | ||
| 91 | Extents meshExtents = getMeshExtents(); | 91 | Extents meshExtents = getMeshExtents(); |
| 92 | _headClipDistance = -(meshExtents.minimum.z / _scale.z - _defaultEyeModelPosition.z); | 92 | _headClipDistance = -(meshExtents.minimum.z / _scale.z - _defaultEyeModelPosition.z); |
| @@ -248,6 +248,7 @@ void SkeletonModel::applyHandPosition(int jointIndex, const glm::vec3& position) · 155 unmodified lines | |||
| 248 | rotationBetween(handRotation * glm::vec3(-sign, 0.0f, 0.0f), forearmVector), | 248 | rotationBetween(handRotation * glm::vec3(-sign, 0.0f, 0.0f), forearmVector), |
| 249 | true, PALM_PRIORITY); | 249 | true, PALM_PRIORITY); |
| 250 | } | 250 | } |
| 251 | |||
| 251 | void SkeletonModel::applyPalmData(int jointIndex, PalmData& palm) { | 252 | void SkeletonModel::applyPalmData(int jointIndex, PalmData& palm) { |
| 252 | if (jointIndex == -1 || jointIndex >= _rig->getJointStateCount()) { | 253 | if (jointIndex == -1 || jointIndex >= _rig->getJointStateCount()) { |
| 253 | return; | 254 | return; |
| @@ -261,9 +262,7 @@ void SkeletonModel::applyPalmData(int jointIndex, PalmData& palm) { · 7 unmodified lines | |||
| 261 | // the palm's position must be transformed into the model-frame | 262 | // the palm's position must be transformed into the model-frame |
| 262 | glm::quat inverseRotation = glm::inverse(_rotation); | 263 | glm::quat inverseRotation = glm::inverse(_rotation); |
| 263 | glm::vec3 palmPosition = inverseRotation * (palm.getPosition() - _translation); | 264 | glm::vec3 palmPosition = inverseRotation * (palm.getPosition() - _translation); |
| 264 | 265 | glm::quat palmRotation = inverseRotation * palm.getRotation(); | |
| 265 | // the palm's "raw" rotation is already in the model-frame | ||
| 266 | glm::quat palmRotation = palm.getRawRotation(); | ||
| 267 | 266 | ||
| 268 | inverseKinematics(jointIndex, palmPosition, palmRotation, PALM_PRIORITY); | 267 | inverseKinematics(jointIndex, palmPosition, palmRotation, PALM_PRIORITY); |
| 269 | } | 268 | } |
| @@ -346,9 +345,9 @@ void SkeletonModel::renderOrientationDirections(gpu::Batch& batch, int jointInde · 76 unmodified lines | |||
| 346 | } | 345 | } |
| 347 | OrientationLineIDs& jointLineIDs = _jointOrientationLines[jointIndex]; | 346 | OrientationLineIDs& jointLineIDs = _jointOrientationLines[jointIndex]; |
| 348 | 347 | ||
| 349 | glm::vec3 pRight = position + orientation * IDENTITY_RIGHT * size; | 348 | glm::vec3 pRight = position + orientation * IDENTITY_RIGHT * size; |
| 350 | glm::vec3 pUp = position + orientation * IDENTITY_UP * size; | 349 | glm::vec3 pUp = position + orientation * IDENTITY_UP * size; |
| 351 | glm::vec3 pFront = position + orientation * IDENTITY_FRONT * size; | 350 | glm::vec3 pFront = position + orientation * IDENTITY_FRONT * size; |
| 352 | 351 | ||
| 353 | glm::vec3 red(1.0f, 0.0f, 0.0f); | 352 | glm::vec3 red(1.0f, 0.0f, 0.0f); |
| 354 | geometryCache->renderLine(batch, position, pRight, red, jointLineIDs._right); | 353 | geometryCache->renderLine(batch, position, pRight, red, jointLineIDs._right); |
| @@ -466,7 +465,7 @@ float MIN_JOINT_MASS = 1.0f; · 111 unmodified lines | |||
| 466 | float VERY_BIG_MASS = 1.0e6f; | 465 | float VERY_BIG_MASS = 1.0e6f; |
| 467 | 466 | ||
| 468 | // virtual | 467 | // virtual |
| 469 | void SkeletonModel::buildShapes() { | 468 | void SkeletonModel::computeBoundingShape() { |
| 470 | if (_geometry == NULL || _rig->jointStatesEmpty()) { | 469 | if (_geometry == NULL || _rig->jointStatesEmpty()) { |
| 471 | return; | 470 | return; |
| 472 | } | 471 | } |
| @@ -476,36 +475,86 @@ void SkeletonModel::buildShapes() { · 3 unmodified lines | |||
| 476 | // rootJointIndex == -1 if the avatar model has no skeleton | 475 | // rootJointIndex == -1 if the avatar model has no skeleton |
| 477 | return; | 476 | return; |
| 478 | } | 477 | } |
| 479 | computeBoundingShape(geometry); | ||
| 480 | } | ||
| 481 | 478 | ||
| 482 | void SkeletonModel::computeBoundingShape(const FBXGeometry& geometry) { | 479 | // BOUNDING SHAPE HACK: before we measure the bounds of the joints we use IK to put the |
| 483 | // compute default joint transforms | 480 | // hands and feet into positions that are more correct than the default pose. |
| 484 | int numStates = _rig->getJointStateCount(); | 481 | |
| 485 | QVector<glm::mat4> transforms; | 482 | // Measure limb lengths so we can specify IK targets that will pull hands and feet tight to body |
| 486 | transforms.fill(glm::mat4(), numStates); | 483 | QVector<QString> endEffectors; |
| 484 | endEffectors.push_back("RightHand"); | ||
| 485 | endEffectors.push_back("LeftHand"); | ||
| 486 | endEffectors.push_back("RightFoot"); | ||
| 487 | endEffectors.push_back("LeftFoot"); | ||
| 488 | |||
| 489 | QVector<QString> baseJoints; | ||
| 490 | baseJoints.push_back("RightArm"); | ||
| 491 | baseJoints.push_back("LeftArm"); | ||
| 492 | baseJoints.push_back("RightUpLeg"); | ||
| 493 | baseJoints.push_back("LeftUpLeg"); | ||
| 494 | |||
| 495 | for (int i = 0; i < endEffectors.size(); ++i) { | ||
| 496 | QString tipName = endEffectors[i]; | ||
| 497 | QString baseName = baseJoints[i]; | ||
| 498 | float limbLength = 0.0f; | ||
| 499 | int tipIndex = _rig->indexOfJoint(tipName); | ||
| 500 | if (tipIndex == -1) { | ||
| 501 | continue; | ||
| 502 | } | ||
| 503 | // save tip's relative rotation for later | ||
| 504 | glm::quat tipRotation = _rig->getJointState(tipIndex).getRotationInConstrainedFrame(); | ||
| 505 | |||
| 506 | // IK on each endpoint | ||
| 507 | int jointIndex = tipIndex; | ||
| 508 | QVector<int> freeLineage; | ||
| 509 | float priority = 1.0f; | ||
| 510 | while (jointIndex > -1) { | ||
| 511 | JointState limbJoint = _rig->getJointState(jointIndex); | ||
| 512 | freeLineage.push_back(jointIndex); | ||
| 513 | if (limbJoint.getName() == baseName) { | ||
| 514 | glm::vec3 targetPosition = limbJoint.getPosition() - glm::vec3(0.0f, 1.5f * limbLength, 0.0f); | ||
| 515 | // do IK a few times to make sure the endpoint gets close to its target | ||
| 516 | for (int j = 0; j < 5; ++j) { | ||
| 517 | _rig->inverseKinematics(tipIndex, | ||
| 518 | targetPosition, | ||
| 519 | glm::quat(), | ||
| 520 | priority, | ||
| 521 | freeLineage, | ||
| 522 | glm::mat4()); | ||
| 523 | } | ||
| 524 | break; | ||
| 525 | } | ||
| 526 | limbLength += limbJoint.getDistanceToParent(); | ||
| 527 | jointIndex = limbJoint.getParentIndex(); | ||
| 528 | } | ||
| 529 | |||
| 530 | // since this IK target is totally bogus we restore the tip's relative rotation | ||
| 531 | _rig->setJointRotationInConstrainedFrame(tipIndex, tipRotation, priority); | ||
| 532 | } | ||
| 533 | |||
| 534 | // recompute all joint model-frame transforms | ||
| 535 | glm::mat4 rootTransform = glm::scale(_scale) * glm::translate(_offset) * geometry.offset; | ||
| 536 | for (int i = 0; i < _rig->getJointStateCount(); i++) { | ||
| 537 | _rig->updateJointState(i, rootTransform); | ||
| 538 | } | ||
| 539 | // END BOUNDING SHAPE HACK | ||
| 487 | 540 | ||
| 488 | // compute bounding box that encloses all shapes | 541 | // compute bounding box that encloses all shapes |
| 489 | Extents totalExtents; | 542 | Extents totalExtents; |
| 490 | totalExtents.reset(); | 543 | totalExtents.reset(); |
| 491 | totalExtents.addPoint(glm::vec3(0.0f)); | 544 | totalExtents.addPoint(glm::vec3(0.0f)); |
| 545 | int numStates = _rig->getJointStateCount(); | ||
| 492 | for (int i = 0; i < numStates; i++) { | 546 | for (int i = 0; i < numStates; i++) { |
| 493 | // compute the default transform of this joint | 547 | // compute the default transform of this joint |
| 494 | const JointState& state = _rig->getJointState(i); | 548 | const JointState& state = _rig->getJointState(i); |
| 495 | int parentIndex = state.getParentIndex(); | ||
| 496 | if (parentIndex == -1) { | ||
| 497 | transforms[i] = _rig->getJointTransform(i); | ||
| 498 | } else { | ||
| 499 | glm::quat modifiedRotation = state.getPreRotation() * state.getDefaultRotation() * state.getPostRotation(); | ||
| 500 | transforms[i] = transforms[parentIndex] * glm::translate(state.getTranslation()) | ||
| 501 | * state.getPreTransform() * glm::mat4_cast(modifiedRotation) * state.getPostTransform(); | ||
| 502 | } | ||
| 503 | 549 | ||
| 504 | // Each joint contributes a sphere at its position | 550 | // HACK WORKAROUND: ignore joints that may have bad translation (e.g. have been flagged as such with zero radius) |
| 505 | glm::vec3 axis(state.getBoneRadius()); | 551 | if (state.getBoneRadius() > 0.0f) { |
| 506 | glm::vec3 jointPosition = extractTranslation(transforms[i]); | 552 | // Each joint contributes a sphere at its position |
| 507 | totalExtents.addPoint(jointPosition + axis); | 553 | glm::vec3 axis(state.getBoneRadius()); |
| 508 | totalExtents.addPoint(jointPosition - axis); | 554 | glm::vec3 jointPosition = state.getPosition(); |
| 555 | totalExtents.addPoint(jointPosition + axis); | ||
| 556 | totalExtents.addPoint(jointPosition - axis); | ||
| 557 | } | ||
| 509 | } | 558 | } |
| 510 | 559 | ||
| 511 | // compute bounding shape parameters | 560 | // compute bounding shape parameters |
| @@ -517,6 +566,11 @@ void SkeletonModel::computeBoundingShape(const FBXGeometry& geometry) { · 5 unmodified lines | |||
| 517 | 566 | ||
| 518 | glm::vec3 rootPosition = _rig->getJointState(geometry.rootJointIndex).getPosition(); | 567 | glm::vec3 rootPosition = _rig->getJointState(geometry.rootJointIndex).getPosition(); |
| 519 | _boundingCapsuleLocalOffset = 0.5f * (totalExtents.maximum + totalExtents.minimum) - rootPosition; | 568 | _boundingCapsuleLocalOffset = 0.5f * (totalExtents.maximum + totalExtents.minimum) - rootPosition; |
| 569 | |||
| 570 | // RECOVER FROM BOUNINDG SHAPE HACK: now that we're all done, restore the default pose | ||
| 571 | for (int i = 0; i < numStates; i++) { | ||
| 572 | _rig->restoreJointRotation(i, 1.0f, 1.0f); | ||
| 573 | } | ||
| 520 | } | 574 | } |
| 521 | 575 | ||
| 522 | void SkeletonModel::renderBoundingCollisionShapes(gpu::Batch& batch, float alpha) { | 576 | void SkeletonModel::renderBoundingCollisionShapes(gpu::Batch& batch, float alpha) { |
| @@ -535,7 +589,7 @@ void SkeletonModel::renderBoundingCollisionShapes(gpu::Batch& batch, float alpha · 12 unmodified lines | |||
| 535 | glm::vec4(0.6f, 0.6f, 0.8f, alpha)); | 589 | glm::vec4(0.6f, 0.6f, 0.8f, alpha)); |
| 536 | 590 | ||
| 537 | // draw a yellow sphere at the capsule bottom point | 591 | // draw a yellow sphere at the capsule bottom point |
| 538 | glm::vec3 bottomPoint = topPoint - glm::vec3(0.0f, -_boundingCapsuleHeight, 0.0f); | 592 | glm::vec3 bottomPoint = topPoint - glm::vec3(0.0f, _boundingCapsuleHeight, 0.0f); |
| 539 | glm::vec3 axis = topPoint - bottomPoint; | 593 | glm::vec3 axis = topPoint - bottomPoint; |
| 540 | transform.setTranslation(bottomPoint); | 594 | transform.setTranslation(bottomPoint); |
| 541 | batch.setModelTransform(transform); | 595 | batch.setModelTransform(transform); |