I'm working on a batch renderer. I'm limited to using one shader per batch (one draw call for everything).

I want to use a TBN matrix for my lighting. To calculate the TBN matrix for each object I need to provide a model matrix to describe the individual objects' change in position. Providing hundreds of matrixes via uniforms or adding them to the vertexes might be very slow. (providing the updated vertex locations instead of the matrix wont work as the TBN matrix needs to know the translation that occurred not the position of the vertices)

Are there any solutions to this issue? I'd rather keep using my batch rendering for my 3d models as it's nice and fast.

further context: I need TBN matrix to convert my vectors into tangent space so my lighting values and my normals all work nicely in the same space. Since the TBN matrix uses an object's position translation matrix and I'm batch rendering with many objects all using the same shader, I run into this issue.

The TBN matrix is a very important matrix to calculate the lighting and view vectors and normals in the same space: quote from https://learnopengl.com/Advanced-Lighting/Normal-Mapping

So now that we have a TBN matrix, how are we going to use it? There are two ways we can use a TBN matrix for normal mapping, and we'll demonstrate both of them:

  1. We take the TBN matrix that transforms any vector from tangent to world space, give it to the fragment shader, and transform the sampled normal from tangent space to world space using the TBN matrix; the normal is then in the same space as the other lighting variables.
  2. We take the inverse of the TBN matrix that transforms any vector from world space to tangent space, and use this matrix to transform not the normal, but the other relevant lighting variables to tangent space; the normal is then again in the same space as the other lighting variables.

My batching technique:

I am currently recalculating the positions of the vertices on the cpu. and updating the buffer with the new vertices, they are passed to the shader using layouts. The only matrix being passed to the shader right now is the vp matrix.


1 Answer 1


If I understand your batching strategy correctly, you're using CPU-side code to "bake out" many objects' transformations, multiplying their mesh vertex positions by the object's local-to-world matrix, and saving these pre-transformed vertices into a single vertex buffer. This buffer is now in world space, so no model transformations are needed on the GPU to put the vertices into the right places.

If that's accurate, then as part of this process, you'll also want to transform each vertex's normal and tangent vectors by the inverse transpose of the object's local-to-world matrix. That way these vectors will also be in a single unified world space before you pass them to the GPU.

Since all per-object information is already baked into these vectors, your shader doesn't need to apply any further compensations. The TBN matrix it computes from the normals and tangents you baked this way will inherit the per-object info you baked into them.

This all works if your batch is pre-transformed into view space too. Just make sure whatever matrix you use for vertex positions, you use its inverse transpose for the tangents and normals. (Though as a shortcut, if your models never contain non-uniform scale or shear, you can get away with using the upper-left 3x3 of the matrix instead of computing the inverse transpose).


You must log in to answer this question.

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