History

Merge branch 'master' into plugins

Bradley Austin Davis committed 11 years ago

Commit 7e60aee2 parents d415ee1 9215ea8181 files · +5728 −48029Browse files

Showing the changes to interface/src/avatar/SkeletonModel.cpp (1 of 181 files). Show all

Unified · Split

interface/src/avatar/SkeletonModel.cpp+97−369
@@ -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
27SkeletonModel::SkeletonModel(Avatar* owningAvatar, QObject* parent) : 25SkeletonModel::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
41SkeletonModel::~SkeletonModel() {39SkeletonModel::~SkeletonModel() {
42}40}
43 41
44void SkeletonModel::initJointStates(QVector<JointState> states) {42void 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.063 // 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 part82 // 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 we83 // 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
86const float PALM_PRIORITY = DEFAULT_PRIORITY;99const float PALM_PRIORITY = DEFAULT_PRIORITY;
87const float LEAN_PRIORITY = DEFAULT_PRIORITY;100
101void 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
89void SkeletonModel::simulate(float deltaTime, bool fullUpdate) {126void 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
154void 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
189void SkeletonModel::renderIKConstraints(gpu::Batch& batch) {183void SkeletonModel::renderIKConstraints(gpu::Batch& batch) {
@@ -202,7 +196,7 @@ bool operator<(const IndexValue& firstIndex, const IndexValue& secondIndex) { · 12 unmodified lines
202}196}
203 197
204void SkeletonModel::applyHandPosition(int jointIndex, const glm::vec3& position) {198void 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-frame202 // 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 forearm219 // 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
228void SkeletonModel::applyPalmData(int jointIndex, PalmData& palm) {226void 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 identity254 // 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
264void 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
291void 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
307void SkeletonModel::maybeUpdateNeckRotation(const JointState& parentState, const FBXJoint& joint, JointState& state) {
308 _owningAvatar->getHead()->getFaceModel().maybeUpdateNeckRotation(parentState, joint, state);
309}
310
311void SkeletonModel::maybeUpdateEyeRotation(const JointState& parentState, const FBXJoint& joint, JointState& state) {
312 _owningAvatar->getHead()->getFaceModel().maybeUpdateEyeRotation(this, parentState, joint, state);
313}
314
315void SkeletonModel::renderJointConstraints(gpu::Batch& batch, int jointIndex) {261void 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
406void 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
470bool SkeletonModel::getLeftHandPosition(glm::vec3& position) const {353bool 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// virtual458// virtual
576void SkeletonModel::buildShapes() {459void 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 skeleton466 // 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
622void SkeletonModel::computeBoundingShape(const FBXGeometry& geometry) {472void SkeletonModel::computeBoundingShape(const FBXGeometry& geometry) {
623 // compute default joint transforms473 // 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 joint483 // 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 box495 // 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 parameters502 // 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
694void 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
724void SkeletonModel::renderBoundingCollisionShapes(gpu::Batch& batch, float alpha) {514void 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 point521 // 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 point529 // 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 points538 // 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
765bool SkeletonModel::hasSkeleton() {544bool SkeletonModel::hasSkeleton() {
766 return isActive() ? _geometry->getFBXGeometry().rootJointIndex != -1 : false;545 return isActive() ? _geometry->getFBXGeometry().rootJointIndex != -1 : false;
767}546}
768 547
769void 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
791void SkeletonModel::invalidateHeadBones() {
792 _headBones.clear();
793}
794
795void 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
819void SkeletonModel::onInvalidate() {548void SkeletonModel::onInvalidate() {
820 invalidateHeadBones();
821}549}

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t