Special case for collision vs ground (upward facing) triangles.

This commit is contained in:
William Moberg
2016-01-23 14:01:54 +01:00
parent 3974c649ab
commit 71404c8828
3 changed files with 134 additions and 145 deletions
+65 -121
View File
@@ -1,122 +1,66 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<Entity xmlns:c="components" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../Types/Entity.xsd">
<Entity xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xi="http://www.w3.org/2001/XInclude" xsi:noNamespaceSchemaLocation="../Types/Entity.xsd" xmlns:c="components"> <Components>
<Components> <c:Transform/>
<c:Transform> </Components>
<Orientation X="0" Y="0" Z="0"/>
</c:Transform> <Children>
<c:Model> <Entity>
<Resource>Models/DummyScene.obj</Resource> <Components>
</c:Model> <c:AABB/>
</Components> <c:Collidable/>
<Children> <c:Model>
<Entity> <Resource>../assets\Models\Test/ObstacleCourse.obj</Resource>
<Components> </c:Model>
<c:Transform> <c:Transform>
<Position X="-1.5"/> <Position X="0" Y="0" Z="0.00638055196"/>
<Scale X="1" Y="1" Z="1"/> </c:Transform>
</c:Transform> </Components>
<c:Model> <Children/>
<Resource>Models/Core/UnitSphere.obj</Resource> </Entity>
</c:Model> <Entity>
</Components> <Components>
</Entity> <c:DirectionalLight>
<Entity> <Intensity>0.46000027656555176</Intensity>
<Components> </c:DirectionalLight>
<c:Transform> <c:Transform>
<Position X="1.5"/> <Orientation X="0" Y="2.59000015" Z="0.799000025"/>
<Scale X="2" Y="2" Z="2"/> </c:Transform>
</c:Transform> </Components>
<c:Model> <Children/>
<Resource>Models/RotationWidgetX.obj</Resource> </Entity>
</c:Model> <Entity>
<c:Trigger> <Components>
</c:Trigger> <c:AABB/>
</Components> <c:Collidable/>
</Entity> <c:Model>
<Entity> <Resource>../assets\Models\Core\UnitCube.obj</Resource>
<Components> </c:Model>
<c:Player> <c:Physics>
<Velocity X="0" Y="0" Z="0"/> <Gravity>false</Gravity>
</c:Player> </c:Physics>
<c:Transform> <c:Player/>
<Position X="2.5"/> <c:Transform>
</c:Transform> <Position X="-2.31658864" Y="2.02328157" Z="4.50379515"/>
<c:Model> </c:Transform>
<Resource>Models/Core/UnitCube.obj</Resource> </Components>
</c:Model> <Children/>
<c:AABB> </Entity>
</c:AABB> <Entity>
</Components> <Components>
</Entity> <c:AABB/>
<Entity> <c:Collidable/>
<Components> <c:Model>
<c:Transform> <Resource>../assets\Models\Core\colorbox.obj</Resource>
<Position X="0" Y="-0"/> </c:Model>
<Scale X="1" Y="1" Z="1"/> <c:Transform>
</c:Transform> <Position X="-1.52309108" Y="5.72108126" Z="0"/>
<!--<c:Move> <Scale X="5" Y="5" Z="5"/>
<Speed>1</Speed> </c:Transform>
<Direction X="-1"/> </Components>
<Rotation Y="3.14"/> <Children/>
</c:Move>--> </Entity>
</Components> </Children>
<Children>
<Entity> </Entity>
<Components>
<c:Transform>
<Position X="0" Y="0"/>
<Orientation X="0.0" Y="0" Z="1.0"/>
</c:Transform>
<c:Model>
<Resource>Models/Core/UnitRaptor.obj</Resource>
<Color R="1" G="0.4" B="0.8"/>
</c:Model>
</Components>
<Children>
<Entity>
<Components>
<c:Transform>
<Position X="-0.01" Y="0.55"/>
<Orientation X="0" Y="0" Z="-1"/>
</c:Transform>
<c:RaptorCopter>
<Speed>20</Speed>
<Axis Y="1"/>
</c:RaptorCopter>
</Components>
<Children>
<Entity>
<Components>
<c:Transform>
<Position X="0" Y="0"/>
<Scale X="1.7" Y="0.03" Z="0.1"/>
<Orientation X="0" Y="0" Z="0"/>
</c:Transform>
<c:Model>
<Resource>Models/Core/UnitCube.obj</Resource>
<Color R="1" G="0.4" B="0.8"/>
</c:Model>
</Components>
</Entity>
<Entity>
<Components>
<c:Transform>
<Position X="0" Y="0"/>
<Scale X="1.7" Y="0.03" Z="0.1"/>
<Orientation X="0" Y="1.57" Z="0"/>
</c:Transform>
<c:Model>
<Resource>Models/Core/UnitCube.obj</Resource>
<Color R="1" G="0.4" B="0.8"/>
</c:Model>
</Components>
</Entity>
</Children>
</Entity>
</Children>
</Entity>
</Children>
</Entity>
</Children>
</Entity>
+68 -24
View File
@@ -4,6 +4,7 @@
#include "Engine/GLM.h" #include "Engine/GLM.h"
#include "Core/World.h" #include "Core/World.h"
#include "Rendering/Model.h" #include "Rendering/Model.h"
#include "imgui/imgui.h"
namespace Collision 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))); 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, bool AABBvsTriangle(const AABB& box,
const glm::vec3& v0, const glm::vec3& v0,
const glm::vec3& v1, const glm::vec3& v1,
const glm::vec3& v2, const glm::vec3& v2,
glm::vec3& outVector, glm::vec3& outVector,
int& lineHit) BoxTriHit& outHit)
{ {
//Check so we don't have a zero area triangle when calculating the normal. //Check so we don't have a zero area triangle when calculating the normal.
glm::vec3 triNormal = glm::cross(v1 - v0, v2 - v0); 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& min = box.MinCorner();
const glm::vec3& max = box.MaxCorner(); 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[] = { const glm::vec3 triPos[] = {
v0, v1, v2 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. return false; //If a triangle is completely inside the box, we call it a non-intersection.
} }
triNormal = glm::normalize(triNormal);
Ray ray; Ray ray;
//All triangle edges. //All triangle edges.
//Check if any edge on the triangle intersects the box. //Check if any edge on the triangle intersects the box.
@@ -302,7 +328,7 @@ bool AABBvsTriangle(const AABB& box,
float dist; float dist;
if (RayVsAABB(ray, box, dist) && dist <= glm::length(edge)) { if (RayVsAABB(ray, box, dist) && dist <= glm::length(edge)) {
outVector = triNormal; outVector = triNormal;
lineHit = l; outHit = (BoxTriHit)l;
return true; return true;
} }
} }
@@ -341,6 +367,7 @@ bool AABBvsTriangle(const AABB& box,
//Distance between triangle plane, and the diagonal corner, multiplied by the normal. //Distance between triangle plane, and the diagonal corner, multiplied by the normal.
//Signed distance, positive if on the same side as the normal. //Signed distance, positive if on the same side as the normal.
outVector = -glm::dot(triNormal, origin + diagonal - v0) * triNormal; outVector = -glm::dot(triNormal, origin + diagonal - v0) * triNormal;
outHit = Corner;
return true; return true;
} }
return false; 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) 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 struct Triangle
{ {
glm::vec3 v0, v1, v2; 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 v0 = Transform::TransformPoint(modelVertices[modelIndices[i++]].Position, modelMatrix);
glm::vec3 v1 = 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); glm::vec3 v2 = Transform::TransformPoint(modelVertices[modelIndices[i++]].Position, modelMatrix);
int lineHit = -1; BoxTriHit hitCase;
if (AABBvsTriangle(box, v0, v1, v2, outVec, lineHit)) if (AABBvsTriangle(newBox, v0, v1, v2, outVec, hitCase))
{ {
hit = true; hit = true;
if (lineHit == -1) { switch (hitCase) {
outResolutionVector += outVec; case Collision::Line0:
//TODO: We might be able to return here instead, having only convex geometry. case Collision::Line1:
cornerHitTODO = true; case Collision::Line2:
//return true; //TODO: Resolve.
} //const glm::vec3 triPos[] = {
else { // v0, v1, v2
const glm::vec3 triPos[] = { //};
v0, v1, v2 //glm::vec3 edge = triPos[(hitCase + 1) % 3] - triPos[hitCase];
};
glm::vec3 edge = triPos[(lineHit + 1) % 3] - triPos[lineHit];
hitTriangles.push_back({v0, v1, v2}); hitTriangles.push_back({v0, v1, v2});
hitNormals.push_back(outVec); 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 (hitTriangles.size() > 0) {
if (cornerHitTODO) { 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; return true;
} }
glm::vec3 lineResolve(0.f);
for (const glm::vec3& norm : hitNormals) { for (const glm::vec3& norm : hitNormals) {
outResolutionVector += norm; lineResolve += norm;
} }
//Normalize. //Normalize.
outResolutionVector /= hitNormals.size(); lineResolve /= hitNormals.size();
const glm::vec3& origin = box.Origin(); const glm::vec3& origin = newBox.Origin();
const glm::vec3& half = box.HalfSize(); const glm::vec3& half = newBox.HalfSize();
float maxDist = -10; float maxDist = -10;
for (const Triangle& tri : hitTriangles) { 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); maxDist = std::max(maxDist, d);
} }
glm::vec3 tmp = glm::clamp(2.0f * outResolutionVector, glm::vec3(-1, -1, -1), glm::vec3(1, 1, 1)); glm::vec3 tmp = glm::clamp(2.0f * lineResolve, glm::vec3(-1, -1, -1), glm::vec3(1, 1, 1));
outResolutionVector *= maxDist + glm::length(tmp * half); outResolutionVector += lineResolve * (maxDist + glm::length(tmp * half));
} }
return hit; return hit;
} }
+1
View File
@@ -56,6 +56,7 @@ void CollisionSystem::UpdateComponent(EntityWrapper& entity, ComponentWrapper& c
glm::vec3 resolutionVector; glm::vec3 resolutionVector;
if (Collision::AABBvsTriangles(boxA, model->m_Vertices, model->m_Indices, modelMatrix, resolutionVector)) { if (Collision::AABBvsTriangles(boxA, model->m_Vertices, model->m_Indices, modelMatrix, resolutionVector)) {
(glm::vec3&)cTransform["Position"] += resolutionVector; (glm::vec3&)cTransform["Position"] += resolutionVector;
cPhysics["Velocity"] = glm::vec3(0, 0, 0);
} }
} }
} }