|
|
|
@ -299,7 +299,115 @@ private: |
|
|
|
|
v.z = v1.x * v2.y - v1.y * v2.x; |
|
|
|
|
return v; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
vec3d Vector_IntersectPlane(vec3d &plane_p, vec3d &plane_n, vec3d &lineStart, vec3d &lineEnd) |
|
|
|
|
{ |
|
|
|
|
plane_n = Vector_Normalise(plane_n); |
|
|
|
|
float plane_d = -Vector_DotProduct(plane_n, plane_p); |
|
|
|
|
float ad = Vector_DotProduct(lineStart, plane_n); |
|
|
|
|
float bd = Vector_DotProduct(lineEnd, plane_n); |
|
|
|
|
float t = (-plane_d - ad) / (bd - ad); |
|
|
|
|
vec3d lineStartToEnd = Vector_Sub(lineEnd, lineStart); |
|
|
|
|
vec3d lineToIntersect = Vector_Mul(lineStartToEnd, t); |
|
|
|
|
return Vector_Add(lineStart, lineToIntersect); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
int Triangle_ClipAgainstPlane(vec3d plane_p, vec3d plane_n, triangle &in_tri, triangle &out_tri1, triangle &out_tri2) |
|
|
|
|
{ |
|
|
|
|
// Make sure plane normal is indeed normal
|
|
|
|
|
plane_n = Vector_Normalise(plane_n); |
|
|
|
|
|
|
|
|
|
// Return signed shortest distance from point to plane, plane normal must be normalised
|
|
|
|
|
auto dist = [&](vec3d &p) |
|
|
|
|
{ |
|
|
|
|
vec3d n = Vector_Normalise(p); |
|
|
|
|
return (plane_n.x * p.x + plane_n.y * p.y + plane_n.z * p.z - Vector_DotProduct(plane_n, plane_p)); |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
// Create two temporary storage arrays to classify points either side of plane
|
|
|
|
|
// If distance sign is positive, point lies on "inside" of plane
|
|
|
|
|
vec3d* inside_points[3]; int nInsidePointCount = 0; |
|
|
|
|
vec3d* outside_points[3]; int nOutsidePointCount = 0; |
|
|
|
|
|
|
|
|
|
// Get signed distance of each point in triangle to plane
|
|
|
|
|
float d0 = dist(in_tri.p[0]); |
|
|
|
|
float d1 = dist(in_tri.p[1]); |
|
|
|
|
float d2 = dist(in_tri.p[2]); |
|
|
|
|
|
|
|
|
|
if (d0 >= 0) { inside_points[nInsidePointCount++] = &in_tri.p[0]; } |
|
|
|
|
else { outside_points[nOutsidePointCount++] = &in_tri.p[0]; } |
|
|
|
|
if (d1 >= 0) { inside_points[nInsidePointCount++] = &in_tri.p[1]; } |
|
|
|
|
else { outside_points[nOutsidePointCount++] = &in_tri.p[1]; } |
|
|
|
|
if (d2 >= 0) { inside_points[nInsidePointCount++] = &in_tri.p[2]; } |
|
|
|
|
else { outside_points[nOutsidePointCount++] = &in_tri.p[2]; } |
|
|
|
|
|
|
|
|
|
// Now classify triangle points, and break the input triangle into
|
|
|
|
|
// smaller output triangles if required. There are four possible
|
|
|
|
|
// outcomes...
|
|
|
|
|
|
|
|
|
|
if (nInsidePointCount == 0) |
|
|
|
|
{ |
|
|
|
|
// All points lie on the outside of plane, so clip whole triangle
|
|
|
|
|
// It ceases to exist
|
|
|
|
|
|
|
|
|
|
return 0; // No returned triangles are valid
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (nInsidePointCount == 3) |
|
|
|
|
{ |
|
|
|
|
// All points lie on the inside of plane, so do nothing
|
|
|
|
|
// and allow the triangle to simply pass through
|
|
|
|
|
out_tri1 = in_tri; |
|
|
|
|
|
|
|
|
|
return 1; // Just the one returned original triangle is valid
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (nInsidePointCount == 1 && nOutsidePointCount == 2) |
|
|
|
|
{ |
|
|
|
|
// Triangle should be clipped. As two points lie outside
|
|
|
|
|
// the plane, the triangle simply becomes a smaller triangle
|
|
|
|
|
|
|
|
|
|
// Copy appearance info to new triangle
|
|
|
|
|
out_tri1.col = in_tri.col; |
|
|
|
|
|
|
|
|
|
// The inside point is valid, so keep that...
|
|
|
|
|
out_tri1.p[0] = *inside_points[0]; |
|
|
|
|
|
|
|
|
|
// but the two new points are at the locations where the
|
|
|
|
|
// original sides of the triangle (lines) intersect with the plane
|
|
|
|
|
out_tri1.p[1] = Vector_IntersectPlane(plane_p, plane_n, *inside_points[0], *outside_points[0]); |
|
|
|
|
out_tri1.p[2] = Vector_IntersectPlane(plane_p, plane_n, *inside_points[0], *outside_points[1]); |
|
|
|
|
|
|
|
|
|
return 1; // Return the newly formed single triangle
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (nInsidePointCount == 2 && nOutsidePointCount == 1) |
|
|
|
|
{ |
|
|
|
|
// Triangle should be clipped. As two points lie inside the plane,
|
|
|
|
|
// the clipped triangle becomes a "quad". Fortunately, we can
|
|
|
|
|
// represent a quad with two new triangles
|
|
|
|
|
|
|
|
|
|
// Copy appearance info to new triangles
|
|
|
|
|
out_tri1.col = in_tri.col; |
|
|
|
|
out_tri2.col = in_tri.col; |
|
|
|
|
|
|
|
|
|
// The first triangle consists of the two inside points and a new
|
|
|
|
|
// point determined by the location where one side of the triangle
|
|
|
|
|
// intersects with the plane
|
|
|
|
|
out_tri1.p[0] = *inside_points[0]; |
|
|
|
|
out_tri1.p[1] = *inside_points[1]; |
|
|
|
|
out_tri1.p[2] = Vector_IntersectPlane(plane_p, plane_n, *inside_points[0], *outside_points[0]); |
|
|
|
|
|
|
|
|
|
// The second triangle is composed of one of he inside points, a
|
|
|
|
|
// new point determined by the intersection of the other side of the
|
|
|
|
|
// triangle and the plane, and the newly created point above
|
|
|
|
|
out_tri2.p[0] = *inside_points[1]; |
|
|
|
|
out_tri2.p[1] = out_tri1.p[2]; |
|
|
|
|
out_tri2.p[2] = Vector_IntersectPlane(plane_p, plane_n, *inside_points[1], *outside_points[0]); |
|
|
|
|
|
|
|
|
|
return 2; // Return two newly formed triangles which form a quad
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public: |
|
|
|
|
bool OnUserCreate() override |
|
|
|
@ -391,37 +499,42 @@ public: |
|
|
|
|
triViewed.p[1]=Matrix_MultiplyVector(matView,triTransformed.p[1]); |
|
|
|
|
triViewed.p[2]=Matrix_MultiplyVector(matView,triTransformed.p[2]); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Project triangles from 3D --> 2D
|
|
|
|
|
triProjected.p[0]=Matrix_MultiplyVector(matProj,triViewed.p[0]); |
|
|
|
|
triProjected.p[1]=Matrix_MultiplyVector(matProj,triViewed.p[1]); |
|
|
|
|
triProjected.p[2]=Matrix_MultiplyVector(matProj,triViewed.p[2]); |
|
|
|
|
triProjected.p[0]=Vector_Div(triProjected.p[0],triProjected.p[0].w); |
|
|
|
|
triProjected.p[1]=Vector_Div(triProjected.p[1],triProjected.p[1].w); |
|
|
|
|
triProjected.p[2]=Vector_Div(triProjected.p[2],triProjected.p[2].w); |
|
|
|
|
triProjected.col=triTransformed.col; |
|
|
|
|
|
|
|
|
|
triProjected.p[0].x*=-1.0f; |
|
|
|
|
triProjected.p[1].x*=-1.0f; |
|
|
|
|
triProjected.p[2].x*=-1.0f; |
|
|
|
|
triProjected.p[0].y*=-1.0f; |
|
|
|
|
triProjected.p[1].y*=-1.0f; |
|
|
|
|
triProjected.p[2].y*=-1.0f; |
|
|
|
|
|
|
|
|
|
// Scale into view
|
|
|
|
|
vec3d vOffsetView={1,1,0}; |
|
|
|
|
triProjected.p[0] = Vector_Add(triProjected.p[0],vOffsetView); |
|
|
|
|
triProjected.p[1] = Vector_Add(triProjected.p[1],vOffsetView); |
|
|
|
|
triProjected.p[2] = Vector_Add(triProjected.p[2],vOffsetView); |
|
|
|
|
triProjected.p[0].x *= 0.5f * (float)ScreenWidth(); |
|
|
|
|
triProjected.p[0].y *= 0.5f * (float)ScreenHeight(); |
|
|
|
|
triProjected.p[1].x *= 0.5f * (float)ScreenWidth(); |
|
|
|
|
triProjected.p[1].y *= 0.5f * (float)ScreenHeight(); |
|
|
|
|
triProjected.p[2].x *= 0.5f * (float)ScreenWidth(); |
|
|
|
|
triProjected.p[2].y *= 0.5f * (float)ScreenHeight(); |
|
|
|
|
|
|
|
|
|
vecTrianglesToRaster.push_back(triProjected); |
|
|
|
|
|
|
|
|
|
int nClippedTriangles = 0; |
|
|
|
|
triangle clipped[2]; |
|
|
|
|
nClippedTriangles = Triangle_ClipAgainstPlane({ 0.0f, 0.0f, 0.1f }, { 0.0f, 0.0f, 1.0f }, triViewed, clipped[0], clipped[1]); |
|
|
|
|
|
|
|
|
|
for (int n=0;n<nClippedTriangles;n++) { |
|
|
|
|
// Project triangles from 3D --> 2D
|
|
|
|
|
triProjected.p[0]=Matrix_MultiplyVector(matProj,clipped[n].p[0]); |
|
|
|
|
triProjected.p[1]=Matrix_MultiplyVector(matProj,clipped[n].p[1]); |
|
|
|
|
triProjected.p[2]=Matrix_MultiplyVector(matProj,clipped[n].p[2]); |
|
|
|
|
triProjected.col=triTransformed.col; |
|
|
|
|
|
|
|
|
|
triProjected.p[0]=Vector_Div(triProjected.p[0],triProjected.p[0].w); |
|
|
|
|
triProjected.p[1]=Vector_Div(triProjected.p[1],triProjected.p[1].w); |
|
|
|
|
triProjected.p[2]=Vector_Div(triProjected.p[2],triProjected.p[2].w); |
|
|
|
|
|
|
|
|
|
triProjected.p[0].x*=-1.0f; |
|
|
|
|
triProjected.p[1].x*=-1.0f; |
|
|
|
|
triProjected.p[2].x*=-1.0f; |
|
|
|
|
triProjected.p[0].y*=-1.0f; |
|
|
|
|
triProjected.p[1].y*=-1.0f; |
|
|
|
|
triProjected.p[2].y*=-1.0f; |
|
|
|
|
|
|
|
|
|
// Scale into view
|
|
|
|
|
vec3d vOffsetView={1,1,0}; |
|
|
|
|
triProjected.p[0] = Vector_Add(triProjected.p[0],vOffsetView); |
|
|
|
|
triProjected.p[1] = Vector_Add(triProjected.p[1],vOffsetView); |
|
|
|
|
triProjected.p[2] = Vector_Add(triProjected.p[2],vOffsetView); |
|
|
|
|
triProjected.p[0].x *= 0.5f * (float)ScreenWidth(); |
|
|
|
|
triProjected.p[0].y *= 0.5f * (float)ScreenHeight(); |
|
|
|
|
triProjected.p[1].x *= 0.5f * (float)ScreenWidth(); |
|
|
|
|
triProjected.p[1].y *= 0.5f * (float)ScreenHeight(); |
|
|
|
|
triProjected.p[2].x *= 0.5f * (float)ScreenWidth(); |
|
|
|
|
triProjected.p[2].y *= 0.5f * (float)ScreenHeight(); |
|
|
|
|
|
|
|
|
|
vecTrianglesToRaster.push_back(triProjected); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -441,7 +554,7 @@ public: |
|
|
|
|
{triProjected.uv[1].u,triProjected.uv[1].v}, |
|
|
|
|
{triProjected.uv[2].u,triProjected.uv[2].v}, |
|
|
|
|
},triProjected.col); |
|
|
|
|
/*SetDecalMode(DecalMode::WIREFRAME);
|
|
|
|
|
SetDecalMode(DecalMode::WIREFRAME); |
|
|
|
|
DrawPolygonDecal(nullptr,{ |
|
|
|
|
{triProjected.p[0].x, triProjected.p[0].y}, |
|
|
|
|
{triProjected.p[1].x, triProjected.p[1].y}, |
|
|
|
@ -450,12 +563,12 @@ public: |
|
|
|
|
{0,0}, |
|
|
|
|
{0,0}, |
|
|
|
|
{0,0}, |
|
|
|
|
},BLACK);*/ |
|
|
|
|
},BLACK); |
|
|
|
|
SetDecalStructure(DecalStructure::FAN); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
SetDecalMode(DecalMode::NORMAL); |
|
|
|
|
DrawStringDecal({0,0},"Triangles: "+std::to_string(meshCube.tris.size())); |
|
|
|
|
DrawStringDecal({0,0},"Triangles: "+std::to_string(vecTrianglesToRaster.size())); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return true; |
|
|
|
|