UNPKG

three

Version:

JavaScript 3D library

93 lines (73 loc) • 3.92 kB
export default /* glsl */` #if NUM_LIGHT_PROBE_GRIDS > 0 // 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[ NUM_LIGHT_PROBE_GRIDS ]; uniform vec3 probesMin[ NUM_LIGHT_PROBE_GRIDS ]; uniform vec3 probesMax[ NUM_LIGHT_PROBE_GRIDS ]; uniform vec3 probesResolution[ NUM_LIGHT_PROBE_GRIDS ]; bool isInsideLightProbeGrid( vec3 worldPos, vec3 worldNormal, vec3 probesMin, vec3 probesMax, vec3 probesResolution ) { vec3 spacing = ( probesMax - probesMin ) / probesResolution; vec3 samplePos = worldPos + worldNormal * spacing * 0.5; // Grow the bounds by 1% of a cell, so fragments on the bounds aren't left out by // precision errors or samples outside of the triangle. vec3 margin = spacing * 0.01; return all( greaterThanEqual( samplePos, probesMin - margin ) ) && all( lessThanEqual( samplePos, probesMax + margin ) ); } vec3 getLightProbeGridIrradiance( highp sampler3D probesSH, vec3 probesMin, vec3 probesMax, vec3 probesResolution, vec3 worldPos, vec3 worldNormal ) { vec3 res = probesResolution; vec3 gridRange = probesMax - probesMin; vec3 probeSpacing = gridRange / res; // Offset sample position along normal by half a probe spacing vec3 samplePos = worldPos + worldNormal * probeSpacing * 0.5; // The bounds hold one cell per probe, so they map directly to the probe grid. // Clamp to the texel centers of the outermost probes (XY and Z). vec3 uvw = clamp( ( samplePos - probesMin ) / gridRange, 0.5 / res, 1.0 - 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 `;