// Adjust normal vector according to the normal map #if defined(NORMALMAP) mat3 cotangent_frame(vec3 n, vec3 p, vec2 uv); vec3 ApplyNormalMap(vec2 texcoord) { #define WITH_NORMALMAP_UNSIGNED #define WITH_NORMALMAP_GREEN_UP //#define WITH_NORMALMAP_2CHANNEL vec3 interpolatedNormal = normalize(vWorldNormal.xyz); vec3 map = texture(normaltexture, texcoord).xyz; #if defined(WITH_NORMALMAP_UNSIGNED) map = map * 255./127. - 128./127.; // Math so "odd" because 0.5 cannot be precisely described in an unsigned format #endif #if defined(WITH_NORMALMAP_2CHANNEL) map.z = sqrt(1 - dot(map.xy, map.xy)); #endif #if defined(WITH_NORMALMAP_GREEN_UP) map.y = -map.y; #endif mat3 tbn = cotangent_frame(interpolatedNormal, pixelpos.xyz, vTexCoord.st); vec3 bumpedNormal = normalize(tbn * map); return bumpedNormal; } mat3 cotangent_frame(vec3 n, vec3 p, vec2 uv) { // get edge vectors of the pixel triangle vec3 dp1 = dFdx(p); vec3 dp2 = dFdy(p); vec2 duv1 = dFdx(uv); vec2 duv2 = dFdy(uv); // solve the linear system vec3 dp2perp = cross(n, dp2); // cross(dp2, n); vec3 dp1perp = cross(dp1, n); // cross(n, dp1); vec3 t = dp2perp * duv1.x + dp1perp * duv2.x; vec3 b = dp2perp * duv1.y + dp1perp * duv2.y; // construct a scale-invariant frame float invmax = inversesqrt(max(dot(t,t), dot(b,b))); return mat3(t * invmax, b * invmax, n); } #else vec3 ApplyNormalMap(vec2 texcoord) { return normalize(vWorldNormal.xyz); } #endif