void SkeletonModel::initJointStates() { const FBXGeometry& geometry = getFBXGeometry(); glm::mat4 modelOffset = glm::scale(_scale) * glm::translate(_offset); _rig->initJointStates(geometry, modelOffset); // Determine the default eye position for avatar scale = 1.0 int headJointIndex = geometry.headJointIndex; if (0 > headJointIndex || headJointIndex >= _rig->getJointStateCount()) { qCWarning(interfaceapp) << "Bad head joint! Got:" << headJointIndex << "jointCount:" << _rig->getJointStateCount(); } glm::vec3 leftEyePosition, rightEyePosition; getEyeModelPositions(leftEyePosition, rightEyePosition); glm::vec3 midEyePosition = (leftEyePosition + rightEyePosition) / 2.0f; int rootJointIndex = geometry.rootJointIndex; glm::vec3 rootModelPosition; getJointPosition(rootJointIndex, rootModelPosition); _defaultEyeModelPosition = midEyePosition - rootModelPosition; // Skeleton may have already been scaled so unscale it _defaultEyeModelPosition = _defaultEyeModelPosition / _scale; computeBoundingShape(); Extents meshExtents = getMeshExtents(); _headClipDistance = -(meshExtents.minimum.z / _scale.z - _defaultEyeModelPosition.z); _headClipDistance = std::max(_headClipDistance, DEFAULT_NEAR_CLIP); _owningAvatar->rebuildCollisionShape(); emit skeletonLoaded(); }
void SkeletonModel::resetShapePositionsToDefaultPose() { // DEBUG method. // Moves shapes to the joint default locations for debug visibility into // how the bounding shape is computed. if (!_geometry || _shapes.isEmpty()) { // geometry or joints have not yet been created return; } const FBXGeometry& geometry = _geometry->getFBXGeometry(); if (geometry.joints.isEmpty()) { return; } // The shapes are moved to their default positions in computeBoundingShape(). computeBoundingShape(geometry); // Then we move them into world frame for rendering at the Model's location. for (int i = 0; i < _shapes.size(); i++) { Shape* shape = _shapes[i]; if (shape) { shape->setTranslation(_translation + _rotation * shape->getTranslation()); shape->setRotation(_rotation * shape->getRotation()); } } _boundingShape.setTranslation(_translation + _rotation * _boundingShapeLocalOffset); _boundingShape.setRotation(_rotation); }
// virtual void SkeletonModel::buildShapes() { if (_geometry == NULL || _rig->jointStatesEmpty()) { return; } const FBXGeometry& geometry = _geometry->getFBXGeometry(); if (geometry.joints.isEmpty() || geometry.rootJointIndex == -1) { // rootJointIndex == -1 if the avatar model has no skeleton return; } computeBoundingShape(geometry); }
// virtual void SkeletonModel::buildShapes() { if (_geometry == NULL || _jointStates.isEmpty()) { return; } const FBXGeometry& geometry = _geometry->getFBXGeometry(); if (geometry.joints.isEmpty() || geometry.rootJointIndex == -1) { // rootJointIndex == -1 if the avatar model has no skeleton return; } float uniformScale = extractUniformScale(_scale); const int numStates = _jointStates.size(); for (int i = 0; i < numStates; i++) { JointState& state = _jointStates[i]; const FBXJoint& joint = state.getFBXJoint(); float radius = uniformScale * joint.boneRadius; float halfHeight = 0.5f * uniformScale * joint.distanceToParent; Shape::Type type = joint.shapeType; int parentIndex = joint.parentIndex; if (parentIndex == -1 || radius < EPSILON) { type = INVALID_SHAPE; } else if (type == CAPSULE_SHAPE && halfHeight < EPSILON) { // this shape is forced to be a sphere type = SPHERE_SHAPE; } Shape* shape = NULL; if (type == SPHERE_SHAPE) { shape = new SphereShape(radius); shape->setEntity(this); } else if (type == CAPSULE_SHAPE) { assert(parentIndex != -1); shape = new CapsuleShape(radius, halfHeight); shape->setEntity(this); } if (shape && parentIndex != -1) { // always disable collisions between joint and its parent disableCollisions(i, parentIndex); } _shapes.push_back(shape); } // This method moves the shapes to their default positions in Model frame. computeBoundingShape(geometry); }
void SkeletonModel::initJointStates() { const HFMModel& hfmModel = getHFMModel(); glm::mat4 modelOffset = glm::scale(_scale) * glm::translate(_offset); _rig.initJointStates(hfmModel, modelOffset); { // initialize _jointData with proper values for default joints QVector<JointData> defaultJointData; _rig.copyJointsIntoJointData(defaultJointData); _owningAvatar->setRawJointData(defaultJointData); } // Determine the default eye position for avatar scale = 1.0 int headJointIndex = _rig.indexOfJoint("Head"); if (0 > headJointIndex || headJointIndex >= _rig.getJointStateCount()) { qCWarning(avatars_renderer) << "Bad head joint! Got:" << headJointIndex << "jointCount:" << _rig.getJointStateCount(); } glm::vec3 leftEyePosition, rightEyePosition; getEyeModelPositions(leftEyePosition, rightEyePosition); glm::vec3 midEyePosition = (leftEyePosition + rightEyePosition) / 2.0f; int rootJointIndex = _rig.indexOfJoint("Hips"); glm::vec3 rootModelPosition; getJointPosition(rootJointIndex, rootModelPosition); _defaultEyeModelPosition = midEyePosition - rootModelPosition; // Skeleton may have already been scaled so unscale it _defaultEyeModelPosition = _defaultEyeModelPosition / _scale; computeBoundingShape(); Extents meshExtents = getMeshExtents(); _headClipDistance = -(meshExtents.minimum.z / _scale.z - _defaultEyeModelPosition.z); _headClipDistance = std::max(_headClipDistance, DEFAULT_NEAR_CLIP); _owningAvatar->rebuildCollisionShape(); emit skeletonLoaded(); }
// virtual void SkeletonModel::buildShapes() { if (_geometry == NULL || _jointStates.isEmpty()) { return; } const FBXGeometry& geometry = _geometry->getFBXGeometry(); if (geometry.joints.isEmpty()) { return; } if (!_ragdoll) { _ragdoll = new SkeletonRagdoll(this); } _ragdoll->setRootIndex(geometry.rootJointIndex); _ragdoll->initPoints(); QVector<VerletPoint>& points = _ragdoll->getPoints(); float massScale = _ragdoll->getMassScale(); float uniformScale = extractUniformScale(_scale); const int numStates = _jointStates.size(); float totalMass = 0.0f; for (int i = 0; i < numStates; i++) { JointState& state = _jointStates[i]; const FBXJoint& joint = state.getFBXJoint(); float radius = uniformScale * joint.boneRadius; float halfHeight = 0.5f * uniformScale * joint.distanceToParent; Shape::Type type = joint.shapeType; int parentIndex = joint.parentIndex; if (parentIndex == -1 || radius < EPSILON) { type = SHAPE_TYPE_UNKNOWN; } else if (type == SHAPE_TYPE_CAPSULE && halfHeight < EPSILON) { // this shape is forced to be a sphere type = SHAPE_TYPE_SPHERE; } Shape* shape = NULL; if (type == SHAPE_TYPE_SPHERE) { shape = new VerletSphereShape(radius, &(points[i])); shape->setEntity(this); float mass = massScale * glm::max(MIN_JOINT_MASS, DENSITY_OF_WATER * shape->getVolume()); points[i].setMass(mass); totalMass += mass; } else if (type == SHAPE_TYPE_CAPSULE) { assert(parentIndex != -1); shape = new VerletCapsuleShape(radius, &(points[parentIndex]), &(points[i])); shape->setEntity(this); float mass = massScale * glm::max(MIN_JOINT_MASS, DENSITY_OF_WATER * shape->getVolume()); points[i].setMass(mass); totalMass += mass; } if (shape && parentIndex != -1) { // always disable collisions between joint and its parent disableCollisions(i, parentIndex); } _shapes.push_back(shape); } // set the mass of the root if (numStates > 0) { points[_ragdoll->getRootIndex()].setMass(totalMass); } // This method moves the shapes to their default positions in Model frame. computeBoundingShape(geometry); // While the shapes are in their default position we disable collisions between // joints that are currently colliding. disableCurrentSelfCollisions(); _ragdoll->buildConstraints(); // ... then move shapes back to current joint positions _ragdoll->slamPointPositions(); _ragdoll->enforceConstraints(); }