fix collision shape of avatars

This commit is contained in:
Andrew Meadows 2015-09-03 18:22:35 -07:00
parent 41daea7d92
commit 16dfc39f5f
2 changed files with 22 additions and 35 deletions

View file

@ -547,14 +547,11 @@ void SkeletonModel::computeBoundingShape() {
// compute the default transform of this joint // compute the default transform of this joint
const JointState& state = _rig->getJointState(i); const JointState& state = _rig->getJointState(i);
// HACK WORKAROUND: ignore joints that may have bad translation (e.g. have been flagged as such with zero radius) // Each joint contributes a sphere at its position
if (state.getBoneRadius() > 0.0f) { glm::vec3 axis(state.getBoneRadius());
// Each joint contributes a sphere at its position glm::vec3 jointPosition = state.getPosition();
glm::vec3 axis(state.getBoneRadius()); totalExtents.addPoint(jointPosition + axis);
glm::vec3 jointPosition = state.getPosition(); totalExtents.addPoint(jointPosition - axis);
totalExtents.addPoint(jointPosition + axis);
totalExtents.addPoint(jointPosition - axis);
}
} }
// compute bounding shape parameters // compute bounding shape parameters

View file

@ -2557,6 +2557,7 @@ FBXGeometry* extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping
int maxJointIndex = firstFBXCluster.jointIndex; int maxJointIndex = firstFBXCluster.jointIndex;
glm::mat4 inverseModelTransform = glm::inverse(modelTransform); glm::mat4 inverseModelTransform = glm::inverse(modelTransform);
if (clusterIDs.size() > 1) { if (clusterIDs.size() > 1) {
// this is a multi-mesh joint
extracted.mesh.clusterIndices.resize(extracted.mesh.vertices.size()); extracted.mesh.clusterIndices.resize(extracted.mesh.vertices.size());
extracted.mesh.clusterWeights.resize(extracted.mesh.vertices.size()); extracted.mesh.clusterWeights.resize(extracted.mesh.vertices.size());
float maxWeight = 0.0f; float maxWeight = 0.0f;
@ -2640,6 +2641,7 @@ FBXGeometry* extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping
} }
} }
} else { } else {
// this is a single-mesh joint
int jointIndex = maxJointIndex; int jointIndex = maxJointIndex;
FBXJoint& joint = geometry.joints[jointIndex]; FBXJoint& joint = geometry.joints[jointIndex];
JointShapeInfo& jointShapeInfo = jointShapeInfos[jointIndex]; JointShapeInfo& jointShapeInfo = jointShapeInfos[jointIndex];
@ -2660,6 +2662,7 @@ FBXGeometry* extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping
} }
float radiusScale = extractUniformScale(joint.transform * firstFBXCluster.inverseBindMatrix); float radiusScale = extractUniformScale(joint.transform * firstFBXCluster.inverseBindMatrix);
// compute average vertex
glm::vec3 averageVertex(0.0f); glm::vec3 averageVertex(0.0f);
foreach (const glm::vec3& vertex, extracted.mesh.vertices) { foreach (const glm::vec3& vertex, extracted.mesh.vertices) {
float proj = glm::dot(boneDirection, boneEnd - vertex); float proj = glm::dot(boneDirection, boneEnd - vertex);
@ -2669,29 +2672,26 @@ FBXGeometry* extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping
++jointShapeInfo.numVertexWeights; ++jointShapeInfo.numVertexWeights;
averageVertex += vertex; averageVertex += vertex;
} }
// compute joint's radius
int numVertices = extracted.mesh.vertices.size(); int numVertices = extracted.mesh.vertices.size();
jointShapeInfo.numVertices = numVertices; jointShapeInfo.numVertices = numVertices;
if (numVertices > 0) { if (numVertices > 0) {
// compute average radius
averageVertex /= (float)jointShapeInfo.numVertices; averageVertex /= (float)jointShapeInfo.numVertices;
float averageRadius = 0.0f; float averageRadius = 0.0f;
foreach (const glm::vec3& vertex, extracted.mesh.vertices) { foreach (const glm::vec3& vertex, extracted.mesh.vertices) {
averageRadius += glm::distance(vertex, averageVertex); averageRadius += glm::distance(vertex, averageVertex);
} }
jointShapeInfo.averageRadius = averageRadius * radiusScale / (float)jointShapeInfo.numVertices; averageRadius *= radiusScale / (float)jointShapeInfo.numVertices;
// final radius is minimum of average and weighted
float weightedRadius = jointShapeInfo.sumWeightedRadii / jointShapeInfo.sumVertexWeights;
jointShapeInfo.averageRadius = glm::min(weightedRadius, averageRadius);
} }
// BUG: the boneBegin and/or boneEnd are incorrect for meshes that are "connected // clear sumVertexWeights (this flags it as a single-mesh joint for later)
// under the bone" without weights. Unfortunately we haven't been able to find it yet.
// Although the the mesh vertices are correct in the model-frame, the joint's transform
// in the same frame is just BAD.
//
// HACK WORKAROUND: prevent these shapes from contributing to the collision capsule by setting
// some key members of jointShapeInfo to zero:
jointShapeInfo.numVertices = 0;
jointShapeInfo.sumVertexWeights = 0.0f; jointShapeInfo.sumVertexWeights = 0.0f;
jointShapeInfo.numVertexWeights = 0;
jointShapeInfo.boneBegin = glm::vec3(0.0f);
jointShapeInfo.averageRadius = 0.0f;
} }
extracted.mesh.isEye = (maxJointIndex == geometry.leftEyeJointIndex || maxJointIndex == geometry.rightEyeJointIndex); extracted.mesh.isEye = (maxJointIndex == geometry.leftEyeJointIndex || maxJointIndex == geometry.rightEyeJointIndex);
@ -2727,22 +2727,12 @@ FBXGeometry* extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping
} }
if (jointShapeInfo.sumVertexWeights > 0.0f) { if (jointShapeInfo.sumVertexWeights > 0.0f) {
// mutiple meshes contributed to the bone radius and now that all
// contributing meshes are done we can finally compute the boneRadius
joint.boneRadius = jointShapeInfo.sumWeightedRadii / jointShapeInfo.sumVertexWeights; joint.boneRadius = jointShapeInfo.sumWeightedRadii / jointShapeInfo.sumVertexWeights;
} } else {
// single-mesh joint
// the joint is "capsule-like" if it had ANY mesh vertices successfully projected onto the bone joint.boneRadius = jointShapeInfo.averageRadius;
// AND its boneRadius is not too close to zero
bool collideLikeCapsule = jointShapeInfo.numVertexWeights > 0
&& glm::length(jointShapeInfo.boneBegin) > EPSILON;
if (!collideLikeCapsule) {
// this joint's mesh did not successfully project onto the bone axis
// so it isn't "capsule-like" and we need to estimate its radius a different way:
// the average radius to the average point.
if (jointShapeInfo.numVertexWeights == 0
&& jointShapeInfo.numVertices > 0) {
joint.boneRadius = jointShapeInfo.averageRadius;
}
} }
} }
geometry.palmDirection = parseVec3(mapping.value("palmDirection", "0, -1, 0").toString()); geometry.palmDirection = parseVec3(mapping.value("palmDirection", "0, -1, 0").toString());