more correct bounding shapes for Models

This commit is contained in:
Andrew Meadows 2014-04-18 11:19:21 -07:00
parent cfdbdad2d8
commit 26487aad06

View file

@ -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<glm::mat4> transforms;
transforms.fill(glm::mat4(), numJoints);
QVector<glm::quat> combinedRotations;
combinedRotations.fill(glm::quat(), numJoints);
QVector<bool> 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);
}
}