From c0a00e4e4a6b589fe8fccb2bb91fccf6d5c3e02e Mon Sep 17 00:00:00 2001 From: JackCarterSmith Date: Thu, 31 Oct 2024 19:42:04 +0100 Subject: [PATCH] Simple clipping approach --- Engine/Graphics/3DRenderer.cpp | 137 ++++++----- Engine/Graphics/3DRenderer.hpp | 2 + Engine/Graphics/Camera.hpp | 4 +- Engine/Utils/3DMaths.hpp | 242 +++++++++++++++++++ Engine/Utils/3DMaths_bs.inl | 408 +++++++++++++++++++++++++++++++++ Engine/World/DbgCube.cpp | 2 + Engine/World/WorldObject.hpp | 10 +- Engine/World/WorldObject.tpp | 3 + 8 files changed, 747 insertions(+), 61 deletions(-) diff --git a/Engine/Graphics/3DRenderer.cpp b/Engine/Graphics/3DRenderer.cpp index dfaf3d7..46f1fe9 100644 --- a/Engine/Graphics/3DRenderer.cpp +++ b/Engine/Graphics/3DRenderer.cpp @@ -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(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(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(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(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(); - } } \ No newline at end of file diff --git a/Engine/Graphics/3DRenderer.hpp b/Engine/Graphics/3DRenderer.hpp index 01575ef..8cc2d53 100644 --- a/Engine/Graphics/3DRenderer.hpp +++ b/Engine/Graphics/3DRenderer.hpp @@ -38,4 +38,6 @@ private: std::vector> mRenderList; // List of elements to be rendered next frame + void UpdateInternalTestObjects(); + }; \ No newline at end of file diff --git a/Engine/Graphics/Camera.hpp b/Engine/Graphics/Camera.hpp index 8d824dd..cf9bbc5 100644 --- a/Engine/Graphics/Camera.hpp +++ b/Engine/Graphics/Camera.hpp @@ -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; } diff --git a/Engine/Utils/3DMaths.hpp b/Engine/Utils/3DMaths.hpp index b43e75e..81439d6 100644 --- a/Engine/Utils/3DMaths.hpp +++ b/Engine/Utils/3DMaths.hpp @@ -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" \ No newline at end of file diff --git a/Engine/Utils/3DMaths_bs.inl b/Engine/Utils/3DMaths_bs.inl index c03b781..6536698 100644 --- a/Engine/Utils/3DMaths_bs.inl +++ b/Engine/Utils/3DMaths_bs.inl @@ -9,4 +9,412 @@ 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(reinterpret_cast(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; + } } \ No newline at end of file diff --git a/Engine/World/DbgCube.cpp b/Engine/World/DbgCube.cpp index ccfa797..bbd471d 100644 --- a/Engine/World/DbgCube.cpp +++ b/Engine/World/DbgCube.cpp @@ -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(); } \ No newline at end of file diff --git a/Engine/World/WorldObject.hpp b/Engine/World/WorldObject.hpp index 5cb9188..3e5f42d 100644 --- a/Engine/World/WorldObject.hpp +++ b/Engine/World/WorldObject.hpp @@ -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(GetObjectMesh().vertices.data()), sizeof(Vertex)); + } protected: inline static Mesh mMesh; diff --git a/Engine/World/WorldObject.tpp b/Engine/World/WorldObject.tpp index 688a0f8..4b23c7a 100644 --- a/Engine/World/WorldObject.tpp +++ b/Engine/World/WorldObject.tpp @@ -61,4 +61,7 @@ void WorldObjectAbstract::LoadMeshFromObjFile(std::string file) { mMesh.parts.push_back(subpart); } + + // Refresh AABB bounds + UpdateAABBFromMesh(); } \ No newline at end of file