Intrinsics1 min read

faceforward

Flips the normal to face the viewer.

Reading Time
1 min
Word Count
167
Sections
12
Try It Live

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 Playground

Live 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

bwsl
faceforward :: (vecN n, vecN i, vecN nref) -> vecN {...}

Where vecN can be float2, float3, or float4.

Parameters

ParameterTypeDescription
nvecNThe normal to potentially flip
ivecNThe incident vector (e.g., view direction)
nrefvecNThe reference normal for comparison

Return Value

Returns n if dot(nref, i) < 0, otherwise returns -n.

Example

bwsl
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

bwsl
// 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

bwsl
// Proper lighting for double-sided surfaces
float3 normal = faceforward(input.normal, viewDir, input.normal);
float NdotL = max(dot(normal, lightDir), 0.0);

Foliage Rendering

bwsl
// Leaves need two-sided lighting
float3 leafNormal = faceforward(normal, -viewDir, normal);
float3 transmitted = translucency * max(dot(-leafNormal, lightDir), 0.0);

Hair/Fur

bwsl
// Hair strands are visible from both directions
float3 strandNormal = faceforward(tangent, viewDir, tangent);

Cloth Simulation

bwsl
// 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:

glsl
faceforward(n, i, nref)

When compiled to HLSL:

hlsl
faceforward(n, i, nref)

See Also