WIP, should take shortest resolution even if forced upwards because of slopes, not solving the jittering problem though. + debug code.
This commit is contained in:
@@ -380,11 +380,11 @@ bool AABBvsTriangle(const AABB& box,
|
||||
|
||||
enum BoxTriResolveCase
|
||||
{
|
||||
ResolveDimX,
|
||||
ResolveDimY,
|
||||
ResolveDimZ,
|
||||
Line, //Box edge colliding with triangle line.
|
||||
Corner //Box corner colliding with the triangle face.
|
||||
EResolveDimX,
|
||||
EResolveDimY,
|
||||
EResolveDimZ,
|
||||
ELine, //Box edge colliding with triangle line.
|
||||
ECorner //Box corner colliding with the triangle face.
|
||||
};
|
||||
struct Resolution
|
||||
{
|
||||
@@ -396,10 +396,55 @@ bool AABBvsTriangle(const AABB& box,
|
||||
float DistanceSq;
|
||||
glm::vec3 Vector;
|
||||
};
|
||||
struct CaseResolutions
|
||||
{
|
||||
Resolution Vertex;
|
||||
Resolution Line;
|
||||
Resolution Corner;
|
||||
Resolution* Shortest = &Vertex;
|
||||
|
||||
void AddResolution(BoxTriResolveCase resCase, float distanceSq, const glm::vec3& resVec)
|
||||
{
|
||||
switch (resCase) {
|
||||
case EResolveDimY:
|
||||
case EResolveDimX:
|
||||
case EResolveDimZ:
|
||||
if (distanceSq < Vertex.DistanceSq) {
|
||||
Vertex.Vector = resVec;
|
||||
Vertex.DistanceSq = distanceSq;
|
||||
Vertex.Case = resCase;
|
||||
if (distanceSq < Line.DistanceSq) {
|
||||
Shortest = &Vertex;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ELine:
|
||||
if (distanceSq < Vertex.DistanceSq && distanceSq < Line.DistanceSq) {
|
||||
Line.Vector = resVec;
|
||||
Line.DistanceSq = distanceSq;
|
||||
Line.Case = resCase;
|
||||
Shortest = &Line;
|
||||
}
|
||||
break;
|
||||
case ECorner:
|
||||
//NOTE: It is assumed that the Corner is less than the
|
||||
//added resolution, since only one corner should be added per triangle.
|
||||
if (distanceSq < Vertex.DistanceSq && distanceSq < Line.DistanceSq) {
|
||||
Corner.Vector = resVec;
|
||||
Corner.DistanceSq = distanceSq;
|
||||
Corner.Case = resCase;
|
||||
Shortest = &Corner;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
//The smallest resolution that solves the collision.
|
||||
Resolution resolveShortest;
|
||||
CaseResolutions resolveShortest;
|
||||
//The smallest resolution that solves the collision, that resolves upwards.
|
||||
Resolution resolveUpwards;
|
||||
CaseResolutions resolveUpwards;
|
||||
//If player stands on the ground and collides with a ground triangle,
|
||||
//we might step up onto it if the step is small enough.
|
||||
bool canStairStepUp = isOnGround && FaceIsGround(triNormal.y);
|
||||
@@ -421,34 +466,27 @@ bool AABBvsTriangle(const AABB& box,
|
||||
//Project box.
|
||||
glm::vec2 boxMin(min[dim.first], min[dim.second]);
|
||||
glm::vec2 boxMax(max[dim.first], max[dim.second]);
|
||||
glm::vec2 resolutionVector;
|
||||
float resolutionDist;
|
||||
glm::vec2 resolutionVector2D;
|
||||
float resolutionDistSq;
|
||||
bool pushedFromTriangleLine;
|
||||
//if projections don't overlap, return false.
|
||||
if (!rectangleVsTriangle(boxMin, boxMax, t2D, resolutionVector, resolutionDist, pushedFromTriangleLine)) {
|
||||
if (!rectangleVsTriangle(boxMin, boxMax, t2D, resolutionVector2D, resolutionDistSq, pushedFromTriangleLine)) {
|
||||
return false;
|
||||
} else if (resolveCollision) {
|
||||
glm::vec3 resolve3D = glm::vec3(0.f);
|
||||
resolve3D[dim.first] = resolutionVector2D.x;
|
||||
resolve3D[dim.second] = resolutionVector2D.y;
|
||||
//If we pushed away from triangle line (edge), or if we
|
||||
//move the player along one coordinate axis (pick the dimension that isn't zero).
|
||||
BoxTriResolveCase resCase = pushedFromTriangleLine ? ELine : static_cast<BoxTriResolveCase>((abs(resolve3D[dim.first]) < 0.0001f) ? dim.second : dim.first);
|
||||
//Overwrite the smallest resolution if this is smaller.
|
||||
if (resolutionDist < resolveShortest.DistanceSq) {
|
||||
resolveShortest.Vector = glm::vec3(0.f);
|
||||
resolveShortest.Vector[dim.first] = resolutionVector.x;
|
||||
resolveShortest.Vector[dim.second] = resolutionVector.y;
|
||||
resolveShortest.DistanceSq = resolutionDist;
|
||||
//If we pushed away from triangle line (edge), or if we
|
||||
//move the player along one coordinate axis (pick the dimension that isn't zero).
|
||||
resolveShortest.Case = pushedFromTriangleLine ? Line : static_cast<BoxTriResolveCase>((abs(resolveShortest.Vector[dim.first]) < 0.0001f) ? dim.second : dim.first);
|
||||
}
|
||||
resolveShortest.AddResolution(resCase, resolutionDistSq, resolve3D);
|
||||
|
||||
//Overwrite the smallest upward resolution if this is smaller, and resolves upwards.
|
||||
constexpr int yAxis = 1;
|
||||
bool resIsUpwardsIn3D = dim.first == yAxis && resolutionVector.x > 0 || dim.second == yAxis && resolutionVector.y > 0;
|
||||
if (canStairStepUp && resIsUpwardsIn3D && resolutionDist < resolveUpwards.DistanceSq) {
|
||||
resolveUpwards.Vector = glm::vec3(0.f);
|
||||
resolveUpwards.Vector[dim.first] = resolutionVector.x;
|
||||
resolveUpwards.Vector[dim.second] = resolutionVector.y;
|
||||
resolveUpwards.DistanceSq = resolutionDist;
|
||||
//If we pushed away from triangle line (edge), or if we
|
||||
//move the player along one coordinate axis (pick the dimension that isn't zero).
|
||||
resolveUpwards.Case = pushedFromTriangleLine ? Line : static_cast<BoxTriResolveCase>((abs(resolveUpwards.Vector[dim.first]) < 0.0001f) ? dim.second : dim.first);
|
||||
bool resIsUpwardsIn3D = dim.first == yAxis && resolutionVector2D.x > 0 || dim.second == yAxis && resolutionVector2D.y > 0;
|
||||
if (canStairStepUp && resIsUpwardsIn3D) {
|
||||
resolveUpwards.AddResolution(resCase, resolutionDistSq, resolve3D);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -472,37 +510,40 @@ bool AABBvsTriangle(const AABB& box,
|
||||
glm::vec3 cornerResolution = (1+t) * diagonal;
|
||||
//Overwrite the smallest resolution if cornerResolution is smaller.
|
||||
float lenSq = glm::length2(cornerResolution);
|
||||
if (lenSq < resolveShortest.DistanceSq) {
|
||||
resolveShortest.Vector = cornerResolution;
|
||||
resolveShortest.Case = Corner;
|
||||
}
|
||||
if (canStairStepUp && cornerResolution.y > 0 && lenSq < resolveUpwards.DistanceSq) {
|
||||
resolveUpwards.Vector = cornerResolution;
|
||||
resolveUpwards.Case = Corner;
|
||||
resolveUpwards.DistanceSq = lenSq;
|
||||
resolveShortest.AddResolution(ECorner, lenSq, cornerResolution);
|
||||
if (canStairStepUp && cornerResolution.y > 0) {
|
||||
resolveUpwards.AddResolution(ECorner, lenSq, cornerResolution);
|
||||
}
|
||||
|
||||
//Force the resolution upwards if it is smaller than the threshold verticalStepHeight.
|
||||
//Else take the shortest resolution.
|
||||
bool takeUp = resolveUpwards.Vector.y > 0 && resolveUpwards.Vector.y < verticalStepHeight;
|
||||
Resolution& bestResolve = takeUp ? resolveUpwards : resolveShortest;
|
||||
outResolution = bestResolve.Vector;
|
||||
bool takeUp = resolveUpwards.Shortest->Vector.y > 0 && resolveUpwards.Shortest->Vector.y < verticalStepHeight;
|
||||
CaseResolutions& bestResolve = takeUp ? resolveUpwards : resolveShortest;
|
||||
outResolution = bestResolve.Shortest->Vector;
|
||||
|
||||
std::string dbgString = "";
|
||||
glm::vec3 projNorm;
|
||||
switch (bestResolve.Case) {
|
||||
case ResolveDimY:
|
||||
switch (bestResolve.Shortest->Case) {
|
||||
case EResolveDimY:
|
||||
boxVelocity.y = 0.f;
|
||||
if (outResolution.y > 0)
|
||||
isOnGround = true;
|
||||
case ResolveDimX:
|
||||
case ResolveDimZ:
|
||||
case EResolveDimX:
|
||||
case EResolveDimZ:
|
||||
//If we get here, the resolution is along one coordinate axis.
|
||||
//set velocity to 0 in y if it is along y-axis.
|
||||
dbgString = "Vertex Collision";
|
||||
dbgString += isOnGround ? " Ground" : " Air";
|
||||
dbgString += takeUp ? " Force up" : " Normal";
|
||||
std::cout << (dbgString.c_str()) << std::endl;
|
||||
ImGui::Text(dbgString.c_str());
|
||||
return true;
|
||||
case Line:
|
||||
case ELine:
|
||||
dbgString = "Line Collision";
|
||||
projNorm = glm::normalize(outResolution);
|
||||
break;
|
||||
case Corner:
|
||||
case ECorner:
|
||||
dbgString = "Corner Collision";
|
||||
projNorm = triNormal;
|
||||
break;
|
||||
default:
|
||||
@@ -519,6 +560,23 @@ bool AABBvsTriangle(const AABB& box,
|
||||
outResolution.y = len / glm::sin(ang);
|
||||
outResolution.z = 0;
|
||||
}
|
||||
float y;
|
||||
if (bestResolve.Shortest->Case == ECorner) {
|
||||
len = glm::length(bestResolve.Line.Vector);
|
||||
ang = glm::half_pi<float>() - glm::acos(bestResolve.Line.Vector.y / len);
|
||||
if (len > 0.0000001f && ang > 0.0000001f) {
|
||||
y = len / glm::sin(ang);
|
||||
if (y < outResolution.y) {
|
||||
outResolution.x = 0;
|
||||
outResolution.y = y;
|
||||
outResolution.z = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
y = bestResolve.Vertex.Vector.y;
|
||||
if (bestResolve.Vertex.Case == EResolveDimY && y < outResolution.y) {
|
||||
outResolution.y = y;
|
||||
}
|
||||
//Also zero the vertical velocity, if it is positive, else project it onto the normal.
|
||||
//Project the velocity onto the normal of the hit line/face.
|
||||
//w = v - <v,n>*n, |n|==1.
|
||||
@@ -533,6 +591,10 @@ bool AABBvsTriangle(const AABB& box,
|
||||
boxVelocity = boxVelocity - glm::dot(boxVelocity, projNorm) * projNorm;
|
||||
}
|
||||
}
|
||||
dbgString += isOnGround ? " Ground" : " Air";
|
||||
dbgString += takeUp ? " Force up" : " Normal";
|
||||
std::cout << (dbgString.c_str()) << std::endl;
|
||||
ImGui::Text(dbgString.c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -546,6 +608,7 @@ bool AABBvsTriangles(const AABB& box,
|
||||
glm::vec3& outResolutionVector,
|
||||
bool resolveCollision)
|
||||
{
|
||||
std::cout << ("---->>>--AABBvsTriangles--------") << std::endl;
|
||||
bool hit = false;
|
||||
|
||||
bool everHitTheGround = false;
|
||||
@@ -573,6 +636,9 @@ bool AABBvsTriangles(const AABB& box,
|
||||
if (!everHitTheGround) {
|
||||
isOnGround = false;
|
||||
}
|
||||
std::cout << (isOnGround ? "Hit Ground" : "In Air") << std::endl;
|
||||
ImGui::Text(isOnGround ? "Hit Ground" : "In Air");
|
||||
std::cout << ("--------AABBvsTriangles---->>>--") << std::endl;
|
||||
return hit;
|
||||
}
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ void CollisionSystem::UpdateComponent(EntityWrapper& entity, ComponentWrapper& c
|
||||
if (!boundingBox) {
|
||||
return;
|
||||
}
|
||||
std::cout << "---->>>--Start Update--------" << std::endl;
|
||||
ComponentWrapper& cTransform = entity["Transform"];
|
||||
EntityAABB& boxA = *boundingBox;
|
||||
bool everHitTheGround = false;
|
||||
@@ -115,4 +116,5 @@ void CollisionSystem::UpdateComponent(EntityWrapper& entity, ComponentWrapper& c
|
||||
}
|
||||
|
||||
m_PrevPositions[entity] = boxA.Origin();
|
||||
std::cout << "--------End Update---->>>--" << std::endl;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user