Well, if you read up on compute shaders and how fragment shaders actuall work, you will find out that they run in a SIMD lane in lockstep 8,16 or 32 pixels at once in nice little 2d slabs, with extra work being done on triangle edges (dead pixel invocations).
You pixel shader needs to be able to do dFdx,dFdy and fwidth in hardware for purposes of mipmap texturing (textureLod(uv,fwidth(uv))) and anisotropic filtering (textureGrad(uv,dFdx(uv),dFdy(uv))).
The GPU instruction set always has an instruction for swizzling data between SIMD lanes so differences between pixels are easy to obtain, you only pay for the "-" operation.
I also cooked up a version (not tested yet) that will calculate the correct tangent and bi-tangent aligned with your UV space for normal mapping.
Code: Select all
in vec3 vertexPos; // model/object, world or even view space, doesn't matter
in vec2 texCoord; // the texcoord you're using for normal mapping, can be uniformly scaled and will produce same results (no need to calculate separately for detail maps)
.. somewhere in your shader
vec2 u1 = dFdx(texCoord);
vec2 u2 = dFdy(texCoord);
//! Should optimize this line by seeing what SPIR-V compiler outputs for this
//mat3x2 tanSpace = mat3x2(dFdx(vertexPos),dFdy(vertexPos))*inverse(mat2(u1,u2)));
//no need for divide by determinant if vectors get normalized
mat3x2 tanSpace = mat3x2(dFdx(vertexPos),dFdy(vertexPos))*mat2(u2.y,-u1.y,-u2.x,u1.x);
vec3 tangent = normalize(tanSpace[0]);
vec3 bitangent = normalize(tanSpace[1]);
vec3 normal = cross( tangent , bitangent);
#ifndef ORTHOGONAL_UV_SPACE
normal = normalize(normal);
#endif
If your uv space is orthogonal, i.e. the texture is not sheared or non-uniformly stretched over ANY of your triangles, then you can #define ORTHOGONAL_UV_SPACE