Simple clipping approach

This commit is contained in:
JackCarterSmith 2024-10-31 19:42:04 +01:00
parent 184b9aa245
commit c0a00e4e4a
Signed by: JackCarterSmith
GPG Key ID: 832E52F4E23F8F24
8 changed files with 747 additions and 61 deletions

View File

@ -19,6 +19,9 @@
// * https://ktstephano.github.io/rendering/stratusgfx/aabbs
// * https://en.wikipedia.org/wiki/Clipping_(computer_graphics)
// * https://www.coranac.com/tonc/text/mode7.htm
// * https://en.wikipedia.org/wiki/Back-face_culling
// * https://en.wikipedia.org/wiki/Hidden-surface_determination#Occlusion_culling
// * https://en.wikipedia.org/wiki/Bounding_volume_hierarchy
Graphic3DRenderer::Graphic3DRenderer() {
mRTSize = {1280.f, 324.f};
@ -87,6 +90,82 @@ void Graphic3DRenderer::Draw(sf::RenderTexture& context) {
sf::RenderStates sRS(sBM);
// Hardcoded debug movement, TODO: remove it
UpdateInternalTestObjects();
// Load main matrices
M3D_MATRIX viewMat = mMainCamera->GetView();
M3D_MATRIX projMat = mMainCamera->GetProj();
M3D_MATRIX viewProjMat = viewMat * projMat;
// Create the frustrum "box"
M3D_BoundingFrustum camFrustrum(projMat, false);
camFrustrum.Transform(camFrustrum, M3D_MInverse(viewMat));
// Process scene's objects
for (auto& obj : mRenderList) {
M3D_BoundingBox projAABB = obj->GetAABB();
auto oTMat = obj->GetTransform();
// Object outside frustrum clipping
projAABB.Transform(projAABB, oTMat);
M3D_ContainmentType objInFrustrum = camFrustrum.Contains(projAABB);
if (objInFrustrum != DISJOINT) {
size_t vCount = obj->GetObjectVerticesCount();
auto& oMesh = obj->GetObjectMesh();
M3D_F3 projVertices[vCount];
// Vertices NDC space transformation
M3D_V3TransformPersDiv(
projVertices, sizeof(M3D_F3),
reinterpret_cast<const M3D_F3*>(oMesh.vertices.data()), sizeof(Vertex),
vCount,
oTMat * viewProjMat
);
// Draw the object indice triangles
sf::Vertex v_tri[4];
for (auto& objPt : oMesh.parts) {
auto indicePtr = static_cast<const uint32_t*>(objPt.indices.data());
for (uint32_t i = 0; i < objPt.GetIndicesCount(); i += 3) {
// Misscontructed indices tree failsafe
if (i+2 > objPt.GetIndicesCount())
break;
// 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]]);
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;
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);
}
}
}
}
}
void Graphic3DRenderer::UpdateInternalTestObjects() {
static float thetaAngle = 0.31f;
thetaAngle = thetaAngle >= 6.283185f ? -6.283185f : thetaAngle + 0.004f;
static float thetaAngle2 = 2.12f;
@ -97,62 +176,4 @@ void Graphic3DRenderer::Draw(sf::RenderTexture& context) {
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);
M3D_MATRIX viewProjMat = mMainCamera->GetView() * mMainCamera->GetProj();
sf::Vertex v_tri[4];
uint32_t totVerticesCnt = 0, processedVerticesCnt = 0;
for (auto obj : mRenderList)
totVerticesCnt += obj->GetObjectMesh().GetVerticesCount();
// Do the vertices projection and perspective divide
M3D_F3 projVertices[totVerticesCnt];
for (auto obj : mRenderList) {
auto& oMesh = obj->GetObjectMesh();
M3D_V3TransformPersDiv(
projVertices + processedVerticesCnt, sizeof(M3D_F3),
reinterpret_cast<const M3D_F3*>(oMesh.vertices.data()), sizeof(M3D_F4),
oMesh.vertices.size(),
obj->GetTransform() * viewProjMat
);
//TODO: Fill a z-depth buffer...
for (auto& objPt : obj->GetObjectMesh().parts) {
auto indicePtr = static_cast<const uint32_t*>(objPt.indices.data());
for (uint32_t i = 0; i < objPt.GetIndicesCount(); i += 3) {
// Misscontructed indices tree failsafe
if (i+2 > objPt.GetIndicesCount())
break;
//TODO: Proceed with z-test: if z is lesser than previous z, draw the pixel and update z
// Simple clipping
//TODO: implement complete Cohen-Sutherland algo or similar
if (((projVertices + processedVerticesCnt)[indicePtr[i]]).z > 0 &&
((projVertices + processedVerticesCnt)[indicePtr[i+1]]).z > 0 &&
((projVertices + processedVerticesCnt)[indicePtr[i+2]]).z > 0) {
M3D_VECTOR V1 = M3D_V4LoadF3(&(projVertices + processedVerticesCnt)[indicePtr[i]]);
M3D_VECTOR V2 = M3D_V4LoadF3(&(projVertices + processedVerticesCnt)[indicePtr[i+1]]);
M3D_VECTOR V3 = M3D_V4LoadF3(&(projVertices + processedVerticesCnt)[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);
v_tri[0].position = sf::Vector2f(M3D_V4GetX(V1), M3D_V4GetY(V1));
v_tri[0].color = oMesh.vertices[indicePtr[i]].color;
v_tri[3] = v_tri[0];
v_tri[1].position = sf::Vector2f(M3D_V4GetX(V2), M3D_V4GetY(V2));
v_tri[1].color = oMesh.vertices[indicePtr[i+1]].color;
v_tri[2].position = sf::Vector2f(M3D_V4GetX(V3), M3D_V4GetY(V3));
v_tri[2].color = oMesh.vertices[indicePtr[i+2]].color;
context.draw(v_tri, 4, sf::LineStrip, sRS);
//context.draw(v_tri, 3, sf::Triangles, sRS);
}
}
}
processedVerticesCnt += oMesh.GetVerticesCount();
}
}

View File

@ -38,4 +38,6 @@ private:
std::vector<std::shared_ptr<WorldObject>> mRenderList; // List of elements to be rendered next frame
void UpdateInternalTestObjects();
};

View File

@ -16,9 +16,9 @@ public:
M3D_VECTOR GetPos() const { return M3D_V4LoadF3(&mPos); }
M3D_F3 GetPos3f() const { return mPos; }
M3D_MATRIX GetView() const { return M3D_V4LoadF4x4(&mViewMat); }
M3D_F4X4 GetView4x4f() const { return mViewMat; }
const M3D_F4X4& GetView4x4f() const { return mViewMat; }
M3D_MATRIX GetProj() const { return M3D_V4LoadF4x4(&mProjMat); }
M3D_F4X4 GetProj4x4f() const { return mProjMat; }
const M3D_F4X4& GetProj4x4f() const { return mProjMat; }
void SetPosition(const float x, const float y, const float z) { mPos = M3D_F3(x, y, z); }
void SetPosition(const M3D_F3 v) { mPos = v; }

View File

@ -596,6 +596,248 @@ constexpr M3D_F4X4 M3D_MIdentity4x4() {
return I;
}
//
// Collision enums and structures definition
//
enum M3D_ContainmentType {
DISJOINT = 0,
INTERSECTS = 1,
CONTAINS = 2
};
enum M3D_PlaneIntersectionType {
FRONT = 0,
INTERSECTING = 1,
BACK = 2
};
struct M3D_BoundingBox; // AABB uhuh :3
struct M3D_BoundingOrientedBox;
struct M3D_BoundingFrustum;
struct M3D_BoundingSphere {
M3D_F3 Center;
float Radius;
M3D_BoundingSphere() noexcept : Center(0, 0, 0), Radius(1.f) {}
M3D_BoundingSphere(const M3D_BoundingSphere&) = default;
M3D_BoundingSphere& operator=(const M3D_BoundingSphere&) = default;
M3D_BoundingSphere(M3D_BoundingSphere&&) = default;
M3D_BoundingSphere& operator=(M3D_BoundingSphere&&) = default;
constexpr M3D_BoundingSphere(const M3D_F3& center, float radius) noexcept : Center(center), Radius(radius) {}
void Transform(M3D_BoundingSphere& Out, M3D_MATRIX M) const noexcept;
void Transform(M3D_BoundingSphere& Out, float Scale, M3D_VECTOR Rotation, M3D_VECTOR Translation) const noexcept;
M3D_ContainmentType Contains(M3D_VECTOR Point) const noexcept;
M3D_ContainmentType Contains(M3D_VECTOR V0, M3D_VECTOR V1, M3D_VECTOR V2) const noexcept;
M3D_ContainmentType Contains(const M3D_BoundingSphere& sh) const noexcept;
M3D_ContainmentType Contains(const M3D_BoundingBox& box) const noexcept;
M3D_ContainmentType Contains(const M3D_BoundingOrientedBox& box) const noexcept;
M3D_ContainmentType Contains(const M3D_BoundingFrustum& fr) const noexcept;
bool Intersects(const M3D_BoundingSphere& sh) const noexcept;
bool Intersects(const M3D_BoundingBox& box) const noexcept;
bool Intersects(const M3D_BoundingOrientedBox& box) const noexcept;
bool Intersects(const M3D_BoundingFrustum& fr) const noexcept;
bool Intersects(M3D_VECTOR V0, M3D_VECTOR V1, M3D_VECTOR V2) const noexcept;
M3D_PlaneIntersectionType Intersects(M3D_VECTOR Plane) const noexcept;
bool Intersects(M3D_VECTOR Origin, M3D_VECTOR Direction, float& Dist) const noexcept;
M3D_ContainmentType ContainedBy(M3D_VECTOR Plane0, M3D_VECTOR Plane1, M3D_VECTOR Plane2,
M3D_VECTOR& Plane3, M3D_VECTOR& Plane4, M3D_VECTOR& Plane5) const noexcept;
static void CreateMerged(M3D_BoundingSphere& Out, const M3D_BoundingSphere& S1, const M3D_BoundingSphere& S2) noexcept;
static void CreateFromBoundingBox(M3D_BoundingSphere& Out, const M3D_BoundingBox& box) noexcept;
static void CreateFromBoundingBox(M3D_BoundingSphere& Out, const M3D_BoundingOrientedBox& box) noexcept;
static void CreateFromPoints(M3D_BoundingSphere& Out, size_t Count, const M3D_F3* pPoints, size_t Stride) noexcept;
};
struct M3D_BoundingBox {
static constexpr size_t CORNER_COUNT = 8;
M3D_F3 Center;
M3D_F3 Extents;
M3D_BoundingBox() noexcept : Center(0, 0, 0), Extents(1.f, 1.f, 1.f) {}
M3D_BoundingBox(const M3D_BoundingBox&) = default;
M3D_BoundingBox& operator=(const M3D_BoundingBox&) = default;
M3D_BoundingBox(M3D_BoundingBox&&) = default;
M3D_BoundingBox& operator=(M3D_BoundingBox&&) = default;
constexpr M3D_BoundingBox(const M3D_F3& center, const M3D_F3& extents) noexcept : Center(center), Extents(extents) {}
void Transform(M3D_BoundingBox& Out, M3D_MATRIX M) const noexcept;
void Transform(M3D_BoundingBox& Out, float Scale, M3D_VECTOR Rotation, M3D_VECTOR Translation) const noexcept;
void GetCorners(M3D_F3* Corners) const noexcept;
M3D_ContainmentType Contains(M3D_VECTOR Point) const noexcept;
M3D_ContainmentType Contains(M3D_VECTOR V0, M3D_VECTOR V1, M3D_VECTOR V2) const noexcept;
M3D_ContainmentType Contains(const M3D_BoundingSphere& sh) const noexcept;
M3D_ContainmentType Contains(const M3D_BoundingBox& box) const noexcept;
M3D_ContainmentType Contains(const M3D_BoundingOrientedBox& box) const noexcept;
M3D_ContainmentType Contains(const M3D_BoundingFrustum& fr) const noexcept;
bool Intersects(const M3D_BoundingSphere& sh) const noexcept;
bool Intersects(const M3D_BoundingBox& box) const noexcept;
bool Intersects(const M3D_BoundingOrientedBox& box) const noexcept;
bool Intersects(const M3D_BoundingFrustum& fr) const noexcept;
bool Intersects(M3D_VECTOR V0, M3D_VECTOR V1, M3D_VECTOR V2) const noexcept;
M3D_PlaneIntersectionType Intersects(M3D_VECTOR Plane) const noexcept;
bool Intersects(M3D_VECTOR Origin, M3D_VECTOR Direction, float& Dist) const noexcept;
M3D_ContainmentType ContainedBy(M3D_VECTOR Plane0, M3D_VECTOR Plane1, M3D_VECTOR Plane2,
M3D_VECTOR& Plane3, M3D_VECTOR& Plane4, M3D_VECTOR& Plane5) const noexcept;
static void CreateMerged(M3D_BoundingBox& Out, const M3D_BoundingBox& b1, const M3D_BoundingBox& b2) noexcept;
static void CreateFromSphere(M3D_BoundingBox& Out, const M3D_BoundingSphere& sh) noexcept;
static void CreateFromPoints(M3D_BoundingBox& Out, M3D_VECTOR pt1, M3D_VECTOR pt2) noexcept;
static void CreateFromPoints(M3D_BoundingBox& Out, size_t Count, const M3D_F3* pPoints, size_t Stride) noexcept;
};
struct M3D_BoundingOrientedBox {
static constexpr size_t CORNER_COUNT = 8;
M3D_F3 Center;
M3D_F3 Extents;
M3D_F4 Orientation; // Unit quaternion representing rotation (box -> world).
M3D_BoundingOrientedBox() noexcept : Center(0, 0, 0), Extents(1.f, 1.f, 1.f), Orientation(0, 0, 0, 1.f) {}
M3D_BoundingOrientedBox(const M3D_BoundingOrientedBox&) = default;
M3D_BoundingOrientedBox& operator=(const M3D_BoundingOrientedBox&) = default;
M3D_BoundingOrientedBox(M3D_BoundingOrientedBox&&) = default;
M3D_BoundingOrientedBox& operator=(M3D_BoundingOrientedBox&&) = default;
constexpr M3D_BoundingOrientedBox(const M3D_F3& center, const M3D_F3& extents, const M3D_F4& orientation) noexcept
: Center(center), Extents(extents), Orientation(orientation) {}
void Transform(M3D_BoundingOrientedBox& Out, M3D_MATRIX M) const noexcept;
void Transform(M3D_BoundingOrientedBox& Out, float Scale, M3D_VECTOR Rotation, M3D_VECTOR Translation) const noexcept;
void GetCorners(M3D_F3* Corners) const noexcept;
M3D_ContainmentType Contains(M3D_VECTOR Point) const noexcept;
M3D_ContainmentType Contains(M3D_VECTOR V0, M3D_VECTOR V1, M3D_VECTOR V2) const noexcept;
M3D_ContainmentType Contains(const M3D_BoundingSphere& sh) const noexcept;
M3D_ContainmentType Contains(const M3D_BoundingBox& box) const noexcept;
M3D_ContainmentType Contains(const M3D_BoundingOrientedBox& box) const noexcept;
M3D_ContainmentType Contains(const M3D_BoundingFrustum& fr) const noexcept;
bool Intersects(const M3D_BoundingSphere& sh) const noexcept;
bool Intersects(const M3D_BoundingBox& box) const noexcept;
bool Intersects(const M3D_BoundingOrientedBox& box) const noexcept;
bool Intersects(const M3D_BoundingFrustum& fr) const noexcept;
bool Intersects(M3D_VECTOR V0, M3D_VECTOR V1, M3D_VECTOR V2) const noexcept;
M3D_PlaneIntersectionType Intersects(M3D_VECTOR Plane) const noexcept;
bool Intersects(M3D_VECTOR Origin, M3D_VECTOR Direction, float& Dist) const noexcept;
M3D_ContainmentType ContainedBy(M3D_VECTOR Plane0, M3D_VECTOR Plane1, M3D_VECTOR Plane2,
M3D_VECTOR& Plane3, M3D_VECTOR& Plane4, M3D_VECTOR& Plane5) const noexcept;
static void CreateFromBoundingBox(M3D_BoundingOrientedBox& Out, const M3D_BoundingBox& box) noexcept;
static void CreateFromPoints(M3D_BoundingOrientedBox& Out, size_t Count, const M3D_F3* pPoints, size_t Stride) noexcept;
};
struct M3D_BoundingFrustum {
static constexpr size_t CORNER_COUNT = 8;
M3D_F3 Origin;
M3D_F4 Orientation; // Quaternion representing rotation.
float RightSlope; // Positive X (X/Z)
float LeftSlope; // Negative X
float TopSlope; // Positive Y (Y/Z)
float BottomSlope; // Negative Y
float Near, Far; // Z of the near plane and far plane.
M3D_BoundingFrustum() noexcept :
Origin(0, 0, 0), Orientation(0, 0, 0, 1.f), RightSlope(1.f), LeftSlope(-1.f),
TopSlope(1.f), BottomSlope(-1.f), Near(0), Far(1.f) {}
M3D_BoundingFrustum(const M3D_BoundingFrustum&) = default;
M3D_BoundingFrustum& operator=(const M3D_BoundingFrustum&) = default;
M3D_BoundingFrustum(M3D_BoundingFrustum&&) = default;
M3D_BoundingFrustum& operator=(M3D_BoundingFrustum&&) = default;
constexpr M3D_BoundingFrustum(const M3D_F3& origin, const M3D_F4& orientation,
float rightSlope, float leftSlope, float topSlope, float bottomSlope,
float nearPlane, float farPlane) noexcept
: Origin(origin), Orientation(orientation),
RightSlope(rightSlope), LeftSlope(leftSlope), TopSlope(topSlope), BottomSlope(bottomSlope),
Near(nearPlane), Far(farPlane) {}
M3D_BoundingFrustum(M3D_MATRIX Projection, bool rhcoords = false) noexcept;
void Transform(M3D_BoundingFrustum& Out, M3D_MATRIX M) const noexcept;
void Transform(M3D_BoundingFrustum& Out, float Scale, M3D_VECTOR Rotation, M3D_VECTOR Translation) const noexcept;
void GetCorners(M3D_F3* Corners) const noexcept;
M3D_ContainmentType Contains(M3D_VECTOR Point) const noexcept;
M3D_ContainmentType Contains(M3D_VECTOR V0, M3D_VECTOR V1, M3D_VECTOR V2) const noexcept;
M3D_ContainmentType Contains(const M3D_BoundingSphere& sp) const noexcept;
M3D_ContainmentType Contains(const M3D_BoundingBox& box) const noexcept;
M3D_ContainmentType Contains(const M3D_BoundingOrientedBox& box) const noexcept;
M3D_ContainmentType Contains(const M3D_BoundingFrustum& fr) const noexcept;
bool Intersects(const M3D_BoundingSphere& sh) const noexcept;
bool Intersects(const M3D_BoundingBox& box) const noexcept;
bool Intersects(const M3D_BoundingOrientedBox& box) const noexcept;
bool Intersects(const M3D_BoundingFrustum& fr) const noexcept;
bool Intersects(M3D_VECTOR V0, M3D_VECTOR V1, M3D_VECTOR V2) const noexcept;
M3D_PlaneIntersectionType Intersects(M3D_VECTOR Plane) const noexcept;
bool Intersects(M3D_VECTOR rayOrigin, M3D_VECTOR Direction, float& Dist) const noexcept;
M3D_ContainmentType ContainedBy(M3D_VECTOR Plane0, M3D_VECTOR Plane1, M3D_VECTOR Plane2,
M3D_VECTOR& Plane3, M3D_VECTOR& Plane4, M3D_VECTOR& Plane5) const noexcept;
void GetPlanes(M3D_VECTOR* NearPlane, M3D_VECTOR* FarPlane, M3D_VECTOR* RightPlane,
M3D_VECTOR* LeftPlane, M3D_VECTOR* TopPlane, M3D_VECTOR* BottomPlane) const noexcept;
static void CreateFromMatrix(M3D_BoundingFrustum& Out, M3D_MATRIX Projection, bool rhcoords = false) noexcept;
};
namespace M3D_TriangleTests {
bool Intersects(M3D_VECTOR Origin, M3D_VECTOR Direction, M3D_VECTOR V0, M3D_VECTOR& V1, M3D_VECTOR& V2, float& Dist) noexcept;
bool Intersects(M3D_VECTOR A0, M3D_VECTOR A1, M3D_VECTOR A2, M3D_VECTOR& B0, M3D_VECTOR& B1, M3D_VECTOR& B2) noexcept;
M3D_PlaneIntersectionType Intersects(M3D_VECTOR V0, M3D_VECTOR V1, M3D_VECTOR V2, M3D_VECTOR& Plane) noexcept;
M3D_ContainmentType ContainedBy(M3D_VECTOR V0, M3D_VECTOR V1, M3D_VECTOR V2,
M3D_VECTOR& Plane0, M3D_VECTOR& Plane1, M3D_VECTOR& Plane2,
M3D_VECTOR& Plane3, M3D_VECTOR& Plane4, M3D_VECTOR& Plane5) noexcept;
}
M3D_GCONST M3D_V4F32 M3D_BRayEpsilon = {{{1e-20f, 1e-20f, 1e-20f, 1e-20f}}};
M3D_GCONST M3D_V4F32 M3D_BRayNegEpsilon = {{{-1e-20f, -1e-20f, -1e-20f, -1e-20f}}};
M3D_GCONST M3D_V4F32 M3D_BFltMin = {{{-__FLT_MAX__, -__FLT_MAX__, -__FLT_MAX__, -__FLT_MAX__}}};
M3D_GCONST M3D_V4F32 M3D_BFltMax = {{{__FLT_MAX__, __FLT_MAX__, __FLT_MAX__, __FLT_MAX__}}};
M3D_GCONST M3D_V4F32 M3D_BBoxOffset[8] = {
{{{-1.0f, -1.0f, 1.0f, 0.0f}}},
{{{ 1.0f, -1.0f, 1.0f, 0.0f}}},
{{{ 1.0f, 1.0f, 1.0f, 0.0f}}},
{{{-1.0f, 1.0f, 1.0f, 0.0f}}},
{{{-1.0f, -1.0f, -1.0f, 0.0f}}},
{{{ 1.0f, -1.0f, -1.0f, 0.0f}}},
{{{ 1.0f, 1.0f, -1.0f, 0.0f}}},
{{{-1.0f, 1.0f, -1.0f, 0.0f}}},
};
#include "3DMaths_vec.inl"
#include "3DMaths_mat.inl"
#include "3DMaths_bs.inl"

View File

@ -10,3 +10,411 @@ namespace M3D_Internal {
return vNormal;
}
}
inline void FastIntersectAxisAlignedBoxPlane(M3D_VECTOR Center, M3D_VECTOR Extents, M3D_VECTOR Plane, M3D_VECTOR& Outside, M3D_VECTOR& Inside) noexcept {
// Compute the distance to the center of the box.
M3D_VECTOR Dist = M3D_V4Dot(Center, Plane);
// Project the axes of the box onto the normal of the plane. Half the
// length of the projection (sometime called the "radius") is equal to
// h(u) * abs(n dot b(u))) + h(v) * abs(n dot b(v)) + h(w) * abs(n dot b(w))
// where h(i) are extents of the box, n is the plane normal, and b(i) are the
// axes of the box. In this case b(i) = [(1,0,0), (0,1,0), (0,0,1)].
M3D_VECTOR Radius = M3D_V3Dot(Extents, M3D_V4Abs(Plane));
// Outside the plane?
Outside = M3D_V4Greater(Dist, Radius);
// Fully inside the plane?
Inside = M3D_V4Less(Dist, M3D_V4Negate(Radius));
}
inline void FastIntersectTrianglePlane(M3D_VECTOR V0, M3D_VECTOR V1, M3D_VECTOR V2,
M3D_VECTOR& Plane, M3D_VECTOR& Outside, M3D_VECTOR& Inside) noexcept {
// Plane0
M3D_VECTOR Dist0 = M3D_V4Dot(V0, Plane);
M3D_VECTOR Dist1 = M3D_V4Dot(V1, Plane);
M3D_VECTOR Dist2 = M3D_V4Dot(V2, Plane);
M3D_VECTOR MinDist = M3D_V4Min(Dist0, Dist1);
MinDist = M3D_V4Min(MinDist, Dist2);
M3D_VECTOR MaxDist = M3D_V4Max(Dist0, Dist1);
MaxDist = M3D_V4Max(MaxDist, Dist2);
M3D_VECTOR Zero = M3D_V4Zero();
// Outside the plane?
Outside = M3D_V4Greater(MinDist, Zero);
// Fully inside the plane?
Inside = M3D_V4Less(MaxDist, Zero);
}
inline M3D_ContainmentType M3D_BoundingBox::ContainedBy(M3D_VECTOR Plane0, M3D_VECTOR Plane1, M3D_VECTOR Plane2,
M3D_VECTOR& Plane3, M3D_VECTOR& Plane4, M3D_VECTOR& Plane5) const noexcept {
// Load the box.
M3D_VECTOR vCenter = M3D_V4LoadF3(&Center);
M3D_VECTOR vExtents = M3D_V4LoadF3(&Extents);
// Set w of the center to one so we can dot4 with a plane.
vCenter = M3D_V4SetW(vCenter, 1.0f);
M3D_VECTOR Outside, Inside;
// Test against each plane.
FastIntersectAxisAlignedBoxPlane(vCenter, vExtents, Plane0, Outside, Inside);
M3D_VECTOR AnyOutside = Outside;
M3D_VECTOR AllInside = Inside;
FastIntersectAxisAlignedBoxPlane(vCenter, vExtents, Plane1, Outside, Inside);
AnyOutside = M3D_V4OrInt(AnyOutside, Outside);
AllInside = M3D_V4AndInt(AllInside, Inside);
FastIntersectAxisAlignedBoxPlane(vCenter, vExtents, Plane2, Outside, Inside);
AnyOutside = M3D_V4OrInt(AnyOutside, Outside);
AllInside = M3D_V4AndInt(AllInside, Inside);
FastIntersectAxisAlignedBoxPlane(vCenter, vExtents, Plane3, Outside, Inside);
AnyOutside = M3D_V4OrInt(AnyOutside, Outside);
AllInside = M3D_V4AndInt(AllInside, Inside);
FastIntersectAxisAlignedBoxPlane(vCenter, vExtents, Plane4, Outside, Inside);
AnyOutside = M3D_V4OrInt(AnyOutside, Outside);
AllInside = M3D_V4AndInt(AllInside, Inside);
FastIntersectAxisAlignedBoxPlane(vCenter, vExtents, Plane5, Outside, Inside);
AnyOutside = M3D_V4OrInt(AnyOutside, Outside);
AllInside = M3D_V4AndInt(AllInside, Inside);
// If the box is outside any plane it is outside.
if (M3D_V4EqualInt(AnyOutside, M3D_V4TrueInt()))
return DISJOINT;
// If the box is inside all planes it is inside.
if (M3D_V4EqualInt(AllInside, M3D_V4TrueInt()))
return CONTAINS;
// The box is not inside all planes or outside a plane, it may intersect.
return INTERSECTS;
}
/* -------------------------------------------------------------------------------------------------------------------------- */
inline void M3D_BoundingBox::CreateFromPoints(M3D_BoundingBox& Out, M3D_VECTOR pt1, M3D_VECTOR pt2) noexcept {
M3D_VECTOR Min = M3D_V4Min(pt1, pt2);
M3D_VECTOR Max = M3D_V4Max(pt1, pt2);
M3D_V4StoreF3(&Out.Center, M3D_V4Scale(M3D_V4Add(Min, Max), 0.5f));
M3D_V4StoreF3(&Out.Extents, M3D_V4Scale(M3D_V4Subtract(Max, Min), 0.5f));
}
inline void M3D_BoundingBox::CreateFromPoints(M3D_BoundingBox& Out, size_t Count, const M3D_F3* pPoints, size_t Stride) noexcept {
// Find the minimum and maximum x, y, and z
M3D_VECTOR vMin, vMax;
vMin = vMax = M3D_V4LoadF3(pPoints);
for (size_t i = 1; i < Count; ++i) {
M3D_VECTOR Point = M3D_V4LoadF3(reinterpret_cast<const M3D_F3*>(reinterpret_cast<const uint8_t*>(pPoints) + i * Stride));
vMin = M3D_V4Min(vMin, Point);
vMax = M3D_V4Max(vMax, Point);
}
// Store center and extents.
M3D_V4StoreF3(&Out.Center, M3D_V4Scale(M3D_V4Add(vMin, vMax), 0.5f));
M3D_V4StoreF3(&Out.Extents, M3D_V4Scale(M3D_V4Subtract(vMax, vMin), 0.5f));
}
inline void M3D_BoundingBox::Transform(M3D_BoundingBox& Out, M3D_MATRIX M) const noexcept {
// Load center and extents.
M3D_VECTOR vCenter = M3D_V4LoadF3(&Center);
M3D_VECTOR vExtents = M3D_V4LoadF3(&Extents);
// Compute and transform the corners and find new min/max bounds.
M3D_VECTOR Corner = M3D_V4MultiplyAdd(vExtents, M3D_BBoxOffset[0], vCenter);
Corner = M3D_V3Transform(Corner, M);
M3D_VECTOR Min, Max;
Min = Max = Corner;
for (size_t i = 1; i < CORNER_COUNT; ++i) {
Corner = M3D_V4MultiplyAdd(vExtents, M3D_BBoxOffset[i], vCenter);
Corner = M3D_V3Transform(Corner, M);
Min = M3D_V4Min(Min, Corner);
Max = M3D_V4Max(Max, Corner);
}
// Store center and extents.
M3D_V4StoreF3(&Out.Center, M3D_V4Scale(M3D_V4Add(Min, Max), 0.5f));
M3D_V4StoreF3(&Out.Extents, M3D_V4Scale(M3D_V4Subtract(Max, Min), 0.5f));
}
inline void M3D_BoundingBox::GetCorners(M3D_F3* Corners) const noexcept {
M3D_VECTOR vCenter = M3D_V4LoadF3(&Center);
M3D_VECTOR vExtents = M3D_V4LoadF3(&Extents);
for (size_t i = 0; i < CORNER_COUNT; ++i) {
M3D_VECTOR C = M3D_V4MultiplyAdd(vExtents, M3D_BBoxOffset[i], vCenter);
M3D_V4StoreF3(&Corners[i], C);
}
}
inline M3D_BoundingFrustum::M3D_BoundingFrustum(M3D_MATRIX Projection, bool rhcoords) noexcept {
CreateFromMatrix(*this, Projection, rhcoords);
}
inline void M3D_BoundingFrustum::Transform(M3D_BoundingFrustum& Out, M3D_MATRIX M) const noexcept {
// Load the frustum.
M3D_VECTOR vOrigin = M3D_V4LoadF3(&Origin);
M3D_VECTOR vOrientation = M3D_V4LoadF4(&Orientation);
// Composite the frustum rotation and the transform rotation
M3D_MATRIX nM;
nM.rows[0] = M3D_V3Normalize(M.rows[0]);
nM.rows[1] = M3D_V3Normalize(M.rows[1]);
nM.rows[2] = M3D_V3Normalize(M.rows[2]);
nM.rows[3] = M3D_MIdentityR3;
M3D_VECTOR Rotation = M3D_QRotationMatrix(nM);
vOrientation = M3D_QMultiply(vOrientation, Rotation);
// Transform the center.
vOrigin = M3D_V3Transform(vOrigin, M);
// Store the frustum.
M3D_V4StoreF3(&Out.Origin, vOrigin);
M3D_V4StoreF4(&Out.Orientation, vOrientation);
// Scale the near and far distances (the slopes remain the same).
M3D_VECTOR dX = M3D_V3Dot(M.rows[0], M.rows[0]);
M3D_VECTOR dY = M3D_V3Dot(M.rows[1], M.rows[1]);
M3D_VECTOR dZ = M3D_V3Dot(M.rows[2], M.rows[2]);
M3D_VECTOR d = M3D_V4Max(dX, M3D_V4Max(dY, dZ));
float Scale = sqrtf(M3D_V4GetX(d));
Out.Near = Near * Scale;
Out.Far = Far * Scale;
// Copy the slopes.
Out.RightSlope = RightSlope;
Out.LeftSlope = LeftSlope;
Out.TopSlope = TopSlope;
Out.BottomSlope = BottomSlope;
}
inline void M3D_BoundingFrustum::GetCorners(M3D_F3* Corners) const noexcept {
// Load origin and orientation of the frustum.
M3D_VECTOR vOrigin = M3D_V4LoadF3(&Origin);
M3D_VECTOR vOrientation = M3D_V4LoadF4(&Orientation);
// Build the corners of the frustum.
M3D_VECTOR vRightTop = M3D_V4Set(RightSlope, TopSlope, 1.0f, 0.0f);
M3D_VECTOR vRightBottom = M3D_V4Set(RightSlope, BottomSlope, 1.0f, 0.0f);
M3D_VECTOR vLeftTop = M3D_V4Set(LeftSlope, TopSlope, 1.0f, 0.0f);
M3D_VECTOR vLeftBottom = M3D_V4Set(LeftSlope, BottomSlope, 1.0f, 0.0f);
M3D_VECTOR vNear = M3D_V4ReplicatePtr(&Near);
M3D_VECTOR vFar = M3D_V4ReplicatePtr(&Far);
// Returns 8 corners position of bounding frustum.
// Near Far
// 0----1 4----5
// | | | |
// | | | |
// 3----2 7----6
M3D_VECTOR vCorners[CORNER_COUNT];
vCorners[0] = M3D_V4Multiply(vLeftTop, vNear);
vCorners[1] = M3D_V4Multiply(vRightTop, vNear);
vCorners[2] = M3D_V4Multiply(vRightBottom, vNear);
vCorners[3] = M3D_V4Multiply(vLeftBottom, vNear);
vCorners[4] = M3D_V4Multiply(vLeftTop, vFar);
vCorners[5] = M3D_V4Multiply(vRightTop, vFar);
vCorners[6] = M3D_V4Multiply(vRightBottom, vFar);
vCorners[7] = M3D_V4Multiply(vLeftBottom, vFar);
for (size_t i = 0; i < CORNER_COUNT; ++i) {
M3D_VECTOR C = M3D_V4Add(M3D_V3Rotate(vCorners[i], vOrientation), vOrigin);
M3D_V4StoreF3(&Corners[i], C);
}
}
inline M3D_ContainmentType M3D_BoundingFrustum::Contains(const M3D_BoundingBox& box) const noexcept {
// Load origin and orientation of the frustum.
M3D_VECTOR vOrigin = M3D_V4LoadF3(&Origin);
M3D_VECTOR vOrientation = M3D_V4LoadF4(&Orientation);
// Create 6 planes (do it inline to encourage use of registers)
M3D_VECTOR NearPlane = M3D_V4Set(0.0f, 0.0f, -1.0f, Near);
NearPlane = M3D_Internal::M3D_PTransform(NearPlane, vOrientation, vOrigin);
NearPlane = M3D_V3Normalize(NearPlane);
M3D_VECTOR FarPlane = M3D_V4Set(0.0f, 0.0f, 1.0f, -Far);
FarPlane = M3D_Internal::M3D_PTransform(FarPlane, vOrientation, vOrigin);
FarPlane = M3D_V3Normalize(FarPlane);
M3D_VECTOR RightPlane = M3D_V4Set(1.0f, 0.0f, -RightSlope, 0.0f);
RightPlane = M3D_Internal::M3D_PTransform(RightPlane, vOrientation, vOrigin);
RightPlane = M3D_V3Normalize(RightPlane);
M3D_VECTOR LeftPlane = M3D_V4Set(-1.0f, 0.0f, LeftSlope, 0.0f);
LeftPlane = M3D_Internal::M3D_PTransform(LeftPlane, vOrientation, vOrigin);
LeftPlane = M3D_V3Normalize(LeftPlane);
M3D_VECTOR TopPlane = M3D_V4Set(0.0f, 1.0f, -TopSlope, 0.0f);
TopPlane = M3D_Internal::M3D_PTransform(TopPlane, vOrientation, vOrigin);
TopPlane = M3D_V3Normalize(TopPlane);
M3D_VECTOR BottomPlane = M3D_V4Set(0.0f, -1.0f, BottomSlope, 0.0f);
BottomPlane = M3D_Internal::M3D_PTransform(BottomPlane, vOrientation, vOrigin);
BottomPlane = M3D_V3Normalize(BottomPlane);
return box.ContainedBy(NearPlane, FarPlane, RightPlane, LeftPlane, TopPlane, BottomPlane);
}
inline void M3D_BoundingFrustum::GetPlanes(M3D_VECTOR* NearPlane, M3D_VECTOR* FarPlane, M3D_VECTOR* RightPlane,
M3D_VECTOR* LeftPlane, M3D_VECTOR* TopPlane, M3D_VECTOR* BottomPlane) const noexcept {
// Load origin and orientation of the frustum.
M3D_VECTOR vOrigin = M3D_V4LoadF3(&Origin);
M3D_VECTOR vOrientation = M3D_V4LoadF4(&Orientation);
if (NearPlane) {
M3D_VECTOR vNearPlane = M3D_V4Set(0.0f, 0.0f, -1.0f, Near);
vNearPlane = M3D_Internal::M3D_PTransform(vNearPlane, vOrientation, vOrigin);
*NearPlane = M3D_V3Normalize(vNearPlane);
}
if (FarPlane) {
M3D_VECTOR vFarPlane = M3D_V4Set(0.0f, 0.0f, 1.0f, -Far);
vFarPlane = M3D_Internal::M3D_PTransform(vFarPlane, vOrientation, vOrigin);
*FarPlane = M3D_V3Normalize(vFarPlane);
}
if (RightPlane) {
M3D_VECTOR vRightPlane = M3D_V4Set(1.0f, 0.0f, -RightSlope, 0.0f);
vRightPlane = M3D_Internal::M3D_PTransform(vRightPlane, vOrientation, vOrigin);
*RightPlane = M3D_V3Normalize(vRightPlane);
}
if (LeftPlane) {
M3D_VECTOR vLeftPlane = M3D_V4Set(-1.0f, 0.0f, LeftSlope, 0.0f);
vLeftPlane = M3D_Internal::M3D_PTransform(vLeftPlane, vOrientation, vOrigin);
*LeftPlane = M3D_V3Normalize(vLeftPlane);
}
if (TopPlane) {
M3D_VECTOR vTopPlane = M3D_V4Set(0.0f, 1.0f, -TopSlope, 0.0f);
vTopPlane = M3D_Internal::M3D_PTransform(vTopPlane, vOrientation, vOrigin);
*TopPlane = M3D_V3Normalize(vTopPlane);
}
if (BottomPlane) {
M3D_VECTOR vBottomPlane = M3D_V4Set(0.0f, -1.0f, BottomSlope, 0.0f);
vBottomPlane = M3D_Internal::M3D_PTransform(vBottomPlane, vOrientation, vOrigin);
*BottomPlane = M3D_V3Normalize(vBottomPlane);
}
}
inline void M3D_BoundingFrustum::CreateFromMatrix(M3D_BoundingFrustum& Out, M3D_MATRIX Projection, bool rhcoords) noexcept {
// Corners of the projection frustum in NDC space.
static M3D_V4F32 NDCPoints[6] = {
{{{1.0f, 0.0f, 1.0f, 1.0f}}}, // right (at far plane)
{{{-1.0f, 0.0f, 1.0f, 1.0f}}}, // left
{{{0.0f, 1.0f, 1.0f, 1.0f}}}, // top
{{{0.0f, -1.0f, 1.0f, 1.0f}}}, // bottom
{{{0.0f, 0.0f, 0.0f, 1.0f}}}, // near
{{{0.0f, 0.0f, 1.0f, 1.0f}}} // far
};
M3D_MATRIX matInverse = M3D_MInverse(Projection);
// Compute the frustum corners in world space.
M3D_VECTOR Points[6];
for (size_t i = 0; i < 6; ++i) {
// Transform point.
Points[i] = M3D_V4Transform(NDCPoints[i], matInverse);
}
Out.Origin = M3D_F3(0.0f, 0.0f, 0.0f);
Out.Orientation = M3D_F4(0.0f, 0.0f, 0.0f, 1.0f);
// Compute the slopes.
Points[0] = M3D_V4Multiply(Points[0], M3D_V4Reciprocal(M3D_V4SplatZ(Points[0])));
Points[1] = M3D_V4Multiply(Points[1], M3D_V4Reciprocal(M3D_V4SplatZ(Points[1])));
Points[2] = M3D_V4Multiply(Points[2], M3D_V4Reciprocal(M3D_V4SplatZ(Points[2])));
Points[3] = M3D_V4Multiply(Points[3], M3D_V4Reciprocal(M3D_V4SplatZ(Points[3])));
Out.RightSlope = M3D_V4GetX(Points[0]);
Out.LeftSlope = M3D_V4GetX(Points[1]);
Out.TopSlope = M3D_V4GetY(Points[2]);
Out.BottomSlope = M3D_V4GetY(Points[3]);
// Compute near and far.
Points[4] = M3D_V4Multiply(Points[4], M3D_V4Reciprocal(M3D_V4SplatW(Points[4])));
Points[5] = M3D_V4Multiply(Points[5], M3D_V4Reciprocal(M3D_V4SplatW(Points[5])));
if (rhcoords) {
Out.Near = M3D_V4GetZ(Points[5]);
Out.Far = M3D_V4GetZ(Points[4]);
} else {
Out.Near = M3D_V4GetZ(Points[4]);
Out.Far = M3D_V4GetZ(Points[5]);
}
}
namespace M3D_TriangleTests {
inline M3D_ContainmentType ContainedBy(
M3D_VECTOR V0, M3D_VECTOR V1, M3D_VECTOR V2,
M3D_VECTOR& Plane0,
M3D_VECTOR& Plane1, M3D_VECTOR& Plane2,
M3D_VECTOR& Plane3, M3D_VECTOR& Plane4, M3D_VECTOR& Plane5) noexcept {
// Set w of the points to one so we can dot4 with a plane.
M3D_VECTOR TV0 = M3D_V4SetW(V0, 1.0f);
M3D_VECTOR TV1 = M3D_V4SetW(V1, 1.0f);
M3D_VECTOR TV2 = M3D_V4SetW(V2, 1.0f);
M3D_VECTOR Outside, Inside;
// Test against each plane.
FastIntersectTrianglePlane(TV0, TV1, TV2, Plane0, Outside, Inside);
M3D_VECTOR AnyOutside = Outside;
M3D_VECTOR AllInside = Inside;
FastIntersectTrianglePlane(TV0, TV1, TV2, Plane1, Outside, Inside);
AnyOutside = M3D_V4OrInt(AnyOutside, Outside);
AllInside = M3D_V4AndInt(AllInside, Inside);
FastIntersectTrianglePlane(TV0, TV1, TV2, Plane2, Outside, Inside);
AnyOutside = M3D_V4OrInt(AnyOutside, Outside);
AllInside = M3D_V4AndInt(AllInside, Inside);
FastIntersectTrianglePlane(TV0, TV1, TV2, Plane3, Outside, Inside);
AnyOutside = M3D_V4OrInt(AnyOutside, Outside);
AllInside = M3D_V4AndInt(AllInside, Inside);
FastIntersectTrianglePlane(TV0, TV1, TV2, Plane4, Outside, Inside);
AnyOutside = M3D_V4OrInt(AnyOutside, Outside);
AllInside = M3D_V4AndInt(AllInside, Inside);
FastIntersectTrianglePlane(TV0, TV1, TV2, Plane5, Outside, Inside);
AnyOutside = M3D_V4OrInt(AnyOutside, Outside);
AllInside = M3D_V4AndInt(AllInside, Inside);
// If the triangle is outside any plane it is outside.
if (M3D_V4EqualInt(AnyOutside, M3D_V4TrueInt()))
return DISJOINT;
// If the triangle is inside all planes it is inside.
if (M3D_V4EqualInt(AllInside, M3D_V4TrueInt()))
return CONTAINS;
// The triangle is not inside all planes or outside a plane, it may intersect.
return INTERSECTS;
}
}

View File

@ -31,4 +31,6 @@ ObjectDbgCube::ObjectDbgCube() {
MHELPER_INDICES_TRI_ADD(basePart.indices, 0, 2, 3);
MHELPER_INDICES_TRI_ADD(basePart.indices, 4, 0, 1);
mMesh.parts.push_back(basePart);
UpdateAABBFromMesh();
}

View File

@ -6,6 +6,7 @@
class WorldObject {
public:
virtual const Mesh& GetObjectMesh() const = 0;
virtual const size_t GetObjectVerticesCount() const = 0;
const M3D_MATRIX GetTransform() noexcept {
M3D_MATRIX M = M3D_MIdentity();
M *= M3D_TransformMatrixScale(M3D_V4LoadF3(&scale));
@ -19,6 +20,8 @@ public:
return out;
}
const M3D_BoundingBox& GetAABB() const noexcept { return aabb; }
void SetPosition(M3D_F3& _pos) noexcept { pos = _pos; }
void SetPosition(float _x, float _y, float _z) noexcept { pos = M3D_F3(_x, _y, _z); }
void SetRotation(M3D_F3& _rot) noexcept { rot = _rot; }
@ -30,7 +33,8 @@ public:
protected:
WorldObject() = default;
private:
M3D_BoundingBox aabb;
M3D_F3 scale = M3D_F3(1.0f, 1.0f, 1.0f);
M3D_F3 rot = M3D_F3(0.0f, 0.0f, 0.0f);
M3D_F3 pos = M3D_F3(0.0f, 0.0f, 0.0f);
@ -43,8 +47,12 @@ public:
virtual ~WorldObjectAbstract() = 0;
const Mesh& GetObjectMesh() const noexcept override { return mMesh; }
const size_t GetObjectVerticesCount() const noexcept override { return mMesh.GetVerticesCount(); }
void LoadMeshFromObjFile(std::string file);
void UpdateAABBFromMesh() noexcept {
M3D_BoundingBox::CreateFromPoints(aabb, GetObjectVerticesCount(), reinterpret_cast<const M3D_F3*>(GetObjectMesh().vertices.data()), sizeof(Vertex));
}
protected:
inline static Mesh mMesh;

View File

@ -61,4 +61,7 @@ void WorldObjectAbstract<D>::LoadMeshFromObjFile(std::string file) {
mMesh.parts.push_back(subpart);
}
// Refresh AABB bounds
UpdateAABBFromMesh();
}