diff --git a/interface/src/Util.cpp b/interface/src/Util.cpp index 779ae5736b..a5c12b3edc 100644 --- a/interface/src/Util.cpp +++ b/interface/src/Util.cpp @@ -224,6 +224,15 @@ glm::quat extractRotation(const glm::mat4& matrix, bool assumeOrthogonal) { 0.5f * sqrtf(z2) * (upper[0][1] >= upper[1][0] ? 1.0f : -1.0f))); } +glm::vec3 extractScale(const glm::mat4& matrix) { + return glm::vec3(glm::length(matrix[0]), glm::length(matrix[1]), glm::length(matrix[2])); +} + +float extractUniformScale(const glm::mat4& matrix) { + glm::vec3 scale = extractScale(matrix); + return (scale.x + scale.y + scale.z) / 3.0f; +} + // Draw a 3D vector floating in space void drawVector(glm::vec3 * vector) { glDisable(GL_LIGHTING); diff --git a/interface/src/Util.h b/interface/src/Util.h index ec410429db..b80731bd20 100644 --- a/interface/src/Util.h +++ b/interface/src/Util.h @@ -61,6 +61,10 @@ void setTranslation(glm::mat4& matrix, const glm::vec3& translation); glm::quat extractRotation(const glm::mat4& matrix, bool assumeOrthogonal = false); +glm::vec3 extractScale(const glm::mat4& matrix); + +float extractUniformScale(const glm::mat4& matrix); + double diffclock(timeval *clock1,timeval *clock2); void renderMouseVoxelGrid(const float& mouseVoxelX, const float& mouseVoxelY, const float& mouseVoxelZ, const float& mouseVoxelS); diff --git a/interface/src/renderer/FBXReader.cpp b/interface/src/renderer/FBXReader.cpp index e841780975..ad44bf2da6 100644 --- a/interface/src/renderer/FBXReader.cpp +++ b/interface/src/renderer/FBXReader.cpp @@ -20,6 +20,7 @@ #include +#include #include #include "FBXReader.h" @@ -1142,6 +1143,7 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping) joint.distanceToParent = glm::distance(extractTranslation(parentJoint.transform), extractTranslation(joint.transform)); } + joint.boneRadius = 0.0f; joint.inverseBindRotation = joint.inverseDefaultRotation; geometry.joints.append(joint); geometry.jointIndices.insert(model.name, geometry.joints.size() - 1); @@ -1274,7 +1276,9 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping) } // whether we're skinned depends on how many clusters are attached - int maxJointIndex = extracted.mesh.clusters.at(0).jointIndex; + const FBXCluster& firstFBXCluster = extracted.mesh.clusters.at(0); + int maxJointIndex = firstFBXCluster.jointIndex; + glm::mat4 inverseModelTransform = glm::inverse(modelTransform); if (clusterIDs.size() > 1) { extracted.mesh.clusterIndices.resize(extracted.mesh.vertices.size()); extracted.mesh.clusterWeights.resize(extracted.mesh.vertices.size()); @@ -1282,6 +1286,21 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping) for (int i = 0; i < clusterIDs.size(); i++) { QString clusterID = clusterIDs.at(i); const Cluster& cluster = clusters[clusterID]; + const FBXCluster& fbxCluster = extracted.mesh.clusters.at(i); + int jointIndex = fbxCluster.jointIndex; + FBXJoint& joint = geometry.joints[jointIndex]; + glm::vec3 boneEnd = extractTranslation(inverseModelTransform * joint.bindTransform); + glm::vec3 boneDirection; + float boneLength; + if (joint.parentIndex != -1) { + boneDirection = boneEnd - extractTranslation(inverseModelTransform * + geometry.joints[joint.parentIndex].bindTransform); + boneLength = glm::length(boneDirection); + if (boneLength > EPSILON) { + boneDirection /= boneLength; + } + } + float radiusScale = extractUniformScale(joint.transform * fbxCluster.inverseBindMatrix); float totalWeight = 0.0f; for (int j = 0; j < cluster.indices.size(); j++) { int oldIndex = cluster.indices.at(j); @@ -1289,9 +1308,18 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping) totalWeight += weight; for (QMultiHash::const_iterator it = extracted.newIndices.constFind(oldIndex); it != extracted.newIndices.end() && it.key() == oldIndex; it++) { - glm::vec4& weights = extracted.mesh.clusterWeights[it.value()]; - + // expand the bone radius + if (weight > 0.25f) { + const glm::vec3& vertex = extracted.mesh.vertices.at(it.value()); + float proj = glm::dot(boneDirection, vertex - boneEnd); + if (proj < 0.0f && proj > -boneLength) { + joint.boneRadius = glm::max(joint.boneRadius, radiusScale * glm::distance( + vertex, boneEnd + boneDirection * proj)); + } } + + // look for an unused slot in the weights vector + glm::vec4& weights = extracted.mesh.clusterWeights[it.value()]; for (int k = 0; k < 4; k++) { if (weights[k] == 0.0f) { extracted.mesh.clusterIndices[it.value()][k] = i; @@ -1303,9 +1331,23 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping) } if (totalWeight > maxWeight) { maxWeight = totalWeight; - maxJointIndex = extracted.mesh.clusters.at(i).jointIndex; + maxJointIndex = jointIndex; } } + } else { + int jointIndex = maxJointIndex; + FBXJoint& joint = geometry.joints[jointIndex]; + glm::vec3 boneEnd = extractTranslation(inverseModelTransform * joint.bindTransform); + glm::vec3 boneStart = boneEnd; + if (joint.parentIndex != -1) { + boneStart = extractTranslation(inverseModelTransform * geometry.joints[joint.parentIndex].bindTransform); + } + float radiusScale = extractUniformScale(joint.transform * firstFBXCluster.inverseBindMatrix); + foreach (const glm::vec3& vertex, extracted.mesh.vertices) { + // expand the bone radius + joint.boneRadius = glm::max(joint.boneRadius, radiusScale * glm::length( + computeVectorFromPointToSegment(vertex, boneStart, boneEnd))); + } } extracted.mesh.isEye = (maxJointIndex == geometry.leftEyeJointIndex || maxJointIndex == geometry.rightEyeJointIndex); diff --git a/interface/src/renderer/FBXReader.h b/interface/src/renderer/FBXReader.h index eb454f7566..6cc08a1549 100644 --- a/interface/src/renderer/FBXReader.h +++ b/interface/src/renderer/FBXReader.h @@ -47,6 +47,7 @@ public: QVector freeLineage; int parentIndex; float distanceToParent; + float boneRadius; glm::mat4 preTransform; glm::quat preRotation; glm::quat rotation;