I'm generating tangents and bitangents for a normal mapping effect and while using the same method as several tutorials, I get tangents that are not very continuous.

enter image description here

Here, we can see on the sphere especially that the tangents are very weird.

Also, my normal are totally correct and don't have this issue.

And when using these tangents with my normal mapping shader they "work", but create a very harsh "break" in the surface.

enter image description here

Here is the code used to generate the tangents and bitangents :

for (size_t i = 0; i < out_vertices.size(); i += 3)
  const auto& v0 = out_vertices[i];
  const auto& v1 = out_vertices[i + 1];
  const auto& v2 = out_vertices[i + 2];

  const auto& uv0 = out_uvs[i];
  const auto& uv1 = out_uvs[i + 1];
  const auto& uv2 = out_uvs[i + 2];

  const auto& dd_v0 = v1 - v0;
  const auto& dd_v1 = v2 - v0;

  const auto& dd_uv0 = uv1 - uv0;
  const auto& dd_uv1 = uv2 - uv0;

  float r = 1.0f / (dd_uv0.x * dd_uv1.y - dd_uv0.y * dd_uv1.x);
  glm::vec3 tangent = glm::normalize((dd_v0 * dd_uv1.y - dd_v1 * dd_uv0.y) * r);
  glm::vec3 bitangent = glm::normalize((dd_v1 * dd_uv0.x - dd_v0 * dd_uv1.x) * r);



I'm not sure if I need to average the (bi)tangents that share the same vertices/uvs, but I'm also not sure how to do it.

Thanks for any help.


1 Answer 1


You need to average tangents and binormals from the neighbor triangles to get a the correct result. I suggest you take a look at Martin Mittrings (Crytek) code:


Now that aside, I might suggest to make life even easier by calculating the tangent space directly in the pixel shader. This is way more robust compared to precalculating it:



  • \$\begingroup\$ Thanks for your answer. I was thinking that I needed to average the tangents so that's what I'm going to try to do with your link. \$\endgroup\$
    – CpCd0y
    Commented Nov 17, 2016 at 11:08
  • \$\begingroup\$ Something that's bothering me is that you say I should compute tangent space directly in the fragment shader but isn't that a waste of GPU time ? Because right now I only transfer a few bytes (normals/tangents/bitangents) to the GPU per vertex and that seems to be the less heavy thing to do for me. Maybe you can tell me otherwise ? \$\endgroup\$
    – CpCd0y
    Commented Nov 17, 2016 at 11:09
  • \$\begingroup\$ Correct, there are a few more instructions in the shader, mostly mul and add. I profiled the approaches (before I switched over to using it in our game) on some low end PC hardware and found the overhead minimal. \$\endgroup\$ Commented Nov 17, 2016 at 18:44
  • \$\begingroup\$ I tried the cotangent space reconstruction in the fragment shader and it works perfectly and the performance impact is not that heavy. Thanks again ! \$\endgroup\$
    – CpCd0y
    Commented Nov 18, 2016 at 11:35

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .