faceforward
Flips the normal to face the viewer.
Test faceforward in a live shader
Open the playground, start from a visual preset, and wire faceforward into the fragment stage to see how it behaves with real values.
Open PlaygroundLive Demo
The faceforward function returns a normal vector that faces the same direction as a reference vector. If the normal is facing away, it is negated.
Signature
faceforward :: (vecN n, vecN i, vecN nref) -> vecN {...}
Where vecN can be float2, float3, or float4.
Parameters
| Parameter | Type | Description |
|---|---|---|
n | vecN | The normal to potentially flip |
i | vecN | The incident vector (e.g., view direction) |
nref | vecN | The reference normal for comparison |
Return Value
Returns n if dot(nref, i) < 0, otherwise returns -n.
Example
pipeline TwoSidedLighting {
fragment {
float3 normal = normalize(input.normal);
float3 viewDir = normalize(input.worldPos - cameraPos);
// Flip normal to face the camera for two-sided rendering
normal = faceforward(normal, viewDir, normal);
// Now lighting works from both sides
float3 lightDir = normalize(lightPos - input.worldPos);
float diffuse = max(dot(normal, lightDir), 0.0);
output.color = float4(baseColor * diffuse, 1.0);
}
}Common Use Cases
Two-Sided Geometry
// Render both sides of thin geometry (leaves, cloth)
float3 N = normalize(input.normal);
float3 V = normalize(cameraPos - input.worldPos);
N = faceforward(N, -V, N);Backface Lighting
// Proper lighting for double-sided surfaces
float3 normal = faceforward(input.normal, viewDir, input.normal);
float NdotL = max(dot(normal, lightDir), 0.0);Foliage Rendering
// Leaves need two-sided lighting
float3 leafNormal = faceforward(normal, -viewDir, normal);
float3 transmitted = translucency * max(dot(-leafNormal, lightDir), 0.0);Hair/Fur
// Hair strands are visible from both directions
float3 strandNormal = faceforward(tangent, viewDir, tangent);Cloth Simulation
// Cloth can flip during animation
float3 clothNormal = faceforward(simNormal, viewDir, simNormal);Simplified Form
When n and nref are the same, the function simplifies to: return n if dot(n, i) < 0, else -n. This is the most common usage pattern.
Manual Alternative
You can achieve the same effect with: n * sign(-dot(n, viewDir)) or using a conditional, but faceforward is more readable and may be optimized.
Compiled Output
When compiled to GLSL:
faceforward(n, i, nref)
When compiled to HLSL:
faceforward(n, i, nref)