0
我試圖在我的遊戲中實現Kasper Fauerby的碰撞檢測和響應,但我在檢測部分遇到了一些問題。多邊形湯橢圓碰撞誤報(Kasper Fauerby)
頂點和邊緣碰撞都會返回誤報,此時我並沒有將自由凸輪的速度添加到碰撞即將發生時的位置(半徑1)。
當我的下一個位置在三角形的平面上時,它看起來像頂點延伸了很多,然後它應該。但是,當我朝着頂點方向移動時,這隻會影響我。我可以平行於三角形的法線移動而不與頂點發生碰撞。
此刻,我剝了下來代碼一路的代碼Kasper provided in his paper,但這裏是我目前正在使用的代碼:
bool MeshCollider::CheckTriangleEllipsoid(glm::vec3 p1, glm::vec3 p2, glm::vec3 p3, Ellipsoid *colPackage)
{
// Make the plane containing this triangle.
Collision::PLANE trianglePlane(p1, p2, p3);
// Is triangle front-facing to the velocity vector?
// We only check front-facing triangles
// (your choice of course)
if (trianglePlane.isFrontFacingTo(
colPackage->normalizedVelocity)) {
// Get interval of plane intersection:
double t0, t1;
bool embeddedInPlane = false;
// Calculate the signed distance from sphere
// position to triangle plane
double signedDistToTrianglePlane = trianglePlane.signedDistanceTo(colPackage->ePosition);
// cache this as we’re going to use it a few times below:
float normalDotVelocity = glm::dot(trianglePlane.normal, colPackage->eVelocity);
// if sphere is travelling parrallel to the plane:
if (normalDotVelocity == 0.0f) {
if (fabs(signedDistToTrianglePlane) >= 1.0f) {
// Sphere is not embedded in plane.
// No collision possible:
return false;
}
else {
// sphere is embedded in plane.
// It intersects in the whole range [0..1]
embeddedInPlane = true;
t0 = 0.0;
t1 = 1.0;
}
}
else {
// N dot D is not 0. Calculate intersection interval:
t0 = (-1.0 - signedDistToTrianglePlane)/normalDotVelocity;
t1 = (1.0 - signedDistToTrianglePlane)/normalDotVelocity;
// Swap so t0 < t1
if (t0 > t1) {
double temp = t1;
t1 = t0;
t0 = temp;
}
// Check that at least one result is within range:
if (t0 > 1.0f || t1 < 0.0f) {
// Both t values are outside values [0,1]
// No collision possible:
return false;
}
// Clamp to [0,1]
if (t0 < 0.0) t0 = 0.0;
if (t1 < 0.0) t1 = 0.0;
if (t0 > 1.0) t0 = 1.0;
if (t1 > 1.0) t1 = 1.0;
}
// OK, at this point we have two time values t0 and t1
// between which the swept sphere intersects with the
// triangle plane. If any collision is to occur it must
// happen within this interval.
glm::vec3 collisionPoint;
bool foundCollison = false;
float t = 1.0;
// First we check for the easy case - collision inside
// the triangle. If this happens it must be at time t0
// as this is when the sphere rests on the front side
// of the triangle plane. Note, this can only happen if
// the sphere is not embedded in the triangle plane.
if(!embeddedInPlane) {
glm::vec3 planeIntersectionPoint =
(colPackage->ePosition - trianglePlane.normal)
+ (float)t0 * colPackage->eVelocity;
if (checkPointInTriangle(planeIntersectionPoint,
p1,
p2,
p3))
{
foundCollison = true;
t = t0;
collisionPoint = planeIntersectionPoint;
}
}
// if we haven’t found a collision already we’ll have to
// sweep sphere against points and edges of the triangle.
// Note: A collision inside the triangle (the check above)
// will always happen before a vertex or edge collision!
// This is why we can skip the swept test if the above
// gives a collision!
if (foundCollison == false) {
// some commonly used terms:
glm::vec3 velocity = colPackage->eVelocity;
glm::vec3 base = colPackage->ePosition;
float velocitySquaredLength = glm::length(velocity);
float a, b, c; // Params for equation
float newT;
// For each vertex or edge a quadratic equation have to
// be solved. We parameterize this equation as
// a*t^2 + b*t + c = 0 and below we calculate the
// parameters a,b and c for each test.
// Check against points:
a = velocitySquaredLength;
// P1
b = 2.0 * (glm::dot(velocity, base - p1));
c = glm::length(p1 - base) - 1.0;
if (getLowestRoot(a, b, c, t, &newT)) {
t = newT;
foundCollison = true;
collisionPoint = p1;
std::cout << "point 1\n";
}
// P2
b = 2.0 * (glm::dot(velocity, base - p2));
c = glm::length(p2 - base) - 1.0;
if (getLowestRoot(a, b, c, t, &newT)) {
t = newT;
foundCollison = true;
collisionPoint = p2;
std::cout << "point 2\n";
}
// P3
b = 2.0*(glm::dot(velocity, base - p3));
c = glm::length(p3 - base) - 1.0 ;
if (getLowestRoot(a, b, c, t, &newT)) {
t = newT;
foundCollison = true;
collisionPoint = p3;
std::cout << "point 3\n";
}
// Check agains edges:
// p1 -> p2:
glm::vec3 edge = p2 - p1;
glm::vec3 baseToVertex = p1 - base;
float edgeSquaredLength = glm::length(edge);
float edgeDotVelocity = glm::dot(edge, velocity);
float edgeDotBaseToVertex = glm::dot(edge, baseToVertex);
// Calculate parameters for equation
a = edgeSquaredLength * -velocitySquaredLength +
edgeDotVelocity*edgeDotVelocity;
b = edgeSquaredLength*(2*glm::dot(velocity, baseToVertex)) -
2.0*edgeDotVelocity*edgeDotBaseToVertex;
c = edgeSquaredLength*(1 - glm::length(baseToVertex)) +
edgeDotBaseToVertex*edgeDotBaseToVertex;
// Does the swept sphere collide against infinite edge?
if(getLowestRoot(a, b, c, t, &newT)) {
// Check if intersection is within line segment:
float f = (edgeDotVelocity*newT - edgeDotBaseToVertex)/
edgeSquaredLength;
if (f >= 0.0 && f <= 1.0) {
// intersection took place within segment.
t = newT;
foundCollison = true;
collisionPoint = p1 + f*edge;
std::cout << "p1 p2\n";
}
}
// p2 -> p3:
edge = p3 - p2;
baseToVertex = p2 - base;
edgeSquaredLength = glm::length(edge);
edgeDotVelocity = glm::dot(edge, velocity);
edgeDotBaseToVertex = glm::dot(edge, baseToVertex);
// Calculate parameters for equation
a = edgeSquaredLength * -velocitySquaredLength +
edgeDotVelocity*edgeDotVelocity;
b = edgeSquaredLength*(2*glm::dot(velocity, baseToVertex)) -
2.0*edgeDotVelocity*edgeDotBaseToVertex;
c = edgeSquaredLength*(1 - glm::length(baseToVertex)) +
edgeDotBaseToVertex*edgeDotBaseToVertex;
if (getLowestRoot(a, b, c, t, &newT)) {
float f = (edgeDotVelocity*newT - edgeDotBaseToVertex)/
edgeSquaredLength;
if (f >= 0.0 && f <= 1.0) {
t = newT;
foundCollison = true;
collisionPoint = p2 + f*edge;
std::cout << "p2 p3\n";
}
}
// p3 -> p1:
edge = p1 - p3;
baseToVertex = p3 - base;
edgeSquaredLength = glm::length(edge);
edgeDotVelocity = glm::dot(edge, velocity);
edgeDotBaseToVertex = glm::dot(edge, baseToVertex);
// Calculate parameters for equation
a = edgeSquaredLength * -velocitySquaredLength +
edgeDotVelocity*edgeDotVelocity;
b = edgeSquaredLength*(2*glm::dot(velocity, baseToVertex)) -
2.0*edgeDotVelocity*edgeDotBaseToVertex;
c = edgeSquaredLength*(1 - glm::length(baseToVertex)) +
edgeDotBaseToVertex*edgeDotBaseToVertex;
if (getLowestRoot(a, b, c, t, &newT)) {
float f = (edgeDotVelocity*newT - edgeDotBaseToVertex)/
edgeSquaredLength;
if (f >= 0.0 && f <= 1.0) {
t = newT;
foundCollison = true;
collisionPoint = p3 + f*edge;
std::cout << "p3 p1\n";
}
}
}
if (foundCollison)
std::cout << t << " t";
return foundCollison;// Exit here since I'm not using collision response yet.
// Set result:
if (foundCollison == true) {
// distance to collision: ’t’ is time of collision
float distToCollision = t * colPackage->velocity.length();
// Does this triangle qualify for the closest hit?
// it does if it’s the first hit or the closest
if (colPackage->foundCollision == false ||
distToCollision < colPackage->nearestDistance) {
// Collision information nessesary for sliding
colPackage->nearestDistance = distToCollision;
colPackage->intersectionPoint = collisionPoint;
colPackage->foundCollision = true;
}
}
} // if not backface
return false;
}
我假設在文件中提供的代碼實際上有效。人們似乎在Kasper的論文中取得了成功。不幸的不是我。
到目前爲止,我已經試過是:
- 再審現在執行它兩次(如果我的地方犯了一個錯誤)。
- 嘗試了碰撞檢測的單獨部分,找出造成問題的原因。
現在我只是出於想法,一切似乎都對我正確,但它仍然給我誤報。