UNPKG

three

Version:

JavaScript 3D library

81 lines (66 loc) 3.17 kB
export default /* glsl */` #ifdef USE_LIGHT_PROBES_GRID // Single atlas 3D texture that stores all 7 SH sub-volumes stacked along Z. // Atlas depth = 7 * ( nz + 2 ) where nz = probesResolution.z. // Each sub-volume occupies ( nz + 2 ) slices: 1 padding + nz data + 1 padding. // Padding is a copy of the first / last data slice and prevents color bleeding // when the hardware linear filter reads across a sub-volume boundary. uniform highp sampler3D probesSH; uniform vec3 probesMin; uniform vec3 probesMax; uniform vec3 probesResolution; vec3 getLightProbeGridIrradiance( vec3 worldPos, vec3 worldNormal ) { vec3 res = probesResolution; vec3 gridRange = probesMax - probesMin; vec3 resMinusOne = res - 1.0; vec3 probeSpacing = gridRange / resMinusOne; // Offset sample position along normal by half a probe spacing vec3 samplePos = worldPos + worldNormal * probeSpacing * 0.5; vec3 uvw = clamp( ( samplePos - probesMin ) / gridRange, 0.0, 1.0 ); // Remap to texel centers of the probe grid (XY and Z) uvw = uvw * resMinusOne / res + 0.5 / res; // Atlas UV mapping along Z: // paddedSlices = nz + 2 (1 padding texel at each end of every sub-volume) // atlasDepth = 7 * paddedSlices // For sub-volume t the first DATA texel sits at atlas slice t*paddedSlices + 1. // Given probe-grid texel-centre UVZ = ( iz + 0.5 ) / nz the atlas UV is: // atlasUvZ = ( uvw.z * nz + t * paddedSlices + 1 ) / atlasDepth // // uvZBase encodes the nz-scaled Z plus the intra-volume offset (+ 1 for padding), // so adding t*paddedSlices steps to each successive sub-volume. float nz = res.z; float paddedSlices = nz + 2.0; float atlasDepth = 7.0 * paddedSlices; float uvZBase = uvw.z * nz + 1.0; vec4 s0 = texture( probesSH, vec3( uvw.xy, ( uvZBase ) / atlasDepth ) ); vec4 s1 = texture( probesSH, vec3( uvw.xy, ( uvZBase + paddedSlices ) / atlasDepth ) ); vec4 s2 = texture( probesSH, vec3( uvw.xy, ( uvZBase + 2.0 * paddedSlices ) / atlasDepth ) ); vec4 s3 = texture( probesSH, vec3( uvw.xy, ( uvZBase + 3.0 * paddedSlices ) / atlasDepth ) ); vec4 s4 = texture( probesSH, vec3( uvw.xy, ( uvZBase + 4.0 * paddedSlices ) / atlasDepth ) ); vec4 s5 = texture( probesSH, vec3( uvw.xy, ( uvZBase + 5.0 * paddedSlices ) / atlasDepth ) ); vec4 s6 = texture( probesSH, vec3( uvw.xy, ( uvZBase + 6.0 * paddedSlices ) / atlasDepth ) ); // Unpack 9 vec3 SH L2 coefficients vec3 c0 = s0.xyz; vec3 c1 = vec3( s0.w, s1.xy ); vec3 c2 = vec3( s1.zw, s2.x ); vec3 c3 = s2.yzw; vec3 c4 = s3.xyz; vec3 c5 = vec3( s3.w, s4.xy ); vec3 c6 = vec3( s4.zw, s5.x ); vec3 c7 = s5.yzw; vec3 c8 = s6.xyz; // Evaluate L2 irradiance float x = worldNormal.x, y = worldNormal.y, z = worldNormal.z; vec3 result = c0 * 0.886227; result += c1 * 2.0 * 0.511664 * y; result += c2 * 2.0 * 0.511664 * z; result += c3 * 2.0 * 0.511664 * x; result += c4 * 2.0 * 0.429043 * x * y; result += c5 * 2.0 * 0.429043 * y * z; result += c6 * ( 0.743125 * z * z - 0.247708 ); result += c7 * 2.0 * 0.429043 * x * z; result += c8 * 0.429043 * ( x * x - y * y ); return max( result, vec3( 0.0 ) ); } #endif `;