You do strange manipulations with matrices. In VS, you are transforming the normal (i.e. model-space) inverse world of representations. That doesn't make any sense. It may be easier to do calculations in world space. I have some working code example, but it uses a slightly different name.
Vertex shader:
void main_vs(in A2V input, out V2P output) { output.position = mul(input.position, _worldViewProjection); output.normal = input.normal; output.binormal = input.binormal; output.tangent = input.tangent; output.positionWorld = mul(input.position, _world); output.tex = input.tex; }
Here we transform the position into the projection (screen) space, TBN remains in the model space, they will be used later. We also get the position of the world space for lighting assessment.
Pixel Shader:
void main_ps(in V2P input, out float4 output : SV_Target) { float3x3 tbn = float3x3(input.tangent, -input.binormal, input.normal);
Here I use directional light, you should do something like
float3 lightDirection = normalize(input.positionWorld - _lightPosition.xyz);
Here we first have a normal texture, that is, in a TBN space. Then we use the TBN matrix to transform it into a model space. Then apply the matrix of the world to transform it into world space, if we already had the position of light, eyes, etc.
Some other shader codes omitted above (DX11, but easy to translate):
cbuffer ViewTranforms { row_major matrix _worldViewProjection; row_major matrix _world; float3 _camera; }; cbuffer BumpData { float4 _ambient; float4 _diffuse; }; cbuffer Textures { texture2D _texture; SamplerState _sampler; texture2D _normalTexture; SamplerState _normalSampler; }; cbuffer Light { float4 _lightPosition; float4 _lightColor; };
In addition, here I use pre-computed binormal: you must leave your code that computes it (via cross (normal, tangent)). Hope this helps.