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 | 12 | #include <glm/gtx/transform.hpp> |
| 13 | 13 | #include <QMultiMap> |
| 14 | 14 | |
| 15 | −#include <CapsuleShape.h> | |
| 16 | 15 | #include <DeferredLightingEffect.h> |
| 17 | −#include <SphereShape.h> | |
| 18 | 16 | |
| 19 | 17 | #include "Application.h" |
| 20 | 18 | #include "Avatar.h" |
| @@ -24,29 +22,47 @@ · 3 unmodified lines | ||
| 24 | 22 | #include "Util.h" |
| 25 | 23 | #include "InterfaceLogging.h" |
| 26 | 24 | |
| 27 | −SkeletonModel::SkeletonModel(Avatar* owningAvatar, QObject* parent) : | |
| 28 | − Model(parent), | |
| 25 | +SkeletonModel::SkeletonModel(Avatar* owningAvatar, QObject* parent, RigPointer rig) : | |
| 26 | + Model(rig, parent), | |
| 29 | 27 | _triangleFanID(DependencyManager::get<GeometryCache>()->allocateID()), |
| 30 | 28 | _owningAvatar(owningAvatar), |
| 31 | − _boundingShape(), | |
| 32 | − _boundingShapeLocalOffset(0.0f), | |
| 29 | + _boundingCapsuleLocalOffset(0.0f), | |
| 30 | + _boundingCapsuleRadius(0.0f), | |
| 31 | + _boundingCapsuleHeight(0.0f), | |
| 33 | 32 | _defaultEyeModelPosition(glm::vec3(0.0f, 0.0f, 0.0f)), |
| 34 | − _headClipDistance(DEFAULT_NEAR_CLIP), | |
| 35 | − _isFirstPerson(false) | |
| 33 | + _headClipDistance(DEFAULT_NEAR_CLIP) | |
| 36 | 34 | { |
| 35 | + assert(_rig); | |
| 37 | 36 | assert(_owningAvatar); |
| 38 | − _enableShapes = true; | |
| 39 | 37 | } |
| 40 | 38 | |
| 41 | 39 | SkeletonModel::~SkeletonModel() { |
| 42 | 40 | } |
| 43 | 41 | |
| 44 | 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 | 63 | // Determine the default eye position for avatar scale = 1.0 |
| 48 | 64 | int headJointIndex = _geometry->getFBXGeometry().headJointIndex; |
| 49 | − if (0 <= headJointIndex && headJointIndex < _jointStates.size()) { | |
| 65 | + if (0 <= headJointIndex && headJointIndex < _rig->getJointStateCount()) { | |
| 50 | 66 | |
| 51 | 67 | glm::vec3 leftEyePosition, rightEyePosition; |
| 52 | 68 | getEyeModelPositions(leftEyePosition, rightEyePosition); |
| @@ -66,14 +82,11 @@ void SkeletonModel::initJointStates(QVector<JointState> states) { · 13 unmodified lines | ||
| 66 | 82 | // the SkeletonModel override of updateJointState() will clear the translation part |
| 67 | 83 | // of its root joint and we need that done before we try to build shapes hence we |
| 68 | 84 | // recompute all joint transforms at this time. |
| 69 | − for (int i = 0; i < _jointStates.size(); i++) { | |
| 70 | − updateJointState(i); | |
| 85 | + for (int i = 0; i < _rig->getJointStateCount(); i++) { | |
| 86 | + _rig->updateJointState(i, parentTransform); | |
| 71 | 87 | } |
| 72 | 88 | |
| 73 | − clearShapes(); | |
| 74 | − if (_enableShapes) { | |
| 75 | − buildShapes(); | |
| 76 | − } | |
| 89 | + buildShapes(); | |
| 77 | 90 | |
| 78 | 91 | Extents meshExtents = getMeshExtents(); |
| 79 | 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 | 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 | 126 | void SkeletonModel::simulate(float deltaTime, bool fullUpdate) { |
| 90 | 127 | setTranslation(_owningAvatar->getSkeletonPosition()); |
| @@ -141,49 +178,6 @@ void SkeletonModel::simulate(float deltaTime, bool fullUpdate) { · 50 unmodified lines | ||
| 141 | 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 | 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 | 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 | 200 | return; |
| 207 | 201 | } |
| 208 | 202 | // NOTE: 'position' is in model-frame |
| @@ -217,16 +211,20 @@ void SkeletonModel::applyHandPosition(int jointIndex, const glm::vec3& position) · 8 unmodified lines | ||
| 217 | 211 | if (forearmLength < EPSILON) { |
| 218 | 212 | return; |
| 219 | 213 | } |
| 220 | − JointState& state = _jointStates[jointIndex]; | |
| 221 | − glm::quat handRotation = state.getRotation(); | |
| 214 | + glm::quat handRotation; | |
| 215 | + if (!_rig->getJointStateRotation(jointIndex, handRotation)) { | |
| 216 | + return; | |
| 217 | + } | |
| 222 | 218 | |
| 223 | 219 | // align hand with forearm |
| 224 | 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 | 226 | void SkeletonModel::applyPalmData(int jointIndex, PalmData& palm) { |
| 229 | − if (jointIndex == -1 || jointIndex >= _jointStates.size()) { | |
| 227 | + if (jointIndex == -1 || jointIndex >= _rig->getJointStateCount()) { | |
| 230 | 228 | return; |
| 231 | 229 | } |
| 232 | 230 | const FBXGeometry& geometry = _geometry->getFBXGeometry(); |
| @@ -246,85 +244,36 @@ void SkeletonModel::applyPalmData(int jointIndex, PalmData& palm) { · 13 unmodified lines | ||
| 246 | 244 | palmRotation = rotationBetween(palmRotation * glm::vec3(-sign, 0.0f, 0.0f), fingerDirection) * palmRotation; |
| 247 | 245 | |
| 248 | 246 | if (Menu::getInstance()->isOptionChecked(MenuOption::AlternateIK)) { |
| 249 | − setHandPosition(jointIndex, palmPosition, palmRotation); | |
| 247 | + _rig->setHandPosition(jointIndex, palmPosition, palmRotation, extractUniformScale(_scale), PALM_PRIORITY); | |
| 250 | 248 | } else if (Menu::getInstance()->isOptionChecked(MenuOption::AlignForearmsWithWrists)) { |
| 251 | 249 | float forearmLength = geometry.joints.at(jointIndex).distanceToParent * extractUniformScale(_scale); |
| 252 | 250 | glm::vec3 forearm = palmRotation * glm::vec3(sign * forearmLength, 0.0f, 0.0f); |
| 253 | 251 | setJointPosition(parentJointIndex, palmPosition + forearm, |
| 254 | 252 | glm::quat(), false, -1, false, glm::vec3(0.0f, -1.0f, 0.0f), PALM_PRIORITY); |
| 255 | − JointState& parentState = _jointStates[parentJointIndex]; | |
| 256 | − parentState.setRotationInBindFrame(palmRotation, PALM_PRIORITY); | |
| 253 | + _rig->setJointRotationInBindFrame(parentJointIndex, palmRotation, PALM_PRIORITY); | |
| 257 | 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 | 256 | } else { |
| 260 | 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 | 261 | void SkeletonModel::renderJointConstraints(gpu::Batch& batch, int jointIndex) { |
| 316 | − if (jointIndex == -1 || jointIndex >= _jointStates.size()) { | |
| 262 | + if (jointIndex == -1 || jointIndex >= _rig->getJointStateCount()) { | |
| 317 | 263 | return; |
| 318 | 264 | } |
| 319 | 265 | const FBXGeometry& geometry = _geometry->getFBXGeometry(); |
| 320 | 266 | const float BASE_DIRECTION_SIZE = 0.3f; |
| 321 | 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 | 270 | do { |
| 324 | 271 | const FBXJoint& joint = geometry.joints.at(jointIndex); |
| 325 | − const JointState& jointState = _jointStates.at(jointIndex); | |
| 272 | + const JointState& jointState = _rig->getJointState(jointIndex); | |
| 326 | 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 | 277 | float fanScale = directionSize * 0.75f; |
| 329 | 278 | |
| 330 | 279 | Transform transform = Transform(); |
| @@ -401,72 +350,6 @@ void SkeletonModel::renderOrientationDirections(gpu::Batch& batch, int jointInde · 70 unmodified lines | ||
| 401 | 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 | 353 | bool SkeletonModel::getLeftHandPosition(glm::vec3& position) const { |
| 471 | 354 | return getJointPositionInWorldFrame(getLeftHandJointIndex(), position); |
| 472 | 355 | } |
| @@ -523,7 +406,7 @@ bool SkeletonModel::getNeckParentRotationFromDefaultOrientation(glm::quat& neckP · 50 unmodified lines | ||
| 523 | 406 | glm::quat worldFrameRotation; |
| 524 | 407 | bool success = getJointRotationInWorldFrame(parentIndex, worldFrameRotation); |
| 525 | 408 | if (success) { |
| 526 | − neckParentRotation = worldFrameRotation * _jointStates[parentIndex].getFBXJoint().inverseDefaultRotation; | |
| 409 | + neckParentRotation = worldFrameRotation * _rig->getJointState(parentIndex).getFBXJoint().inverseDefaultRotation; | |
| 527 | 410 | } |
| 528 | 411 | return success; |
| 529 | 412 | } |
| @@ -574,7 +457,7 @@ float VERY_BIG_MASS = 1.0e6f; · 44 unmodified lines | ||
| 574 | 457 | |
| 575 | 458 | // virtual |
| 576 | 459 | void SkeletonModel::buildShapes() { |
| 577 | − if (_geometry == NULL || _jointStates.isEmpty()) { | |
| 460 | + if (_geometry == NULL || _rig->jointStatesEmpty()) { | |
| 578 | 461 | return; |
| 579 | 462 | } |
| 580 | 463 | |
| @@ -583,46 +466,12 @@ void SkeletonModel::buildShapes() { · 2 unmodified lines | ||
| 583 | 466 | // rootJointIndex == -1 if the avatar model has no skeleton |
| 584 | 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 | 469 | computeBoundingShape(geometry); |
| 620 | 470 | } |
| 621 | 471 | |
| 622 | 472 | void SkeletonModel::computeBoundingShape(const FBXGeometry& geometry) { |
| 623 | 473 | // compute default joint transforms |
| 624 | − int numStates = _jointStates.size(); | |
| 625 | − assert(numStates == _shapes.size()); | |
| 474 | + int numStates = _rig->getJointStateCount(); | |
| 626 | 475 | QVector<glm::mat4> transforms; |
| 627 | 476 | transforms.fill(glm::mat4(), numStates); |
| 628 | 477 | |
| @@ -632,190 +481,69 @@ void SkeletonModel::computeBoundingShape(const FBXGeometry& geometry) { · 3 unmodified lines | ||
| 632 | 481 | totalExtents.addPoint(glm::vec3(0.0f)); |
| 633 | 482 | for (int i = 0; i < numStates; i++) { |
| 634 | 483 | // compute the default transform of this joint |
| 635 | − JointState& state = _jointStates[i]; | |
| 484 | + const JointState& state = _rig->getJointState(i); | |
| 636 | 485 | const FBXJoint& joint = state.getFBXJoint(); |
| 637 | 486 | int parentIndex = joint.parentIndex; |
| 638 | 487 | if (parentIndex == -1) { |
| 639 | − transforms[i] = _jointStates[i].getTransform(); | |
| 488 | + transforms[i] = _rig->getJointTransform(i); | |
| 640 | 489 | } else { |
| 641 | 490 | glm::quat modifiedRotation = joint.preRotation * joint.rotation * joint.postRotation; |
| 642 | 491 | transforms[i] = transforms[parentIndex] * glm::translate(joint.translation) |
| 643 | 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 | 497 | glm::vec3 jointPosition = extractTranslation(transforms[i]); |
| 648 | − totalExtents.addPoint(jointPosition); | |
| 649 | − | |
| 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 | − } | |
| 498 | + totalExtents.addPoint(jointPosition + axis); | |
| 499 | + totalExtents.addPoint(jointPosition - axis); | |
| 679 | 500 | } |
| 680 | 501 | |
| 681 | 502 | // compute bounding shape parameters |
| 682 | 503 | // NOTE: we assume that the longest side of totalExtents is the yAxis... |
| 683 | 504 | glm::vec3 diagonal = totalExtents.maximum - totalExtents.minimum; |
| 684 | 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)); | |
| 686 | − _boundingShape.setRadius(capsuleRadius); | |
| 687 | − _boundingShape.setHalfHeight(0.5f * diagonal.y - capsuleRadius); | |
| 506 | + _boundingCapsuleRadius = 0.5f * sqrtf(0.5f * (diagonal.x * diagonal.x + diagonal.z * diagonal.z)); | |
| 507 | + _boundingCapsuleHeight = diagonal.y - 2.0f * _boundingCapsuleRadius; | |
| 688 | 508 | |
| 689 | − glm::vec3 rootPosition = _jointStates[geometry.rootJointIndex].getPosition(); | |
| 690 | − _boundingShapeLocalOffset = 0.5f * (totalExtents.maximum + totalExtents.minimum) - rootPosition; | |
| 509 | + glm::vec3 rootPosition = _rig->getJointState(geometry.rootJointIndex).getPosition(); | |
| 510 | + _boundingCapsuleLocalOffset = 0.5f * (totalExtents.maximum + totalExtents.minimum) - rootPosition; | |
| 691 | 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 | 514 | void SkeletonModel::renderBoundingCollisionShapes(gpu::Batch& batch, float alpha) { |
| 725 | 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 | 517 | auto geometryCache = DependencyManager::get<GeometryCache>(); |
| 734 | 518 | auto deferredLighting = DependencyManager::get<DeferredLightingEffect>(); |
| 735 | 519 | Transform transform; // = Transform(); |
| 736 | 520 | |
| 737 | − // draw a blue sphere at the capsule end point | |
| 738 | − glm::vec3 endPoint; | |
| 739 | − _boundingShape.getEndPoint(endPoint); | |
| 740 | − endPoint = endPoint + _translation; | |
| 741 | − transform.setTranslation(endPoint); | |
| 521 | + // draw a blue sphere at the capsule top point | |
| 522 | + glm::vec3 topPoint = _translation + _boundingCapsuleLocalOffset + (0.5f * _boundingCapsuleHeight) * glm::vec3(0.0f, 1.0f, 0.0f); | |
| 523 | + transform.setTranslation(topPoint); | |
| 742 | 524 | batch.setModelTransform(transform); |
| 743 | 525 | deferredLighting->bindSimpleProgram(batch); |
| 744 | − geometryCache->renderSphere(batch, _boundingShape.getRadius(), BALL_SUBDIVISIONS, BALL_SUBDIVISIONS, | |
| 526 | + geometryCache->renderSphere(batch, _boundingCapsuleRadius, BALL_SUBDIVISIONS, BALL_SUBDIVISIONS, | |
| 745 | 527 | glm::vec4(0.6f, 0.6f, 0.8f, alpha)); |
| 746 | 528 | |
| 747 | − // draw a yellow sphere at the capsule start point | |
| 748 | − glm::vec3 startPoint; | |
| 749 | − _boundingShape.getStartPoint(startPoint); | |
| 750 | − startPoint = startPoint + _translation; | |
| 751 | − glm::vec3 axis = endPoint - startPoint; | |
| 752 | − transform.setTranslation(startPoint); | |
| 529 | + // draw a yellow sphere at the capsule bottom point | |
| 530 | + glm::vec3 bottomPoint = topPoint - glm::vec3(0.0f, -_boundingCapsuleHeight, 0.0f); | |
| 531 | + glm::vec3 axis = topPoint - bottomPoint; | |
| 532 | + transform.setTranslation(bottomPoint); | |
| 753 | 533 | batch.setModelTransform(transform); |
| 754 | 534 | deferredLighting->bindSimpleProgram(batch); |
| 755 | − geometryCache->renderSphere(batch, _boundingShape.getRadius(), BALL_SUBDIVISIONS, BALL_SUBDIVISIONS, | |
| 535 | + geometryCache->renderSphere(batch, _boundingCapsuleRadius, BALL_SUBDIVISIONS, BALL_SUBDIVISIONS, | |
| 756 | 536 | glm::vec4(0.8f, 0.8f, 0.6f, alpha)); |
| 757 | 537 | |
| 758 | 538 | // draw a green cylinder between the two points |
| 759 | 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 | 541 | glm::vec4(0.6f, 0.8f, 0.6f, alpha)); |
| 762 | −#endif | |
| 763 | 542 | } |
| 764 | 543 | |
| 765 | 544 | bool SkeletonModel::hasSkeleton() { |
| 766 | 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 | 548 | void SkeletonModel::onInvalidate() { |
| 820 | − invalidateHeadBones(); | |
| 821 | 549 | } |