godot/servers/rendering/renderer_rd/shaders/oct_inc.glsl
Dario c78c3ba894 Rewrite Radiance and Reflection probes to use Octahedral maps.
Co-authored-by: clayjohn <claynjohn@gmail.com>
2025-12-02 17:48:12 -08:00

51 lines
1.6 KiB
GLSL

vec3 oct_to_vec3(vec2 e) {
vec3 v = vec3(e.xy, 1.0 - abs(e.x) - abs(e.y));
float t = max(-v.z, 0.0);
v.xy += t * -sign(v.xy);
return normalize(v);
}
// border_size: 1.0 - padding_in_uv_space * 2.0.
vec3 oct_to_vec3_with_border(vec2 uv, float border_size) {
// Convert into [-1,1] space and add border which extends beyond [-1,1].
uv = (uv - 0.5) * (2.0 / border_size);
// Calculate octahedral mirroring for values outside of [-1,1].
// Inspired by Timothy Lottes' code here: https://gpuopen.com/learn/fetching-from-cubes-and-octahedrons/
vec2 mask = step(vec2(1.0), abs(uv));
uv = 2.0 * clamp(uv, -1.0, 1.0) - uv;
uv = mix(uv, -uv, mask.yx);
return oct_to_vec3(uv);
}
vec2 oct_wrap(vec2 v) {
vec2 signVal;
signVal.x = v.x >= 0.0 ? 1.0 : -1.0;
signVal.y = v.y >= 0.0 ? 1.0 : -1.0;
return (1.0 - abs(v.yx)) * signVal;
}
vec2 vec3_to_oct(vec3 n) {
// Reference: https://twitter.com/Stubbesaurus/status/937994790553227264
n /= (abs(n.x) + abs(n.y) + abs(n.z));
n.xy = (n.z >= 0.0) ? n.xy : oct_wrap(n.xy);
n.xy = n.xy * 0.5 + 0.5;
return n.xy;
}
// border_size.x: padding_in_uv_space
// border_size.y: 1.0 - padding_in_uv_space * 2.0
vec2 vec3_to_oct_with_border(vec3 n, vec2 border_size) {
vec2 uv = vec3_to_oct(n);
return uv * border_size.y + border_size.x;
}
float vec3_to_oct_lod(vec3 n_ddx, vec3 n_ddy, float pixel_size) {
// Approximate UV space derivatives by a factor of 0.5 because
// vec3_to_oct maps from [-1,1] to [0,1].
float pixel_size_sqr = 4.0 * pixel_size * pixel_size;
float ddx = dot(n_ddx, n_ddx) / pixel_size_sqr;
float ddy = dot(n_ddy, n_ddy) / pixel_size_sqr;
float dd_sqr = max(ddx, ddy);
return 0.25 * log2(dd_sqr + 1e-6f);
}