From 6f2f0668cd84d741d6f5bf3bd5def6a1315ecadb Mon Sep 17 00:00:00 2001 From: Razakhel Date: Wed, 20 Dec 2023 18:24:39 +0100 Subject: [PATCH] [Data/Submesh] Tangents can be computed on submeshes - It will allow computing them for each individual submesh instead of the whole mesh --- include/RaZ/Data/Mesh.hpp | 2 +- include/RaZ/Data/Submesh.hpp | 2 ++ src/RaZ/Data/Mesh.cpp | 47 ++---------------------------------- src/RaZ/Data/Submesh.cpp | 46 +++++++++++++++++++++++++++++++++++ 4 files changed, 51 insertions(+), 46 deletions(-) diff --git a/include/RaZ/Data/Mesh.hpp b/include/RaZ/Data/Mesh.hpp index be04fda7..d1f60688 100644 --- a/include/RaZ/Data/Mesh.hpp +++ b/include/RaZ/Data/Mesh.hpp @@ -41,7 +41,7 @@ class Mesh : public Component { /// Computes & updates the mesh's bounding box by computing the submeshes' ones. /// \return Mesh's bounding box. const AABB& computeBoundingBox(); - /// Computes the mesh's tangents. + /// Computes the tangents for each of the mesh's vertices. void computeTangents(); Mesh& operator=(const Mesh&) = delete; diff --git a/include/RaZ/Data/Submesh.hpp b/include/RaZ/Data/Submesh.hpp index 485f1c88..684a3817 100644 --- a/include/RaZ/Data/Submesh.hpp +++ b/include/RaZ/Data/Submesh.hpp @@ -48,6 +48,8 @@ class Submesh { /// Computes & updates the submesh's bounding box. /// \return Submesh's bounding box. const AABB& computeBoundingBox(); + /// Computes the tangents for each of the submesh's vertices. + void computeTangents(); Submesh& operator=(const Submesh&) = delete; Submesh& operator=(Submesh&&) noexcept = default; diff --git a/src/RaZ/Data/Mesh.cpp b/src/RaZ/Data/Mesh.cpp index 633f13f5..8a4a7dd4 100644 --- a/src/RaZ/Data/Mesh.cpp +++ b/src/RaZ/Data/Mesh.cpp @@ -6,25 +6,6 @@ namespace Raz { -namespace { - -constexpr Vec3f computeTangent(const Vertex& firstVert, const Vertex& secondVert, const Vertex& thirdVert) noexcept { - const Vec3f firstEdge = secondVert.position - firstVert.position; - const Vec3f secondEdge = thirdVert.position - firstVert.position; - - const Vec2f firstUvDiff = secondVert.texcoords - firstVert.texcoords; - const Vec2f secondUvDiff = thirdVert.texcoords - firstVert.texcoords; - - const float denominator = (firstUvDiff.x() * secondUvDiff.y() - secondUvDiff.x() * firstUvDiff.y()); - - if (denominator == 0.f) - return Vec3f(0.f); - - return (firstEdge * secondUvDiff.y() - secondEdge * firstUvDiff.y()) / denominator; -} - -} // namespace - Mesh::Mesh(const Plane& plane, float width, float depth) { const float height = plane.computeCentroid().y(); @@ -257,32 +238,8 @@ void Mesh::computeTangents() { return; Threading::parallelize(m_submeshes, [] (const auto& range) noexcept { - for (Submesh& submesh : range) { - for (Vertex& vertex : submesh.getVertices()) - vertex.tangent = Vec3f(0.f, 0.f, 0.f); - - for (std::size_t i = 0; i < submesh.getTriangleIndexCount(); i += 3) { - Vertex& firstVert = submesh.getVertices()[submesh.getTriangleIndices()[i ]]; - Vertex& secondVert = submesh.getVertices()[submesh.getTriangleIndices()[i + 1]]; - Vertex& thirdVert = submesh.getVertices()[submesh.getTriangleIndices()[i + 2]]; - - const Vec3f tangent = computeTangent(firstVert, secondVert, thirdVert); - - // Adding the computed tangent to each vertex; they will be normalized later - firstVert.tangent += tangent; - secondVert.tangent += tangent; - thirdVert.tangent += tangent; - } - - // Normalizing the accumulated tangents - for (Vertex& vert : submesh.getVertices()) { - // Avoiding NaNs by preventing normalization of a 0 vector - if (vert.tangent.strictlyEquals(Vec3f(0.f))) - continue; - - vert.tangent = (vert.tangent - vert.normal * vert.tangent.dot(vert.normal)).normalize(); - } - } + for (Submesh& submesh : range) + submesh.computeTangents(); }); } diff --git a/src/RaZ/Data/Submesh.cpp b/src/RaZ/Data/Submesh.cpp index 9962f370..4560ae81 100644 --- a/src/RaZ/Data/Submesh.cpp +++ b/src/RaZ/Data/Submesh.cpp @@ -2,6 +2,25 @@ namespace Raz { +namespace { + +constexpr Vec3f computeTangent(const Vertex& firstVert, const Vertex& secondVert, const Vertex& thirdVert) noexcept { + const Vec3f firstEdge = secondVert.position - firstVert.position; + const Vec3f secondEdge = thirdVert.position - firstVert.position; + + const Vec2f firstUvDiff = secondVert.texcoords - firstVert.texcoords; + const Vec2f secondUvDiff = thirdVert.texcoords - firstVert.texcoords; + + const float denominator = (firstUvDiff.x() * secondUvDiff.y() - secondUvDiff.x() * firstUvDiff.y()); + + if (denominator == 0.f) + return Vec3f(0.f); + + return (firstEdge * secondUvDiff.y() - secondEdge * firstUvDiff.y()) / denominator; +} + +} // namespace + const AABB& Submesh::computeBoundingBox() { Vec3f minPos(std::numeric_limits::max()); Vec3f maxPos(std::numeric_limits::lowest()); @@ -20,4 +39,31 @@ const AABB& Submesh::computeBoundingBox() { return m_boundingBox; } +void Submesh::computeTangents() { + for (Vertex& vert : m_vertices) + vert.tangent = Vec3f(0.f, 0.f, 0.f); + + for (std::size_t i = 0; i < m_triangleIndices.size(); i += 3) { + Vertex& firstVert = m_vertices[m_triangleIndices[i ]]; + Vertex& secondVert = m_vertices[m_triangleIndices[i + 1]]; + Vertex& thirdVert = m_vertices[m_triangleIndices[i + 2]]; + + const Vec3f tangent = computeTangent(firstVert, secondVert, thirdVert); + + // Adding the computed tangent to each vertex; they will be normalized later + firstVert.tangent += tangent; + secondVert.tangent += tangent; + thirdVert.tangent += tangent; + } + + // Normalizing the accumulated tangents + for (Vertex& vert : m_vertices) { + // Avoiding NaNs by preventing the normalization of a 0 vector + if (vert.tangent.strictlyEquals(Vec3f(0.f))) + continue; + + vert.tangent = (vert.tangent - vert.normal * vert.tangent.dot(vert.normal)).normalize(); + } +} + } // namespace Raz