mirror of
https://github.com/overte-org/overte.git
synced 2025-08-08 18:16:45 +02:00
capsule projection and distance tests now work for non-vertical capsules
This commit is contained in:
parent
9567ec11af
commit
f4c4b3474b
4 changed files with 39 additions and 37 deletions
|
@ -2300,16 +2300,11 @@ void MyAvatar::FollowHelper::prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat
|
||||||
}
|
}
|
||||||
|
|
||||||
void MyAvatar::FollowHelper::postPhysicsUpdate(MyAvatar& myAvatar) {
|
void MyAvatar::FollowHelper::postPhysicsUpdate(MyAvatar& myAvatar) {
|
||||||
|
|
||||||
// get HMD position from sensor space into world space, and back into rig space
|
|
||||||
glm::mat4 worldHMDMat = myAvatar.getSensorToWorldMatrix() * myAvatar.getHMDSensorMatrix();
|
glm::mat4 worldHMDMat = myAvatar.getSensorToWorldMatrix() * myAvatar.getHMDSensorMatrix();
|
||||||
glm::mat4 rigToWorld = createMatFromQuatAndPos(myAvatar.getRotation() * Quaternions::Y_180, myAvatar.getPosition());
|
glm::vec3 worldHMDPosition = extractTranslation(worldHMDMat);
|
||||||
glm::mat4 worldToRig = glm::inverse(rigToWorld);
|
glm::vec3 capsuleStart = myAvatar.getPosition() + Vectors::UNIT_Y * (TRUNCATE_IK_CAPSULE_LENGTH / 2.0f);
|
||||||
glm::mat4 rigHMDMat = worldToRig * worldHMDMat;
|
glm::vec3 capsuleEnd = myAvatar.getPosition() - Vectors::UNIT_Y * (TRUNCATE_IK_CAPSULE_LENGTH / 2.0f);
|
||||||
glm::vec3 rigHMDPosition = extractTranslation(rigHMDMat);
|
_isOutOfBody = !pointIsInsideCapsule(worldHMDPosition, capsuleStart, capsuleEnd, TRUNCATE_IK_CAPSULE_RADIUS);
|
||||||
|
|
||||||
// detect if the rig head position is too far from the avatar's position.
|
|
||||||
_isOutOfBody = !pointIsInsideCapsule(rigHMDPosition, TRUNCATE_IK_CAPSULE_POSITION, TRUNCATE_IK_CAPSULE_LENGTH, TRUNCATE_IK_CAPSULE_RADIUS);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
float MyAvatar::getAccelerationEnergy() {
|
float MyAvatar::getAccelerationEnergy() {
|
||||||
|
|
|
@ -124,10 +124,12 @@ void SkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) {
|
||||||
|
|
||||||
hmdPositionInRigSpace = extractTranslation(rigHMDMat);
|
hmdPositionInRigSpace = extractTranslation(rigHMDMat);
|
||||||
|
|
||||||
|
glm::vec3 capsuleStart = Vectors::UNIT_Y * (TRUNCATE_IK_CAPSULE_LENGTH / 2.0f);
|
||||||
|
glm::vec3 capsuleEnd = -Vectors::UNIT_Y * (TRUNCATE_IK_CAPSULE_LENGTH / 2.0f);
|
||||||
|
|
||||||
// truncate head IK target if it's out of body
|
// truncate head IK target if it's out of body
|
||||||
if (myAvatar->isOutOfBody()) {
|
if (myAvatar->isOutOfBody()) {
|
||||||
truncatedHMDPositionInRigSpace = projectPointOntoCapsule(hmdPositionInRigSpace, TRUNCATE_IK_CAPSULE_POSITION,
|
truncatedHMDPositionInRigSpace = projectPointOntoCapsule(hmdPositionInRigSpace, capsuleStart, capsuleEnd, TRUNCATE_IK_CAPSULE_RADIUS);
|
||||||
TRUNCATE_IK_CAPSULE_LENGTH, TRUNCATE_IK_CAPSULE_RADIUS);
|
|
||||||
} else {
|
} else {
|
||||||
truncatedHMDPositionInRigSpace = hmdPositionInRigSpace;
|
truncatedHMDPositionInRigSpace = hmdPositionInRigSpace;
|
||||||
}
|
}
|
||||||
|
|
|
@ -579,33 +579,37 @@ float coneSphereAngle(const glm::vec3& coneCenter, const glm::vec3& coneDirectio
|
||||||
return glm::max(0.0f, theta - phi);
|
return glm::max(0.0f, theta - phi);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool pointIsInsideCapsule(const glm::vec3& point, const glm::vec3& capsulePosition, float capsuleLength, float capsuleRadius) {
|
glm::vec3 nearestPointOnLineSegment(const glm::vec3& point, const glm::vec3& segmentStart, const glm::vec3& segmentEnd) {
|
||||||
glm::vec3 top = capsulePosition.y + glm::vec3(0.0f, capsuleLength / 2.0f, 0.0f);
|
glm::vec3 n = segmentEnd - segmentStart;
|
||||||
glm::vec3 bottom = capsulePosition.y - glm::vec3(0.0f, capsuleLength / 2.0f, 0.0f);
|
float len = glm::length(n);
|
||||||
if (point.y > top.y + capsuleRadius) {
|
if (len < EPSILON) {
|
||||||
return false;
|
return segmentStart;
|
||||||
} else if (point.y > top.y) {
|
|
||||||
return glm::length(point - top) < capsuleRadius;
|
|
||||||
} else if (point.y < bottom.y - capsuleRadius) {
|
|
||||||
return false;
|
|
||||||
} else if (point.y < bottom.y) {
|
|
||||||
return glm::length(point - bottom) < capsuleRadius;
|
|
||||||
} else {
|
} else {
|
||||||
return glm::length(glm::vec2(point.x, point.z) - glm::vec2(capsulePosition.x, capsulePosition.z)) < capsuleRadius;
|
n /= len;
|
||||||
|
float projection = glm::dot(point - segmentStart, n);
|
||||||
|
projection = glm::clamp(projection, 0.0f, len);
|
||||||
|
return segmentStart + n * projection;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::vec3 projectPointOntoCapsule(const glm::vec3& point, const glm::vec3& capsulePosition, float capsuleLength, float capsuleRadius) {
|
float distanceFromLineSegment(const glm::vec3& point, const glm::vec3& segmentStart, const glm::vec3& segmentEnd) {
|
||||||
glm::vec3 top = capsulePosition.y + glm::vec3(0.0f, capsuleLength / 2.0f, 0.0f);
|
return glm::length(point - nearestPointOnLineSegment(point, segmentStart, segmentEnd));
|
||||||
glm::vec3 bottom = capsulePosition.y - glm::vec3(0.0f, capsuleLength / 2.0f, 0.0f);
|
}
|
||||||
if (point.y > top.y) {
|
|
||||||
return capsuleRadius * glm::normalize(point - top) + top;
|
bool pointIsInsideCapsule(const glm::vec3& point, const glm::vec3& capsuleStart, const glm::vec3& capsuleEnd, float capsuleRadius) {
|
||||||
} else if (point.y < bottom.y) {
|
return distanceFromLineSegment(point, capsuleStart, capsuleEnd) < capsuleRadius;
|
||||||
return capsuleRadius * glm::normalize(point - bottom) + bottom;
|
}
|
||||||
|
|
||||||
|
glm::vec3 projectPointOntoCapsule(const glm::vec3& point, const glm::vec3& capsuleStart, const glm::vec3& capsuleEnd, float capsuleRadius) {
|
||||||
|
glm::vec3 nearestPoint = nearestPointOnLineSegment(point, capsuleStart, capsuleEnd);
|
||||||
|
glm::vec3 d = point - nearestPoint;
|
||||||
|
float dLen = glm::length(d);
|
||||||
|
if (dLen > EPSILON) {
|
||||||
|
return nearestPoint; // TODO: maybe we should pick a point actually on the surface...
|
||||||
} else {
|
} else {
|
||||||
glm::vec2 capsulePosition2D(capsulePosition.x, capsulePosition.z);
|
return nearestPoint + d * (capsuleRadius / dLen);
|
||||||
glm::vec2 point2D(point.x, point.z);
|
|
||||||
glm::vec2 projectedPoint2D = capsuleRadius * glm::normalize(point2D - capsulePosition2D) + capsulePosition2D;
|
|
||||||
return glm::vec3(projectedPoint2D.x, point.y, projectedPoint2D.y);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -160,8 +160,9 @@ private:
|
||||||
static void copyCleanArray(int& lengthA, glm::vec2* vertexArrayA, int& lengthB, glm::vec2* vertexArrayB);
|
static void copyCleanArray(int& lengthA, glm::vec2* vertexArrayA, int& lengthB, glm::vec2* vertexArrayB);
|
||||||
};
|
};
|
||||||
|
|
||||||
// vertical capsule
|
glm::vec3 nearestPointOnLineSegment(const glm::vec3& point, const glm::vec3& segmentStart, const glm::vec3& segmentEnd);
|
||||||
bool pointIsInsideCapsule(const glm::vec3& point, const glm::vec3& capsulePosition, float capsuleLength, float capsuleRadius);
|
float distanceFromLineSegment(const glm::vec3& point, const glm::vec3& segmentStart, const glm::vec3& segmentEnd);
|
||||||
glm::vec3 projectPointOntoCapsule(const glm::vec3& point, const glm::vec3& capsulePosition, float capsuleLength, float capsuleRadius);
|
bool pointIsInsideCapsule(const glm::vec3& point, const glm::vec3& capsuleStart, const glm::vec3& capsuleEnd, float capsuleRadius);
|
||||||
|
glm::vec3 projectPointOntoCapsule(const glm::vec3& point, const glm::vec3& capsuleStart, const glm::vec3& capsuleEnd, float capsuleRadius);
|
||||||
|
|
||||||
#endif // hifi_GeometryUtil_h
|
#endif // hifi_GeometryUtil_h
|
||||||
|
|
Loading…
Reference in a new issue