gpu-curtains
    Preparing search index...
    generateTBN: "\n// Normal Mapping Without Precomputed Tangents in world space\n// http://www.thetenthplanet.de/archives/1180\nfn getTangentFrame( modelPosition: vec3f, normal: vec3f, uv: vec2f ) -> mat3x3f {\n let q0: vec3f = dpdx( modelPosition.xyz );\n let q1: vec3f = dpdy( modelPosition.xyz );\n let st0: vec2f = dpdx( uv.xy );\n let st1: vec2f = dpdy( uv.xy );\n\n let N: vec3f = normal; // normalized\n\n let q1perp: vec3f = cross( q1, N );\n let q0perp: vec3f = cross( N, q0 );\n\n let T: vec3f = q1perp * st0.x + q0perp * st1.x;\n let B: vec3f = q1perp * st0.y + q0perp * st1.y;\n\n let det: f32 = max( dot( T, T ), dot( B, B ) );\n let scale: f32 = select(inverseSqrt( det ), 0.0, det == 0.0);\n\n return mat3x3f( T * scale, B * scale, N );\n\n}\n\n// TBN generates a tangent bitangent normal coordinate frame from the normal\n// (the normal must be normalized)\nfn generateTBN(normal: vec3f) -> mat3x3f {\n var bitangent: vec3f = vec3(0.0, 1.0, 0.0);\n\n let NdotUp: f32 = dot(normal, vec3(0.0, 1.0, 0.0));\n \n if (1.0 - abs(NdotUp) <= EPSILON) {\n // Sampling +Y or -Y, so we need a more robust bitangent.\n if (NdotUp > 0.0) {\n bitangent = vec3(0.0, 0.0, 1.0);\n }\n else {\n bitangent = vec3(0.0, 0.0, -1.0);\n }\n }\n\n let tangent: vec3f = normalize(cross(bitangent, normal));\n bitangent = cross(normal, tangent);\n\n return mat3x3f(tangent, bitangent, normal);\n}\n" = ...

    WGSL function to generate a tangent bitangent normal coordinate frame from the normal.