use kDop volume of avatar mesh parts for capsule

This commit is contained in:
Andrew Meadows 2015-11-18 09:21:04 -08:00
parent 9c29ba2ca3
commit ee751ed1b9
3 changed files with 38 additions and 58 deletions

View file

@ -625,19 +625,15 @@ void SkeletonModel::computeBoundingShape() {
totalExtents.addPoint(glm::vec3(0.0f));
int numStates = _rig->getJointStateCount();
for (int i = 0; i < numStates; i++) {
const JointState& state = _rig->getJointState(i);
const glm::mat4& jointTransform = state.getTransform();
float scale = extractUniformScale(jointTransform);
// Each joint contributes a capsule defined by FBXJoint.shapeInfo.
// For totalExtents we use the capsule endpoints expanded by the radius.
const JointState& state = _rig->getJointState(i);
const glm::mat4& jointTransform = state.getTransform();
const FBXJointShapeInfo& shapeInfo = geometry.joints.at(i).shapeInfo;
for (int j = 0; j < shapeInfo.points.size(); ++j) {
glm::vec3 transformedPoint = extractTranslation(jointTransform * glm::translate(shapeInfo.points[j]));
vec3 radius(scale * shapeInfo.radius);
totalExtents.addPoint(transformedPoint + radius);
totalExtents.addPoint(transformedPoint - radius);
if (shapeInfo.points.size() > 0) {
for (int j = 0; j < shapeInfo.points.size(); ++j) {
totalExtents.addPoint(extractTranslation(jointTransform * glm::translate(shapeInfo.points[j])));
}
}
// HACK so that default legless robot doesn't knuckle-drag
if (shapeInfo.points.size() == 0 && (state.getName() == "LeftFoot" || state.getName() == "RightFoot")) {

View file

@ -1460,7 +1460,7 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
it != extracted.newIndices.end() && it.key() == oldIndex; it++) {
// remember vertices with at least 1/4 weight
const float EXPANSION_WEIGHT_THRESHOLD = 0.25f;
const float EXPANSION_WEIGHT_THRESHOLD = 0.99f;
if (weight > EXPANSION_WEIGHT_THRESHOLD) {
// transform to joint-frame and save for later
const glm::mat4 vertexTransform = meshToJoint * glm::translate(extracted.mesh.vertices.at(it.value()));
@ -1535,63 +1535,48 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
meshIDsToMeshIndices.insert(it.key(), meshIndex);
}
// now that all joints have been scanned, compute a radius for each bone
ShapeVertices cardinalDirections;
cardinalDirections.push_back(Vectors::UNIT_X);
cardinalDirections.push_back(Vectors::UNIT_Y);
cardinalDirections.push_back(Vectors::UNIT_Z);
const float INV_SQRT_3 = 0.57735026918f;
cardinalDirections.push_back(glm::vec3(INV_SQRT_3, INV_SQRT_3, INV_SQRT_3));
cardinalDirections.push_back(glm::vec3(INV_SQRT_3, -INV_SQRT_3, INV_SQRT_3));
cardinalDirections.push_back(glm::vec3(INV_SQRT_3, INV_SQRT_3, -INV_SQRT_3));
cardinalDirections.push_back(glm::vec3(INV_SQRT_3, -INV_SQRT_3, -INV_SQRT_3));
// now that all joints have been scanned compute a k-Dop bounding volume of mesh
glm::vec3 defaultCapsuleAxis(0.0f, 1.0f, 0.0f);
for (int i = 0; i < geometry.joints.size(); ++i) {
FBXJoint& joint = geometry.joints[i];
// NOTE: points are in joint-frame
// compute average point
ShapeVertices& points = shapeVertices[i];
glm::vec3 avgPoint = glm::vec3(0.0f);
for (uint32_t j = 0; j < points.size(); ++j) {
avgPoint += points[j];
}
avgPoint /= (float)points.size();
// compute axis from begin to avgPoint
glm::vec3 begin(0.0f);
glm::vec3 end = avgPoint;
glm::vec3 axis = end - begin;
float axisLength = glm::length(axis);
if (axisLength > EPSILON) {
axis /= axisLength;
} else {
axis = glm::vec3(0.0f);
}
// measure average cylindrical radius
float avgRadius = 0.0f;
if (points.size() > 0) {
float minProjection = FLT_MAX;
float maxProjection = -FLT_MIN;
// compute average point
glm::vec3 avgPoint = glm::vec3(0.0f);
for (uint32_t j = 0; j < points.size(); ++j) {
glm::vec3 offset = points[j] - avgPoint;
float projection = glm::dot(offset, axis);
maxProjection = glm::max(maxProjection, projection);
minProjection = glm::min(minProjection, projection);
avgRadius += glm::length(offset - projection * axis);
avgPoint += points[j];
}
avgRadius /= (float)points.size();
// compute endpoints of capsule in joint-frame
glm::vec3 capsuleBegin = avgPoint;
glm::vec3 capsuleEnd = avgPoint;
if (maxProjection - minProjection < 2.0f * avgRadius) {
// the mesh-as-cylinder approximation is too short to collide as a capsule
// so we'll collapse it to a sphere (although that isn't a very good approximation)
capsuleBegin = avgPoint + 0.5f * (maxProjection + minProjection) * axis;
capsuleEnd = capsuleBegin;
} else {
capsuleBegin = avgPoint + (minProjection + avgRadius) * axis;
capsuleEnd = avgPoint + (maxProjection - avgRadius) * axis;
avgPoint /= (float)points.size();
// compute a k-Dop bounding volume
for (uint32_t j = 0; j < cardinalDirections.size(); ++j) {
float maxDot = -FLT_MAX;
float minDot = FLT_MIN;
for (uint32_t k = 0; k < points.size(); ++k) {
float kDot = glm::dot(cardinalDirections[j], points[k] - avgPoint);
if (kDot > maxDot) {
maxDot = kDot;
}
if (kDot < minDot) {
minDot = kDot;
}
}
joint.shapeInfo.points.push_back(avgPoint + maxDot * cardinalDirections[j]);
joint.shapeInfo.points.push_back(avgPoint + minDot * cardinalDirections[j]);
}
// save points for later
joint.shapeInfo.points.push_back(capsuleBegin);
joint.shapeInfo.points.push_back(capsuleEnd);
}
joint.shapeInfo.radius = avgRadius;
}
geometry.palmDirection = parseVec3(mapping.value("palmDirection", "0, -1, 0").toString());

View file

@ -56,7 +56,6 @@ public:
struct FBXJointShapeInfo {
// same units and frame as FBXJoint.translation
QVector<glm::vec3> points;
float radius;
};
/// A single joint (transformation node) extracted from an FBX document.