mirror of
https://github.com/overte-org/overte.git
synced 2025-04-22 20:53:33 +02:00
Merge pull request #6417 from AndrewMeadows/avatar-capsule
fix bounding capusule calculations for new avatars
This commit is contained in:
commit
d3d3ddfaf1
4 changed files with 41 additions and 60 deletions
|
@ -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")) {
|
||||
|
@ -668,7 +664,7 @@ void SkeletonModel::renderBoundingCollisionShapes(gpu::Batch& batch, float alpha
|
|||
// draw a blue sphere at the capsule top point
|
||||
glm::vec3 topPoint = _translation + _boundingCapsuleLocalOffset + (0.5f * _boundingCapsuleHeight) * glm::vec3(0.0f, 1.0f, 0.0f);
|
||||
|
||||
deferredLighting->renderSolidSphereInstance(batch,
|
||||
deferredLighting->renderSolidSphereInstance(batch,
|
||||
Transform().setTranslation(topPoint).postScale(_boundingCapsuleRadius),
|
||||
glm::vec4(0.6f, 0.6f, 0.8f, alpha));
|
||||
|
||||
|
@ -676,7 +672,7 @@ void SkeletonModel::renderBoundingCollisionShapes(gpu::Batch& batch, float alpha
|
|||
glm::vec3 bottomPoint = topPoint - glm::vec3(0.0f, _boundingCapsuleHeight, 0.0f);
|
||||
glm::vec3 axis = topPoint - bottomPoint;
|
||||
|
||||
deferredLighting->renderSolidSphereInstance(batch,
|
||||
deferredLighting->renderSolidSphereInstance(batch,
|
||||
Transform().setTranslation(bottomPoint).postScale(_boundingCapsuleRadius),
|
||||
glm::vec4(0.8f, 0.8f, 0.6f, alpha));
|
||||
|
||||
|
|
|
@ -82,7 +82,7 @@ public:
|
|||
bool getNeckPosition(glm::vec3& neckPosition) const;
|
||||
|
||||
bool getLocalNeckPosition(glm::vec3& neckPosition) const;
|
||||
|
||||
|
||||
/// Returns the rotation of the neck joint's parent from default orientation
|
||||
/// \return whether or not the neck was found
|
||||
bool getNeckParentRotationFromDefaultOrientation(glm::quat& neckParentRotation) const;
|
||||
|
|
|
@ -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,49 @@ 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
|
||||
const float INV_SQRT_3 = 0.57735026918f;
|
||||
ShapeVertices cardinalDirections = {
|
||||
Vectors::UNIT_X,
|
||||
Vectors::UNIT_Y,
|
||||
Vectors::UNIT_Z,
|
||||
glm::vec3(INV_SQRT_3, INV_SQRT_3, INV_SQRT_3),
|
||||
glm::vec3(INV_SQRT_3, -INV_SQRT_3, INV_SQRT_3),
|
||||
glm::vec3(INV_SQRT_3, INV_SQRT_3, -INV_SQRT_3),
|
||||
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();
|
||||
avgPoint /= (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;
|
||||
// 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());
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
Loading…
Reference in a new issue