Intrinsics2 min read

refract

Computes the refraction vector using Snell's law.

Reading Time
2 min
Word Count
195
Sections
12
Try It Live

Test refract in a live shader

Open the playground, start from a visual preset, and wire refract into the fragment stage to see how it behaves with real values.

Open Playground

Live Demo

The refract function computes the refraction of an incident vector through a surface with a given ratio of indices of refraction.

Signature

bwsl
refract :: (vecN i, vecN n, float eta) -> vecN {...}

Where vecN can be float2, float3, or float4.

Parameters

ParameterTypeDescription
ivecNIncident vector (must be normalized)
nvecNSurface normal (must be normalized)
etafloatRatio of indices of refraction (n1/n2)

Return Value

Returns the refracted vector. Returns zero vector if total internal reflection occurs.

Example

bwsl
pipeline GlassRefraction {
fragment {
float3 normal = normalize(input.normal);
float3 viewDir = normalize(cameraPos - input.worldPos);
// Index of refraction ratios
float etaAirToGlass = 1.0 / 1.5; // Air (1.0) to Glass (1.5)
// Calculate refraction
float3 refractDir = refract(-viewDir, normal, etaAirToGlass);
// Sample background through refraction
float2 refractUV = input.screenUV + refractDir.xy * refractionStrength;
float3 refractColor = sample(backgroundTex, refractUV).rgb;
// Add fresnel for realism
float fresnel = pow(1.0 - max(dot(normal, viewDir), 0.0), 5.0);
float3 reflectDir = reflect(-viewDir, normal);
float3 reflectColor = sample(envMap, reflectDir).rgb;
float3 finalColor = lerp(refractColor, reflectColor, fresnel);
output.color = float4(finalColor, 1.0);
}
}

Common Use Cases

Glass/Water Materials

bwsl
// Water refraction (air to water)
float eta = 1.0 / 1.33;
float3 refracted = refract(incidentDir, waterNormal, eta);

Ice Effect

bwsl
// Ice refraction
float eta = 1.0 / 1.31;
float3 iceRefract = refract(-viewDir, normal, eta);

Diamond

bwsl
// Diamond has high IOR
float eta = 1.0 / 2.42;
float3 diamondRefract = refract(-viewDir, normal, eta);

Underwater View

bwsl
// Looking from underwater up
float eta = 1.33 / 1.0; // Water to air
float3 refractedView = refract(viewDir, -waterSurfaceNormal, eta);

Total Internal Reflection Check

bwsl
// Check for total internal reflection
float3 refracted = refract(incident, normal, eta);
if (length(refracted) < 0.001) {
// Total internal reflection - use reflect instead
refracted = reflect(incident, normal);
}

Common IOR Values

  • Air: 1.0
  • Water: 1.33
  • Glass: 1.5
  • Diamond: 2.42
  • Ice: 1.31

Total Internal Reflection

When light travels from a denser medium to a less dense one (eta > 1), total internal reflection can occur at steep angles. The function returns a zero vector in this case.

Eta Direction

eta is the ratio n1/n2, where n1 is the IOR of the medium the ray is coming from, and n2 is the IOR of the medium it's entering.

Compiled Output

When compiled to GLSL:

glsl
refract(i, n, eta)

When compiled to HLSL:

hlsl
refract(i, n, eta)

See Also