// virtual void SkeletonModel::renderJointCollisionShapes(float alpha) { if (!_ragdoll) { return; } glPushMatrix(); Application::getInstance()->loadTranslatedViewMatrix(_translation); glm::vec3 simulationTranslation = _ragdoll->getTranslationInSimulationFrame(); for (int i = 0; i < _shapes.size(); i++) { Shape* shape = _shapes[i]; if (!shape) { continue; } auto geometryCache = DependencyManager::get<GeometryCache>(); glPushMatrix(); // shapes are stored in simulation-frame but we want position to be model-relative if (shape->getType() == SPHERE_SHAPE) { glm::vec3 position = shape->getTranslation() - simulationTranslation; glTranslatef(position.x, position.y, position.z); // draw a grey sphere at shape position geometryCache->renderSphere(shape->getBoundingRadius(), BALL_SUBDIVISIONS, BALL_SUBDIVISIONS, glm::vec4(0.75f, 0.75f, 0.75f, alpha)); } else if (shape->getType() == CAPSULE_SHAPE) { CapsuleShape* capsule = static_cast<CapsuleShape*>(shape); // draw a blue sphere at the capsule endpoint glm::vec3 endPoint; capsule->getEndPoint(endPoint); endPoint = endPoint - simulationTranslation; glTranslatef(endPoint.x, endPoint.y, endPoint.z); geometryCache->renderSphere(capsule->getRadius(), BALL_SUBDIVISIONS, BALL_SUBDIVISIONS, glm::vec4(0.6f, 0.6f, 0.8f, alpha)); // draw a yellow sphere at the capsule startpoint glm::vec3 startPoint; capsule->getStartPoint(startPoint); startPoint = startPoint - simulationTranslation; glm::vec3 axis = endPoint - startPoint; glTranslatef(-axis.x, -axis.y, -axis.z); geometryCache->renderSphere(capsule->getRadius(), BALL_SUBDIVISIONS, BALL_SUBDIVISIONS, glm::vec4(0.8f, 0.8f, 0.6f, alpha)); // draw a green cylinder between the two points glm::vec3 origin(0.0f); Avatar::renderJointConnectingCone( origin, axis, capsule->getRadius(), capsule->getRadius(), glm::vec4(0.6f, 0.8f, 0.6f, alpha)); } glPopMatrix(); } glPopMatrix(); }
void SkeletonModel::computeBoundingShape(const FBXGeometry& geometry) { // compute default joint transforms int numStates = _jointStates.size(); assert(numStates == _shapes.size()); QVector<glm::mat4> transforms; transforms.fill(glm::mat4(), numStates); // compute bounding box that encloses all shapes Extents totalExtents; totalExtents.reset(); totalExtents.addPoint(glm::vec3(0.0f)); for (int i = 0; i < numStates; i++) { // compute the default transform of this joint JointState& state = _jointStates[i]; const FBXJoint& joint = state.getFBXJoint(); int parentIndex = joint.parentIndex; if (parentIndex == -1) { transforms[i] = _jointStates[i].getTransform(); } else { glm::quat modifiedRotation = joint.preRotation * joint.rotation * joint.postRotation; transforms[i] = transforms[parentIndex] * glm::translate(joint.translation) * joint.preTransform * glm::mat4_cast(modifiedRotation) * joint.postTransform; } // Each joint contributes its point to the bounding box glm::vec3 jointPosition = extractTranslation(transforms[i]); totalExtents.addPoint(jointPosition); Shape* shape = _shapes[i]; if (!shape) { continue; } // Each joint with a shape contributes to the totalExtents: a box // that contains the sphere centered at the end of the joint with radius of the bone. // TODO: skip hand and arm shapes for bounding box calculation int type = shape->getType(); if (type == CAPSULE_SHAPE) { // add the two furthest surface points of the capsule CapsuleShape* capsule = static_cast<CapsuleShape*>(shape); float radius = capsule->getRadius(); glm::vec3 axis(radius); Extents shapeExtents; shapeExtents.reset(); shapeExtents.addPoint(jointPosition + axis); shapeExtents.addPoint(jointPosition - axis); totalExtents.addExtents(shapeExtents); } else if (type == SPHERE_SHAPE) { float radius = shape->getBoundingRadius(); glm::vec3 axis(radius); Extents shapeExtents; shapeExtents.reset(); shapeExtents.addPoint(jointPosition + axis); shapeExtents.addPoint(jointPosition - axis); totalExtents.addExtents(shapeExtents); } } // compute bounding shape parameters // NOTE: we assume that the longest side of totalExtents is the yAxis... glm::vec3 diagonal = totalExtents.maximum - totalExtents.minimum; // ... and assume the radius is half the RMS of the X and Z sides: float capsuleRadius = 0.5f * sqrtf(0.5f * (diagonal.x * diagonal.x + diagonal.z * diagonal.z)); _boundingShape.setRadius(capsuleRadius); _boundingShape.setHalfHeight(0.5f * diagonal.y - capsuleRadius); glm::vec3 rootPosition = _jointStates[geometry.rootJointIndex].getPosition(); _boundingShapeLocalOffset = 0.5f * (totalExtents.maximum + totalExtents.minimum) - rootPosition; _boundingRadius = 0.5f * glm::length(diagonal); }
void SkeletonModel::computeBoundingShape(const FBXGeometry& geometry) { // compute default joint transforms int numStates = _jointStates.size(); QVector<glm::mat4> transforms; transforms.fill(glm::mat4(), numStates); QVector<VerletPoint>& ragdollPoints = _ragdoll->getPoints(); // compute the default transforms and slam the ragdoll positions accordingly // (which puts the shapes where we want them) for (int i = 0; i < numStates; i++) { JointState& state = _jointStates[i]; const FBXJoint& joint = state.getFBXJoint(); int parentIndex = joint.parentIndex; if (parentIndex == -1) { transforms[i] = _jointStates[i].getTransform(); ragdollPoints[i].initPosition(extractTranslation(transforms[i])); continue; } glm::quat modifiedRotation = joint.preRotation * joint.rotation * joint.postRotation; transforms[i] = transforms[parentIndex] * glm::translate(joint.translation) * joint.preTransform * glm::mat4_cast(modifiedRotation) * joint.postTransform; // setting the ragdollPoints here slams the VerletShapes into their default positions ragdollPoints[i].initPosition(extractTranslation(transforms[i])); } // compute bounding box that encloses all shapes Extents totalExtents; totalExtents.reset(); totalExtents.addPoint(glm::vec3(0.0f)); for (int i = 0; i < _shapes.size(); i++) { Shape* shape = _shapes[i]; if (!shape) { continue; } // TODO: skip hand and arm shapes for bounding box calculation Extents shapeExtents; shapeExtents.reset(); glm::vec3 localPosition = shape->getTranslation(); int type = shape->getType(); if (type == CAPSULE_SHAPE) { // add the two furthest surface points of the capsule CapsuleShape* capsule = static_cast<CapsuleShape*>(shape); glm::vec3 axis; capsule->computeNormalizedAxis(axis); float radius = capsule->getRadius(); float halfHeight = capsule->getHalfHeight(); axis = halfHeight * axis + glm::vec3(radius); shapeExtents.addPoint(localPosition + axis); shapeExtents.addPoint(localPosition - axis); totalExtents.addExtents(shapeExtents); } else if (type == SPHERE_SHAPE) { float radius = shape->getBoundingRadius(); glm::vec3 axis = glm::vec3(radius); shapeExtents.addPoint(localPosition + axis); shapeExtents.addPoint(localPosition - axis); totalExtents.addExtents(shapeExtents); } } // compute bounding shape parameters // NOTE: we assume that the longest side of totalExtents is the yAxis... glm::vec3 diagonal = totalExtents.maximum - totalExtents.minimum; // ... and assume the radius is half the RMS of the X and Z sides: float capsuleRadius = 0.5f * sqrtf(0.5f * (diagonal.x * diagonal.x + diagonal.z * diagonal.z)); _boundingShape.setRadius(capsuleRadius); _boundingShape.setHalfHeight(0.5f * diagonal.y - capsuleRadius); glm::vec3 rootPosition = _jointStates[geometry.rootJointIndex].getPosition(); _boundingShapeLocalOffset = 0.5f * (totalExtents.maximum + totalExtents.minimum) - rootPosition; _boundingRadius = 0.5f * glm::length(diagonal); }