From 26487aad0682f0a1c845fcce0467ad2685f67b9e Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 18 Apr 2014 11:19:21 -0700 Subject: [PATCH] more correct bounding shapes for Models --- interface/src/renderer/Model.cpp | 78 ++++++++++++++++++++++---------- 1 file changed, 54 insertions(+), 24 deletions(-) diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index ca0b46841d..f8de7210ea 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -60,11 +60,11 @@ Model::SkinLocations Model::_skinNormalMapLocations; Model::SkinLocations Model::_skinShadowLocations; void Model::setScale(const glm::vec3& scale) { - glm::vec3 deltaScale = _scale - scale; + float scaleLength = glm::length(_scale); + float relativeDeltaScale = glm::length(_scale - scale) / scaleLength; - // decreased epsilon because this wasn't handling scale changes of 0.01 - const float SMALLER_EPSILON = EPSILON * 0.0001f; - if (glm::length2(deltaScale) > SMALLER_EPSILON) { + const float ONE_PERCENT = 0.01f; + if (relativeDeltaScale > ONE_PERCENT || scaleLength < EPSILON) { _scale = scale; rebuildShapes(); } @@ -468,20 +468,51 @@ void Model::clearShapes() { void Model::rebuildShapes() { clearShapes(); + const FBXGeometry& geometry = _geometry->getFBXGeometry(); - if (_jointStates.isEmpty()) { + if (geometry.joints.isEmpty()) { return; } - // make sure all the joints are updated correctly before we try to create their shapes - for (int i = 0; i < _jointStates.size(); i++) { - updateJointState(i); - } - - const FBXGeometry& geometry = _geometry->getFBXGeometry(); + int numJoints = geometry.joints.size(); + QVector transforms; + transforms.fill(glm::mat4(), numJoints); + QVector combinedRotations; + combinedRotations.fill(glm::quat(), numJoints); + QVector shapeIsSet; + shapeIsSet.fill(false, numJoints); + int rootIndex = 0; + float uniformScale = extractUniformScale(_scale); - glm::quat inverseRotation = glm::inverse(_rotation); - glm::vec3 rootPosition(0.f); + int numShapesSet = 0; + int lastNumShapesSet = -1; + while (numShapesSet < numJoints && numShapesSet != lastNumShapesSet) { + lastNumShapesSet = numShapesSet; + for (int i = 0; i < numJoints; ++i) { + if (shapeIsSet[i]) { + continue; + } + const FBXJoint& joint = geometry.joints[i]; + int parentIndex = joint.parentIndex; + if (parentIndex == -1) { + rootIndex = i; + glm::mat4 baseTransform = glm::mat4_cast(_rotation) * uniformScale * glm::translate(_offset); + glm::quat combinedRotation = joint.preRotation * joint.rotation * joint.postRotation; + transforms[i] = baseTransform * geometry.offset * glm::translate(joint.translation) * joint.preTransform * + glm::mat4_cast(combinedRotation) * joint.postTransform; + combinedRotations[i] = _rotation * combinedRotation; + ++numShapesSet; + shapeIsSet[i] = true; + } else if (shapeIsSet[parentIndex]) { + glm::quat combinedRotation = joint.preRotation * joint.rotation * joint.postRotation; + transforms[i] = transforms[parentIndex] * glm::translate(joint.translation) * joint.preTransform * + glm::mat4_cast(combinedRotation) * joint.postTransform; + combinedRotations[i] = combinedRotations[parentIndex] * combinedRotation; + ++numShapesSet; + shapeIsSet[i] = true; + } + } + } // joint shapes Extents totalExtents; @@ -489,15 +520,10 @@ void Model::rebuildShapes() { for (int i = 0; i < _jointStates.size(); i++) { const FBXJoint& joint = geometry.joints[i]; - glm::vec3 jointToShapeOffset = uniformScale * (_jointStates[i].combinedRotation * joint.shapePosition); - glm::vec3 worldPosition = extractTranslation(_jointStates[i].transform) + jointToShapeOffset + _translation; + glm::vec3 worldPosition = extractTranslation(transforms[i]); Extents shapeExtents; shapeExtents.reset(); - if (joint.parentIndex == -1) { - rootPosition = worldPosition; - } - float radius = uniformScale * joint.boneRadius; float halfHeight = 0.5f * uniformScale * joint.distanceToParent; Shape::Type type = joint.shapeType; @@ -508,7 +534,7 @@ void Model::rebuildShapes() { if (type == Shape::CAPSULE_SHAPE) { CapsuleShape* capsule = new CapsuleShape(radius, halfHeight); capsule->setPosition(worldPosition); - capsule->setRotation(_jointStates[i].combinedRotation * joint.shapeRotation); + capsule->setRotation(combinedRotations[i] * joint.shapeRotation); _jointShapes.push_back(capsule); glm::vec3 endPoint; @@ -526,7 +552,6 @@ void Model::rebuildShapes() { shapeExtents.addPoint(worldPosition + axis); shapeExtents.addPoint(worldPosition - axis); - totalExtents.addExtents(shapeExtents); } else if (type == Shape::SPHERE_SHAPE) { SphereShape* sphere = new SphereShape(radius, worldPosition); @@ -539,12 +564,11 @@ void Model::rebuildShapes() { } else { // this shape type is not handled and the joint shouldn't collide, // however we must have a shape for each joint, - // so we make a bogus sphere and put it at the center of the model + // so we make a bogus sphere with zero radius. // TODO: implement collision groups for more control over what collides with what - SphereShape* sphere = new SphereShape(0.f, _offset); + SphereShape* sphere = new SphereShape(0.f, worldPosition); _jointShapes.push_back(sphere); } - } // bounding shape @@ -554,7 +578,12 @@ void Model::rebuildShapes() { 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::quat inverseRotation = glm::inverse(_rotation); + glm::vec3 rootPosition = extractTranslation(transforms[rootIndex]); _boundingShapeLocalOffset = inverseRotation * (0.5f * (totalExtents.maximum + totalExtents.minimum) - rootPosition); + _boundingShape.setPosition(_translation - _rotation * _boundingShapeLocalOffset); + _boundingShape.setRotation(_rotation); } void Model::updateShapePositions() { @@ -581,6 +610,7 @@ void Model::updateShapePositions() { _boundingRadius = sqrtf(_boundingRadius); _shapesAreDirty = false; _boundingShape.setPosition(rootPosition + _rotation * _boundingShapeLocalOffset); + _boundingShape.setRotation(_rotation); } }