Special case for collision vs ground (upward facing) triangles.
This commit is contained in:
@@ -4,6 +4,7 @@
|
||||
#include "Engine/GLM.h"
|
||||
#include "Core/World.h"
|
||||
#include "Rendering/Model.h"
|
||||
#include "imgui/imgui.h"
|
||||
|
||||
namespace Collision
|
||||
{
|
||||
@@ -248,12 +249,21 @@ bool vectorHasLength(const glm::vec3& vec)
|
||||
return glm::any(glm::greaterThan(glm::abs(vec), glm::vec3(0.0001f, 0.0001f, 0.0001f)));
|
||||
}
|
||||
|
||||
enum BoxTriHit
|
||||
{
|
||||
Line0 = 0,
|
||||
Line1,
|
||||
Line2,
|
||||
Ground,
|
||||
Corner
|
||||
};
|
||||
|
||||
bool AABBvsTriangle(const AABB& box,
|
||||
const glm::vec3& v0,
|
||||
const glm::vec3& v1,
|
||||
const glm::vec3& v2,
|
||||
glm::vec3& outVector,
|
||||
int& lineHit)
|
||||
BoxTriHit& outHit)
|
||||
{
|
||||
//Check so we don't have a zero area triangle when calculating the normal.
|
||||
glm::vec3 triNormal = glm::cross(v1 - v0, v2 - v0);
|
||||
@@ -266,6 +276,23 @@ bool AABBvsTriangle(const AABB& box,
|
||||
const glm::vec3& min = box.MinCorner();
|
||||
const glm::vec3& max = box.MaxCorner();
|
||||
|
||||
//Check if normal faces upwards, and if so, just push the box upwards on collision.
|
||||
triNormal = glm::normalize(triNormal);
|
||||
if (triNormal.y > 0.5f || true) {
|
||||
//TODO: Optimize calculation since x, z is 0.
|
||||
//Ray ray(glm::vec3(origin.x, origin.y + half.y, origin.z), glm::vec3(0, -1, 0));
|
||||
//float dist = INFINITY, u, v;
|
||||
//if (RayVsTriangle(ray, v0, v1, v2, dist, u, v) && dist < 2.0f * half.y) {
|
||||
Ray ray(origin, glm::vec3(0, -1, 0));
|
||||
float dist = INFINITY, u, v;
|
||||
if (RayVsTriangle(ray, v0, v1, v2, dist, u, v) && dist < half.y) {
|
||||
outVector = glm::vec3(0, half.y - dist, 0);
|
||||
outHit = Ground;
|
||||
return true;
|
||||
}
|
||||
//return false; //TODO: Uncomment?
|
||||
}
|
||||
|
||||
const glm::vec3 triPos[] = {
|
||||
v0, v1, v2
|
||||
};
|
||||
@@ -291,7 +318,6 @@ bool AABBvsTriangle(const AABB& box,
|
||||
return false; //If a triangle is completely inside the box, we call it a non-intersection.
|
||||
}
|
||||
|
||||
triNormal = glm::normalize(triNormal);
|
||||
Ray ray;
|
||||
//All triangle edges.
|
||||
//Check if any edge on the triangle intersects the box.
|
||||
@@ -302,7 +328,7 @@ bool AABBvsTriangle(const AABB& box,
|
||||
float dist;
|
||||
if (RayVsAABB(ray, box, dist) && dist <= glm::length(edge)) {
|
||||
outVector = triNormal;
|
||||
lineHit = l;
|
||||
outHit = (BoxTriHit)l;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -341,6 +367,7 @@ bool AABBvsTriangle(const AABB& box,
|
||||
//Distance between triangle plane, and the diagonal corner, multiplied by the normal.
|
||||
//Signed distance, positive if on the same side as the normal.
|
||||
outVector = -glm::dot(triNormal, origin + diagonal - v0) * triNormal;
|
||||
outHit = Corner;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -348,6 +375,7 @@ bool AABBvsTriangle(const AABB& box,
|
||||
|
||||
bool AABBvsTriangles(const AABB& box, const std::vector<RawModel::Vertex>& modelVertices, const std::vector<unsigned int>& modelIndices, const glm::mat4& modelMatrix, glm::vec3& outResolutionVector)
|
||||
{
|
||||
AABB newBox = box;
|
||||
struct Triangle
|
||||
{
|
||||
glm::vec3 v0, v1, v2;
|
||||
@@ -362,45 +390,61 @@ bool AABBvsTriangles(const AABB& box, const std::vector<RawModel::Vertex>& model
|
||||
glm::vec3 v0 = Transform::TransformPoint(modelVertices[modelIndices[i++]].Position, modelMatrix);
|
||||
glm::vec3 v1 = Transform::TransformPoint(modelVertices[modelIndices[i++]].Position, modelMatrix);
|
||||
glm::vec3 v2 = Transform::TransformPoint(modelVertices[modelIndices[i++]].Position, modelMatrix);
|
||||
int lineHit = -1;
|
||||
if (AABBvsTriangle(box, v0, v1, v2, outVec, lineHit))
|
||||
BoxTriHit hitCase;
|
||||
if (AABBvsTriangle(newBox, v0, v1, v2, outVec, hitCase))
|
||||
{
|
||||
hit = true;
|
||||
if (lineHit == -1) {
|
||||
outResolutionVector += outVec;
|
||||
//TODO: We might be able to return here instead, having only convex geometry.
|
||||
cornerHitTODO = true;
|
||||
//return true;
|
||||
}
|
||||
else {
|
||||
const glm::vec3 triPos[] = {
|
||||
v0, v1, v2
|
||||
};
|
||||
glm::vec3 edge = triPos[(lineHit + 1) % 3] - triPos[lineHit];
|
||||
switch (hitCase) {
|
||||
case Collision::Line0:
|
||||
case Collision::Line1:
|
||||
case Collision::Line2:
|
||||
//TODO: Resolve.
|
||||
//const glm::vec3 triPos[] = {
|
||||
// v0, v1, v2
|
||||
//};
|
||||
//glm::vec3 edge = triPos[(hitCase + 1) % 3] - triPos[hitCase];
|
||||
hitTriangles.push_back({v0, v1, v2});
|
||||
hitNormals.push_back(outVec);
|
||||
ImGui::Text("triangle edge collision.");
|
||||
break;
|
||||
case Collision::Corner:
|
||||
//TODO: We might be able to return here instead, having only convex geometry.
|
||||
cornerHitTODO = true;
|
||||
//outResolutionVector += outVec;
|
||||
//return true;
|
||||
ImGui::Text("triangle corner collision.");
|
||||
outResolutionVector += outVec;
|
||||
newBox = AABB::FromOriginSize(newBox.Origin() + outVec, newBox.Size());
|
||||
break;
|
||||
case Collision::Ground:
|
||||
default:
|
||||
outResolutionVector += outVec;
|
||||
newBox = AABB::FromOriginSize(newBox.Origin() + outVec, newBox.Size());
|
||||
ImGui::Text("triangle ground collision.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (hitTriangles.size() > 0) {
|
||||
if (cornerHitTODO) {
|
||||
LOG_DEBUG("Both edges and corners was hit on the same model.");
|
||||
ImGui::Text("Both edges and corners was hit on the same model.");
|
||||
return true;
|
||||
}
|
||||
glm::vec3 lineResolve(0.f);
|
||||
for (const glm::vec3& norm : hitNormals) {
|
||||
outResolutionVector += norm;
|
||||
lineResolve += norm;
|
||||
}
|
||||
//Normalize.
|
||||
outResolutionVector /= hitNormals.size();
|
||||
const glm::vec3& origin = box.Origin();
|
||||
const glm::vec3& half = box.HalfSize();
|
||||
lineResolve /= hitNormals.size();
|
||||
const glm::vec3& origin = newBox.Origin();
|
||||
const glm::vec3& half = newBox.HalfSize();
|
||||
float maxDist = -10;
|
||||
for (const Triangle& tri : hitTriangles) {
|
||||
float d = glm::dot(outResolutionVector, 0.333f * (tri.v0 + tri.v1 + tri.v2) - origin);
|
||||
float d = glm::dot(lineResolve, 0.333f * (tri.v0 + tri.v1 + tri.v2) - origin);
|
||||
maxDist = std::max(maxDist, d);
|
||||
}
|
||||
glm::vec3 tmp = glm::clamp(2.0f * outResolutionVector, glm::vec3(-1, -1, -1), glm::vec3(1, 1, 1));
|
||||
outResolutionVector *= maxDist + glm::length(tmp * half);
|
||||
glm::vec3 tmp = glm::clamp(2.0f * lineResolve, glm::vec3(-1, -1, -1), glm::vec3(1, 1, 1));
|
||||
outResolutionVector += lineResolve * (maxDist + glm::length(tmp * half));
|
||||
}
|
||||
return hit;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user