Clipping and backface culling

Culling isn't bad, clipping need a better approach to cut partial triangles.
This commit is contained in:
JackCarterSmith 2024-11-02 00:41:43 +01:00
parent 54507108b3
commit 098345409f
Signed by: JackCarterSmith
GPG Key ID: 832E52F4E23F8F24
3 changed files with 85 additions and 34 deletions

View File

@ -3,6 +3,8 @@
#include "../World/DbgCube.hpp"
#include "../World/Tank.hpp"
//#define DISABLE_INVISIBLE_VERTICES
// Rendering pipeline:
// model matrix (Object SRT) -> view matrix (camera matrix inverted) -> proj matrix -> clipping -> perspective divide -> viewport transformation -> Rasterizer (draw pixels inside projected triangles on 2D screen)
@ -23,6 +25,8 @@
// * https://en.wikipedia.org/wiki/Hidden-surface_determination#Occlusion_culling
// * https://en.wikipedia.org/wiki/Bounding_volume_hierarchy
static bool VertexIsInsideClipSpace(M3D_F4& V);
Graphic3DRenderer::Graphic3DRenderer() {
mRTSize = {1280.f, 324.f};
@ -109,20 +113,23 @@ void Graphic3DRenderer::Draw(sf::RenderTexture& context) {
// Object outside frustrum clipping
projAABB.Transform(projAABB, oTMat);
M3D_ContainmentType objInFrustrum = camFrustrum.Contains(projAABB);
if (objInFrustrum != DISJOINT) {
#ifndef DISABLE_INVISIBLE_VERTICES
if (objInFrustrum != DISJOINT)
#endif
{
size_t vCount = obj->GetObjectVerticesCount();
auto& oMesh = obj->GetObjectMesh();
M3D_F3 projVertices[vCount];
M3D_F4 projVertices[vCount];
// Vertices NDC space transformation
M3D_V3TransformPersDiv(
projVertices, sizeof(M3D_F3),
// Vertices homogeneous clip space transformation
M3D_V3Transform(
projVertices, sizeof(M3D_F4),
reinterpret_cast<const M3D_F3*>(oMesh.vertices.data()), sizeof(Vertex),
vCount,
oTMat * viewProjMat
);
// Draw the object indice triangles
// Draw the object indice triangles if visible or partially clipped
sf::Vertex v_tri[4];
for (auto& objPt : oMesh.parts) {
auto indicePtr = static_cast<const uint32_t*>(objPt.indices.data());
@ -134,29 +141,45 @@ void Graphic3DRenderer::Draw(sf::RenderTexture& context) {
// Triangle clipping
//TODO: implement complete Cohen-Sutherland algo or similar
M3D_VECTOR V1 = M3D_V4LoadF3(&projVertices[indicePtr[i]]);
M3D_VECTOR V2 = M3D_V4LoadF3(&projVertices[indicePtr[i+1]]);
M3D_VECTOR V3 = M3D_V4LoadF3(&projVertices[indicePtr[i+2]]);
if (VertexIsInsideClipSpace(projVertices[indicePtr[i]]) &&
VertexIsInsideClipSpace(projVertices[indicePtr[i+1]]) &&
VertexIsInsideClipSpace(projVertices[indicePtr[i+2]]))
{
M3D_VECTOR V1 = M3D_V4LoadF4(&projVertices[indicePtr[i]]);
M3D_VECTOR V2 = M3D_V4LoadF4(&projVertices[indicePtr[i+1]]);
M3D_VECTOR V3 = M3D_V4LoadF4(&projVertices[indicePtr[i+2]]);
// Face culling
M3D_VECTOR faceNormal = M3D_TNormal(V1,V2,V3);
if (M3D_V4GetX(M3D_V3Dot(V1, faceNormal)) >= 0) {
// Do the perspective divide
V1 = M3D_V4Divide(V1, M3D_V4SplatW(V1));
V2 = M3D_V4Divide(V2, M3D_V4SplatW(V2));
V3 = M3D_V4Divide(V3, M3D_V4SplatW(V3));
V1 = M3D_V3TransformNDCToViewport(V1, 0.f, 0.f, mRTSize.x, mRTSize.y, 1.f, 100.f);
V2 = M3D_V3TransformNDCToViewport(V2, 0.f, 0.f, mRTSize.x, mRTSize.y, 1.f, 100.f);
V3 = M3D_V3TransformNDCToViewport(V3, 0.f, 0.f, mRTSize.x, mRTSize.y, 1.f, 100.f);
sf::Color vColor;
if (objInFrustrum == DISJOINT)
vColor = sf::Color::Red;
else if (objInFrustrum == INTERSECTS)
vColor = sf::Color::Yellow;
else
vColor = oMesh.vertices[indicePtr[i]].color;
if (objInFrustrum == DISJOINT) {
v_tri[0].color = sf::Color::Red;
v_tri[1].color = sf::Color::Red;
v_tri[2].color = sf::Color::Red;
} else if (objInFrustrum == INTERSECTS) {
v_tri[0].color = sf::Color::Yellow;
v_tri[1].color = sf::Color::Yellow;
v_tri[2].color = sf::Color::Yellow;
} else {
v_tri[0].color = oMesh.vertices[indicePtr[i]].color;
v_tri[1].color = oMesh.vertices[indicePtr[i+1]].color;
v_tri[2].color = oMesh.vertices[indicePtr[i+2]].color;
}
v_tri[0].position = sf::Vector2f(M3D_V4GetX(V1), M3D_V4GetY(V1));
v_tri[0].color = vColor;
v_tri[3] = v_tri[0];
v_tri[1].position = sf::Vector2f(M3D_V4GetX(V2), M3D_V4GetY(V2));
v_tri[1].color = vColor;
v_tri[2].position = sf::Vector2f(M3D_V4GetX(V3), M3D_V4GetY(V3));
v_tri[2].color = vColor;
v_tri[3] = v_tri[0];
context.draw(v_tri, 4, sf::LineStrip, sRS);
//context.draw(v_tri, 3, sf::Triangles, sRS);
}
@ -164,6 +187,8 @@ void Graphic3DRenderer::Draw(sf::RenderTexture& context) {
}
}
}
}
}
void Graphic3DRenderer::UpdateInternalTestObjects() {
static float thetaAngle = 0.31f;
@ -177,3 +202,10 @@ void Graphic3DRenderer::UpdateInternalTestObjects() {
mRenderList[2]->SetRotation(thetaAngle3, 0.f, thetaAngle3 * 0.5f);
mRenderList[3]->SetRotation(0.f, thetaAngle, 0.f);
}
inline static bool VertexIsInsideClipSpace(M3D_F4& V) {
return (V.x > -V.w && V.x < V.w &&
V.y > -V.w && V.y < V.w &&
V.z > 0 && V.z < V.w
);
}

View File

@ -401,6 +401,7 @@ M3D_VECTOR M3D_V4OrInt(M3D_VECTOR V1, M3D_VECTOR V2) noexcept;
M3D_VECTOR M3D_V4Reciprocal(M3D_VECTOR V) noexcept;
M3D_VECTOR M3D_V4Sqrt(M3D_VECTOR V) noexcept;
M3D_VECTOR M3D_V4ModAngles(M3D_VECTOR Angles) noexcept;
bool M3D_V3LessOrEqual(M3D_VECTOR V1, M3D_VECTOR V2) noexcept;
M3D_VECTOR M3D_V3Dot(M3D_VECTOR V1, M3D_VECTOR V2) noexcept;
M3D_VECTOR M3D_V3Cross(M3D_VECTOR V1, M3D_VECTOR V2) noexcept;
M3D_VECTOR M3D_V3LengthSq(M3D_VECTOR V) noexcept;
@ -524,6 +525,8 @@ inline M3D_VECTOR M3D_V4Swizzle(M3D_VECTOR V) noexcept {
M3D_VECTOR M3D_QMultiply(M3D_VECTOR Q1, M3D_VECTOR Q2) noexcept;
M3D_VECTOR M3D_QConjugate(M3D_VECTOR Q) noexcept;
M3D_VECTOR M3D_TNormal(M3D_VECTOR P1, M3D_VECTOR P2, M3D_VECTOR P3) noexcept;
void M3D_V4SinCos(M3D_VECTOR* pSin, M3D_VECTOR* pCos, M3D_VECTOR V) noexcept;

View File

@ -1048,6 +1048,15 @@ inline M3D_VECTOR M3D_V4ModAngles(M3D_VECTOR Angles) noexcept {
#endif
}
inline bool M3D_V3LessOrEqual(M3D_VECTOR V1, M3D_VECTOR V2) noexcept {
#ifdef DISABLE_INTRINSICS
return (((V1.v4f[0] <= V2.v4f[0]) && (V1.v4f[1] <= V2.v4f[1]) && (V1.v4f[2] <= V2.v4f[2])) != 0);
#else
M3D_VECTOR vTemp = _mm_cmple_ps(V1, V2);
return (((_mm_movemask_ps(vTemp) & 7) == 7) != 0);
#endif
}
inline M3D_VECTOR M3D_V3Dot(M3D_VECTOR V1, M3D_VECTOR V2) noexcept {
#ifdef DISABLE_INTRINSICS
float fValue = V1.v4f[0] * V2.v4f[0] + V1.v4f[1] * V2.v4f[1] + V1.v4f[2] * V2.v4f[2];
@ -1304,6 +1313,13 @@ inline M3D_VECTOR M3D_QConjugate(M3D_VECTOR Q) noexcept {
#endif
}
inline M3D_VECTOR M3D_TNormal(M3D_VECTOR P1, M3D_VECTOR P2, M3D_VECTOR P3) noexcept {
M3D_VECTOR L1 = M3D_V4Subtract(P2, P1);
M3D_VECTOR L2 = M3D_V4Subtract(P3, P1);
return M3D_V3Normalize(M3D_V3Cross(L2, L1));
}
/* -------------------------------------------------------------------------------------------------------------------------- */