I'm working on implementing normal mapping for my renderer and I am using rapidobj to load the model. While loading the model data for each mesh, I am trying to calculate the tangent and bitangent for the mesh following the method presented by LearnOpengl.
However, some of the tangents and bitangents are resulting in NaN. When this occurs ‘f’ which we calculate is has the value of ‘inf’. These vectors then produce black spots on the resulting mesh when outputting the normals from the normal map. I'm not sure what I am doing wrong in my calculations for this to happen and was wondering if anyone could guide me in the right direction or spot my mistake. Thanks in advance.
// Load mesh data: position, tex and normals
for( std::size_t i = 0; i < shape.mesh.indices.size(); ++i )
{
auto const faceId = i/3;
auto const faceMat = std::size_t(shape.mesh.material_ids[faceId]);
if( faceMat != matId )
continue;
const auto& idx = shape.mesh.indices[i];
ret.positions.emplace_back( glm::vec3{
result.attributes.positions[idx.position_index*3+0],
result.attributes.positions[idx.position_index*3+1],
result.attributes.positions[idx.position_index*3+2]
} );
ret.texcoords.emplace_back( glm::vec2{
result.attributes.texcoords[idx.texcoord_index*2+0],
result.attributes.texcoords[idx.texcoord_index*2+1]
} );
ret.normals.emplace_back( glm::vec3{
result.attributes.normals[idx.normal_index*3+0],
result.attributes.normals[idx.normal_index*3+1],
result.attributes.normals[idx.normal_index*3+2]
} );
; }
// Calculate the bitangent and tangent vectors
for (std::size_t i = 0; i < shape.mesh.indices.size(); i += 3)
{
auto const faceId = i / 3;
const auto& idx0 = shape.mesh.indices[i];
const auto& idx1 = shape.mesh.indices[i + 1];
const auto& idx2 = shape.mesh.indices[i + 2];
glm::vec3 edge1 = ret.positions[idx1.position_index] - ret.positions[idx0.position_index];
glm::vec3 edge2 = ret.positions[idx2.position_index] - ret.positions[idx0.position_index];
glm::vec2 deltaUV1 = ret.texcoords[idx1.texcoord_index] - ret.texcoords[idx0.texcoord_index];
glm::vec2 deltaUV2 = ret.texcoords[idx2.texcoord_index] - ret.texcoords[idx0.texcoord_index];
// this is becoming inf when vectors are NaN
float f = 1.0f / (deltaUV1.x * deltaUV2.y - deltaUV2.x * deltaUV1.y);
glm::vec3 tangent = glm::vec3(0.0f, 0.0f, 0.0f);
tangent.x = f * (deltaUV2.y * edge1.x - deltaUV1.y * edge2.x);
tangent.y = f * (deltaUV2.y * edge1.y - deltaUV1.y * edge2.y);
tangent.z = f * (deltaUV2.y * edge1.z - deltaUV1.y * edge2.z);
glm::vec3 bitangent = glm::vec3(0.0f, 0.0f, 0.0f);
bitangent.x = f * (-deltaUV2.x * edge1.x + deltaUV1.x * edge2.x);
bitangent.y = f * (-deltaUV2.x * edge1.y + deltaUV1.x * edge2.y);
bitangent.z = f * (-deltaUV2.x * edge1.z + deltaUV1.x * edge2.z);
ret.tangent.emplace_back(tangent);
ret.tangent.emplace_back(tangent);
ret.tangent.emplace_back(tangent);
ret.bitangent.emplace_back(bitangent);
ret.bitangent.emplace_back(bitangent);
ret.bitangent.emplace_back(bitangent);
}