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 | 86 | _rig->updateJointState(i, rootTransform); |
| 87 | 87 | } |
| 88 | 88 | |
| 89 | − buildShapes(); | |
| 89 | + computeBoundingShape(); | |
| 90 | 90 | |
| 91 | 91 | Extents meshExtents = getMeshExtents(); |
| 92 | 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 | 248 | rotationBetween(handRotation * glm::vec3(-sign, 0.0f, 0.0f), forearmVector), |
| 249 | 249 | true, PALM_PRIORITY); |
| 250 | 250 | } |
| 251 | + | |
| 251 | 252 | void SkeletonModel::applyPalmData(int jointIndex, PalmData& palm) { |
| 252 | 253 | if (jointIndex == -1 || jointIndex >= _rig->getJointStateCount()) { |
| 253 | 254 | return; |
| @@ -261,9 +262,7 @@ void SkeletonModel::applyPalmData(int jointIndex, PalmData& palm) { · 7 unmodified lines | ||
| 261 | 262 | // the palm's position must be transformed into the model-frame |
| 262 | 263 | glm::quat inverseRotation = glm::inverse(_rotation); |
| 263 | 264 | glm::vec3 palmPosition = inverseRotation * (palm.getPosition() - _translation); |
| 264 | − | |
| 265 | − // the palm's "raw" rotation is already in the model-frame | |
| 266 | − glm::quat palmRotation = palm.getRawRotation(); | |
| 265 | + glm::quat palmRotation = inverseRotation * palm.getRotation(); | |
| 267 | 266 | |
| 268 | 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 | 346 | OrientationLineIDs& jointLineIDs = _jointOrientationLines[jointIndex]; |
| 348 | 347 | |
| 349 | − glm::vec3 pRight = position + orientation * IDENTITY_RIGHT * size; | |
| 350 | − glm::vec3 pUp = position + orientation * IDENTITY_UP * size; | |
| 351 | − glm::vec3 pFront = position + orientation * IDENTITY_FRONT * size; | |
| 348 | + glm::vec3 pRight = position + orientation * IDENTITY_RIGHT * size; | |
| 349 | + glm::vec3 pUp = position + orientation * IDENTITY_UP * size; | |
| 350 | + glm::vec3 pFront = position + orientation * IDENTITY_FRONT * size; | |
| 352 | 351 | |
| 353 | 352 | glm::vec3 red(1.0f, 0.0f, 0.0f); |
| 354 | 353 | geometryCache->renderLine(batch, position, pRight, red, jointLineIDs._right); |
| @@ -466,7 +465,7 @@ float MIN_JOINT_MASS = 1.0f; · 111 unmodified lines | ||
| 466 | 465 | float VERY_BIG_MASS = 1.0e6f; |
| 467 | 466 | |
| 468 | 467 | // virtual |
| 469 | −void SkeletonModel::buildShapes() { | |
| 468 | +void SkeletonModel::computeBoundingShape() { | |
| 470 | 469 | if (_geometry == NULL || _rig->jointStatesEmpty()) { |
| 471 | 470 | return; |
| 472 | 471 | } |
| @@ -476,36 +475,86 @@ void SkeletonModel::buildShapes() { · 3 unmodified lines | ||
| 476 | 475 | // rootJointIndex == -1 if the avatar model has no skeleton |
| 477 | 476 | return; |
| 478 | 477 | } |
| 479 | − computeBoundingShape(geometry); | |
| 480 | −} | |
| 481 | 478 | |
| 482 | −void SkeletonModel::computeBoundingShape(const FBXGeometry& geometry) { | |
| 483 | − // compute default joint transforms | |
| 484 | − int numStates = _rig->getJointStateCount(); | |
| 485 | − QVector<glm::mat4> transforms; | |
| 486 | − transforms.fill(glm::mat4(), numStates); | |
| 479 | + // BOUNDING SHAPE HACK: before we measure the bounds of the joints we use IK to put the | |
| 480 | + // hands and feet into positions that are more correct than the default pose. | |
| 481 | + | |
| 482 | + // Measure limb lengths so we can specify IK targets that will pull hands and feet tight to body | |
| 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 | 541 | // compute bounding box that encloses all shapes |
| 489 | 542 | Extents totalExtents; |
| 490 | 543 | totalExtents.reset(); |
| 491 | 544 | totalExtents.addPoint(glm::vec3(0.0f)); |
| 545 | + int numStates = _rig->getJointStateCount(); | |
| 492 | 546 | for (int i = 0; i < numStates; i++) { |
| 493 | 547 | // compute the default transform of this joint |
| 494 | 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 | |
| 505 | − glm::vec3 axis(state.getBoneRadius()); | |
| 506 | − glm::vec3 jointPosition = extractTranslation(transforms[i]); | |
| 507 | − totalExtents.addPoint(jointPosition + axis); | |
| 508 | − totalExtents.addPoint(jointPosition - axis); | |
| 550 | + // HACK WORKAROUND: ignore joints that may have bad translation (e.g. have been flagged as such with zero radius) | |
| 551 | + if (state.getBoneRadius() > 0.0f) { | |
| 552 | + // Each joint contributes a sphere at its position | |
| 553 | + glm::vec3 axis(state.getBoneRadius()); | |
| 554 | + glm::vec3 jointPosition = state.getPosition(); | |
| 555 | + totalExtents.addPoint(jointPosition + axis); | |
| 556 | + totalExtents.addPoint(jointPosition - axis); | |
| 557 | + } | |
| 509 | 558 | } |
| 510 | 559 | |
| 511 | 560 | // compute bounding shape parameters |
| @@ -517,6 +566,11 @@ void SkeletonModel::computeBoundingShape(const FBXGeometry& geometry) { · 5 unmodified lines | ||
| 517 | 566 | |
| 518 | 567 | glm::vec3 rootPosition = _rig->getJointState(geometry.rootJointIndex).getPosition(); |
| 519 | 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 | 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 | 589 | glm::vec4(0.6f, 0.6f, 0.8f, alpha)); |
| 536 | 590 | |
| 537 | 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 | 593 | glm::vec3 axis = topPoint - bottomPoint; |
| 540 | 594 | transform.setTranslation(bottomPoint); |
| 541 | 595 | batch.setModelTransform(transform); |