diff --git a/interface/src/renderer/FBXReader.cpp b/interface/src/renderer/FBXReader.cpp index 959c015eea..32b5686558 100644 --- a/interface/src/renderer/FBXReader.cpp +++ b/interface/src/renderer/FBXReader.cpp @@ -1516,7 +1516,6 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping) } float radiusScale = extractUniformScale(joint.transform * fbxCluster.inverseBindMatrix); JointShapeInfo& jointShapeInfo = jointShapeInfos[jointIndex]; - jointShapeInfo.boneBegin = rotateMeshToJoint * (radiusScale * (boneBegin - boneEnd)); float totalWeight = 0.0f; for (int j = 0; j < cluster.indices.size(); j++) { @@ -1578,7 +1577,6 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping) } } float radiusScale = extractUniformScale(joint.transform * firstFBXCluster.inverseBindMatrix); - jointShapeInfo.boneBegin = rotateMeshToJoint * (radiusScale * (boneBegin - boneEnd)); glm::vec3 averageVertex(0.f); foreach (const glm::vec3& vertex, extracted.mesh.vertices) { @@ -1614,6 +1612,14 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping) FBXJoint& joint = geometry.joints[i]; JointShapeInfo& jointShapeInfo = jointShapeInfos[i]; + if (joint.parentIndex == -1) { + jointShapeInfo.boneBegin = glm::vec3(0.0f); + } else { + const FBXJoint& parentJoint = geometry.joints[joint.parentIndex]; + glm::quat inverseRotation = glm::inverse(extractRotation(joint.transform)); + jointShapeInfo.boneBegin = inverseRotation * (extractTranslation(parentJoint.transform) - extractTranslation(joint.transform)); + } + // we use a capsule if the joint ANY mesh vertices successfully projected onto the bone // AND its boneRadius is not too close to zero bool collideLikeCapsule = jointShapeInfo.numProjectedVertices > 0 @@ -1625,12 +1631,12 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping) joint.shapeType = Shape::CAPSULE_SHAPE; } else { // collide the joint like a sphere + joint.shapeType = Shape::SPHERE_SHAPE; if (jointShapeInfo.numVertices > 0) { jointShapeInfo.averageVertex /= (float)jointShapeInfo.numVertices; joint.shapePosition = jointShapeInfo.averageVertex; } else { joint.shapePosition = glm::vec3(0.f); - joint.shapeType = Shape::SPHERE_SHAPE; } if (jointShapeInfo.numProjectedVertices == 0 && jointShapeInfo.numVertices > 0) { @@ -1639,6 +1645,15 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping) jointShapeInfo.averageRadius /= (float)jointShapeInfo.numVertices; joint.boneRadius = jointShapeInfo.averageRadius; } + + float distanceFromEnd = glm::length(joint.shapePosition); + float distanceFromBegin = glm::distance(joint.shapePosition, jointShapeInfo.boneBegin); + if (distanceFromEnd > joint.distanceToParent && distanceFromBegin > joint.distanceToParent) { + // The shape is further from both joint endpoints than the endpoints are from each other + // which probably means the model has a bad transform somewhere. We disable this shape + // by setting its radius to zero. + joint.boneRadius = 0.0f; + } } } geometry.palmDirection = parseVec3(mapping.value("palmDirection", "0, -1, 0").toString()); diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 2d47a077b7..bcde861e84 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -510,24 +510,38 @@ void Model::rebuildShapes() { capsule->getEndPoint(endPoint); glm::vec3 startPoint; capsule->getStartPoint(startPoint); - glm::vec3 axis = (halfHeight + radius) * glm::normalize(endPoint - startPoint); + + // add some points that bound a sphere at the center of the capsule + glm::vec3 axis = glm::vec3(radius); shapeExtents.addPoint(worldPosition + axis); shapeExtents.addPoint(worldPosition - axis); + + // add the two furthest surface points of the capsule + axis = (halfHeight + radius) * glm::normalize(endPoint - startPoint); + shapeExtents.addPoint(worldPosition + axis); + shapeExtents.addPoint(worldPosition - axis); + + + totalExtents.addExtents(shapeExtents); } else { SphereShape* sphere = new SphereShape(radius, worldPosition); _jointShapes.push_back(sphere); - glm::vec3 axis = glm::vec3(radius); - shapeExtents.addPoint(worldPosition + axis); - shapeExtents.addPoint(worldPosition - axis); + if (radius > 0.0f) { + // only include sphere shapes with non-zero radius + glm::vec3 axis = glm::vec3(radius); + shapeExtents.addPoint(worldPosition + axis); + shapeExtents.addPoint(worldPosition - axis); + totalExtents.addExtents(shapeExtents); + } } - totalExtents.addExtents(shapeExtents); } // bounding shape // NOTE: we assume that the longest side of totalExtents is the yAxis glm::vec3 diagonal = totalExtents.maximum - totalExtents.minimum; - float capsuleRadius = 0.25f * (diagonal.x + diagonal.z); // half the average of x and z + // 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); _boundingShapeLocalOffset = inverseRotation * (0.5f * (totalExtents.maximum + totalExtents.minimum) - rootPosition);