If you want to use a normal map in a shader, you generally need to compute a tangent space coordinate system where to apply the normal perturbation values read from the normal map. To do this, you need two vectors per vertex: a normal vector and a tangent vector. From these two vectors you can compute the bitangent vector to complete the tangent space basis. pocket.gl is based on Three.js, which does not support tangent vectors. The reason is the fact that tangent space can be computed per-pixel using shader derivatives without the need of tangent vectors. Thus, removing tangent vectors support from the library makes the library and the mesh files smaller, which is important in a web context.

## Per-pixel tangent space normal mapping

An algorithm to compute per-pixel tangent space is explained here.

Here is a GLSL function based on this algorithm. It takes as input the fragment position in eye space, the current surface normal, the UV coordinates and the normal perturbation value from the normal map. It returns the perturbed normal in eye space. Note that the tangent space computation is based on the UV coordinates, pass to the function the same UV channel (which you have carefully unwrapped) that you are using to sample the normal map.

``````vec3 perturbNormal( vec3 eye_pos, vec3 surf_norm,
vec2 uv_coords, vec3 normal_perturbation )
{
vec3 q0 = dFdx( eye_pos.xyz );
vec3 q1 = dFdy( eye_pos.xyz );
vec2 st0 = dFdx( uv_coords.st );
vec2 st1 = dFdy( uv_coords.st );

vec3 S = normalize( q0 * st1.t - q1 * st0.t );
vec3 T = normalize( -q0 * st1.s + q1 * st0.s );
vec3 N = normalize( surf_norm );

mat3 tsn = mat3( S, T, N );
return normalize( tsn * normal_perturbation );
}``````