refract
Computes the refraction vector using Snell's law.
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 PlaygroundLive Demo
The refract function computes the refraction of an incident vector through a surface with a given ratio of indices of refraction.
Signature
refract :: (vecN i, vecN n, float eta) -> vecN {...}
Where vecN can be float2, float3, or float4.
Parameters
| Parameter | Type | Description |
|---|---|---|
i | vecN | Incident vector (must be normalized) |
n | vecN | Surface normal (must be normalized) |
eta | float | Ratio of indices of refraction (n1/n2) |
Return Value
Returns the refracted vector. Returns zero vector if total internal reflection occurs.
Example
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
// Water refraction (air to water)
float eta = 1.0 / 1.33;
float3 refracted = refract(incidentDir, waterNormal, eta);Ice Effect
// Ice refraction
float eta = 1.0 / 1.31;
float3 iceRefract = refract(-viewDir, normal, eta);Diamond
// Diamond has high IOR
float eta = 1.0 / 2.42;
float3 diamondRefract = refract(-viewDir, normal, eta);Underwater View
// Looking from underwater up
float eta = 1.33 / 1.0; // Water to air
float3 refractedView = refract(viewDir, -waterSurfaceNormal, eta);Total Internal Reflection Check
// 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:
refract(i, n, eta)
When compiled to HLSL:
refract(i, n, eta)