Clipping and backface culling
Culling isn't bad, clipping need a better approach to cut partial triangles.
This commit is contained in:
parent
54507108b3
commit
098345409f
@ -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,31 +141,49 @@ 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]]);
|
||||
|
||||
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);
|
||||
// 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));
|
||||
|
||||
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;
|
||||
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);
|
||||
|
||||
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;
|
||||
context.draw(v_tri, 4, sf::LineStrip, sRS);
|
||||
//context.draw(v_tri, 3, sf::Triangles, sRS);
|
||||
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[1].position = sf::Vector2f(M3D_V4GetX(V2), M3D_V4GetY(V2));
|
||||
v_tri[2].position = sf::Vector2f(M3D_V4GetX(V3), M3D_V4GetY(V3));
|
||||
v_tri[3] = v_tri[0];
|
||||
context.draw(v_tri, 4, sf::LineStrip, sRS);
|
||||
//context.draw(v_tri, 3, sf::Triangles, sRS);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -176,4 +201,11 @@ void Graphic3DRenderer::UpdateInternalTestObjects() {
|
||||
mRenderList[1]->SetRotation(thetaAngle2, 0.f, thetaAngle2 * 0.5f);
|
||||
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
|
||||
);
|
||||
}
|
@ -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;
|
||||
|
||||
|
||||
|
@ -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];
|
||||
@ -1244,12 +1253,12 @@ inline M3D_VECTOR M3D_V3Normalize(M3D_VECTOR V) noexcept {
|
||||
|
||||
inline M3D_VECTOR M3D_QMultiply(M3D_VECTOR Q1, M3D_VECTOR Q2) noexcept {
|
||||
#ifdef DISABLE_INTRINSICS
|
||||
M3D_V4F32 Result = { { {
|
||||
M3D_V4F32 Result = {{{
|
||||
(Q2.v4f[3] * Q1.v4f[0]) + (Q2.v4f[0] * Q1.v4f[3]) + (Q2.v4f[1] * Q1.v4f[2]) - (Q2.v4f[2] * Q1.v4f[1]),
|
||||
(Q2.v4f[3] * Q1.v4f[1]) - (Q2.v4f[0] * Q1.v4f[2]) + (Q2.v4f[1] * Q1.v4f[3]) + (Q2.v4f[2] * Q1.v4f[0]),
|
||||
(Q2.v4f[3] * Q1.v4f[2]) + (Q2.v4f[0] * Q1.v4f[1]) - (Q2.v4f[1] * Q1.v4f[0]) + (Q2.v4f[2] * Q1.v4f[3]),
|
||||
(Q2.v4f[3] * Q1.v4f[3]) - (Q2.v4f[0] * Q1.v4f[0]) - (Q2.v4f[1] * Q1.v4f[1]) - (Q2.v4f[2] * Q1.v4f[2])
|
||||
} } };
|
||||
}}};
|
||||
return Result.v;
|
||||
#else
|
||||
static const M3D_V4F32 ControlWZYX = {{{1.0f, -1.0f, 1.0f, -1.0f}}};
|
||||
@ -1304,24 +1313,31 @@ 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));
|
||||
}
|
||||
|
||||
|
||||
/* -------------------------------------------------------------------------------------------------------------------------- */
|
||||
|
||||
inline void M3D_V4SinCos(M3D_VECTOR* pSin, M3D_VECTOR* pCos, M3D_VECTOR V) noexcept {
|
||||
#ifdef DISABLE_INTRINSICS
|
||||
M3D_V4F32 Sin = { { {
|
||||
M3D_V4F32 Sin = {{{
|
||||
sinf(V.v4f[0]),
|
||||
sinf(V.v4f[1]),
|
||||
sinf(V.v4f[2]),
|
||||
sinf(V.v4f[3])
|
||||
} } };
|
||||
}}};
|
||||
|
||||
M3D_V4F32 Cos = { { {
|
||||
M3D_V4F32 Cos = {{{
|
||||
cosf(V.v4f[0]),
|
||||
cosf(V.v4f[1]),
|
||||
cosf(V.v4f[2]),
|
||||
cosf(V.v4f[3])
|
||||
} } };
|
||||
}}};
|
||||
|
||||
*pSin = Sin.v;
|
||||
*pCos = Cos.v;
|
||||
|
Loading…
x
Reference in New Issue
Block a user