export default /* glsl */` #ifdef USE_ALPHAHASH /** * See: https://casual-effects.com/research/Wyman2017Hashed/index.html */ const float ALPHA_HASH_SCALE = 0.05; // Derived from trials only, and may be changed. float hash2D( vec2 value ) { return fract( 1.0e4 * sin( 17.0 * value.x + 0.1 * value.y ) * ( 0.1 + abs( sin( 13.0 * value.y + value.x ) ) ) ); } float hash3D( vec3 value ) { return hash2D( vec2( hash2D( value.xy ), value.z ) ); } float getAlphaHashThreshold( vec3 position ) { // Find the discretized derivatives of our coordinates float maxDeriv = max( length( dFdx( position.xyz ) ), length( dFdy( position.xyz ) ) ); float pixScale = 1.0 / ( ALPHA_HASH_SCALE * maxDeriv ); // Find two nearest log-discretized noise scales vec2 pixScales = vec2( exp2( floor( log2( pixScale ) ) ), exp2( ceil( log2( pixScale ) ) ) ); // Compute alpha thresholds at our two noise scales vec2 alpha = vec2( hash3D( floor( pixScales.x * position.xyz ) ), hash3D( floor( pixScales.y * position.xyz ) ) ); // Factor to interpolate lerp with float lerpFactor = fract( log2( pixScale ) ); // Interpolate alpha threshold from noise at two scales float x = ( 1.0 - lerpFactor ) * alpha.x + lerpFactor * alpha.y; // Pass into CDF to compute uniformly distrib threshold float a = min( lerpFactor, 1.0 - lerpFactor ); vec3 cases = vec3( x * x / ( 2.0 * a * ( 1.0 - a ) ), ( x - 0.5 * a ) / ( 1.0 - a ), 1.0 - ( ( 1.0 - x ) * ( 1.0 - x ) / ( 2.0 * a * ( 1.0 - a ) ) ) ); // Find our final, uniformly distributed alpha threshold (ατ) float threshold = ( x < ( 1.0 - a ) ) ? ( ( x < a ) ? cases.x : cases.y ) : cases.z; // Avoids ατ == 0. Could also do ατ =1-ατ return clamp( threshold , 1.0e-6, 1.0 ); } #endif `;