Skip to content

Commit

Permalink
[Data/Submesh] Tangents can be computed on submeshes
Browse files Browse the repository at this point in the history
- It will allow computing them for each individual submesh instead of the whole mesh
  • Loading branch information
Razakhel committed Dec 20, 2023
1 parent a83282d commit 6f2f066
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 46 deletions.
2 changes: 1 addition & 1 deletion include/RaZ/Data/Mesh.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 2 additions & 0 deletions include/RaZ/Data/Submesh.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
47 changes: 2 additions & 45 deletions src/RaZ/Data/Mesh.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();

Expand Down Expand Up @@ -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();
});
}

Expand Down
46 changes: 46 additions & 0 deletions src/RaZ/Data/Submesh.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<float>::max());
Vec3f maxPos(std::numeric_limits<float>::lowest());
Expand All @@ -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

0 comments on commit 6f2f066

Please sign in to comment.