Преглед изворни кода

Material: Add "material.alphaHash" transparency mode (#24271)

* Material: Add .alphaHash and .alphaHashScale

Material.alphaHash: Add example

Clean up.

Update builds

Examples: Clean up alpha hash params

Fix background color changes, add GammaCorrectionShader

TAARenderPass: Initialize .accumulateIndex

Alpha Hash: Initialize sampleLevel=0 in example

Avoids flashing from TAARenderPass

Clean up alpha hash example.

Lint

Update builds

Add screenshot

* Material: Move alphahash to separate shader chunks.

* Material: Remove alphaHashScale

* Clean up

* Clean up

* Clean up

* Clean up
Don McCurdy пре 2 година
родитељ
комит
77ba7432bd

+ 1 - 0
examples/jsm/postprocessing/TAARenderPass.js

@@ -24,6 +24,7 @@ class TAARenderPass extends SSAARenderPass {
 
 		this.sampleLevel = 0;
 		this.accumulate = false;
+		this.accumulateIndex = - 1;
 
 	}
 

+ 1 - 0
src/loaders/MaterialLoader.js

@@ -121,6 +121,7 @@ class MaterialLoader extends Loader {
 		if ( json.opacity !== undefined ) material.opacity = json.opacity;
 		if ( json.transparent !== undefined ) material.transparent = json.transparent;
 		if ( json.alphaTest !== undefined ) material.alphaTest = json.alphaTest;
+		if ( json.alphaHash !== undefined ) material.alphaHash = json.alphaHash;
 		if ( json.depthTest !== undefined ) material.depthTest = json.depthTest;
 		if ( json.depthWrite !== undefined ) material.depthWrite = json.depthWrite;
 		if ( json.colorWrite !== undefined ) material.colorWrite = json.colorWrite;

+ 3 - 0
src/materials/Material.js

@@ -25,6 +25,7 @@ class Material extends EventDispatcher {
 
 		this.opacity = 1;
 		this.transparent = false;
+		this.alphaHash = false;
 
 		this.blendSrc = SrcAlphaFactor;
 		this.blendDst = OneMinusSrcAlphaFactor;
@@ -353,6 +354,7 @@ class Material extends EventDispatcher {
 		if ( this.dithering === true ) data.dithering = true;
 
 		if ( this.alphaTest > 0 ) data.alphaTest = this.alphaTest;
+		if ( this.alphaHash === true ) data.alphaHash = this.alphaHash;
 		if ( this.alphaToCoverage === true ) data.alphaToCoverage = this.alphaToCoverage;
 		if ( this.premultipliedAlpha === true ) data.premultipliedAlpha = this.premultipliedAlpha;
 		if ( this.forceSinglePass === true ) data.forceSinglePass = this.forceSinglePass;
@@ -474,6 +476,7 @@ class Material extends EventDispatcher {
 		this.dithering = source.dithering;
 
 		this.alphaTest = source.alphaTest;
+		this.alphaHash = source.alphaHash;
 		this.alphaToCoverage = source.alphaToCoverage;
 		this.premultipliedAlpha = source.premultipliedAlpha;
 		this.forceSinglePass = source.forceSinglePass;

+ 4 - 0
src/renderers/shaders/ShaderChunk.js

@@ -1,3 +1,5 @@
+import alphahash_fragment from './ShaderChunk/alphahash_fragment.glsl.js';
+import alphahash_pars_fragment from './ShaderChunk/alphahash_pars_fragment.glsl.js';
 import alphamap_fragment from './ShaderChunk/alphamap_fragment.glsl.js';
 import alphamap_pars_fragment from './ShaderChunk/alphamap_pars_fragment.glsl.js';
 import alphatest_fragment from './ShaderChunk/alphatest_fragment.glsl.js';
@@ -121,6 +123,8 @@ import * as shadow from './ShaderLib/shadow.glsl.js';
 import * as sprite from './ShaderLib/sprite.glsl.js';
 
 export const ShaderChunk = {
+	alphahash_fragment: alphahash_fragment,
+	alphahash_pars_fragment: alphahash_pars_fragment,
 	alphamap_fragment: alphamap_fragment,
 	alphamap_pars_fragment: alphamap_pars_fragment,
 	alphatest_fragment: alphatest_fragment,

+ 7 - 0
src/renderers/shaders/ShaderChunk/alphahash_fragment.glsl.js

@@ -0,0 +1,7 @@
+export default /* glsl */`
+#ifdef USE_ALPHAHASH
+
+	if ( diffuseColor.a < getAlphaHashThreshold( vPosition ) ) discard;
+
+#endif
+`;

+ 68 - 0
src/renderers/shaders/ShaderChunk/alphahash_pars_fragment.glsl.js

@@ -0,0 +1,68 @@
+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
+`;

+ 6 - 0
src/renderers/shaders/ShaderChunk/begin_vertex.glsl.js

@@ -1,3 +1,9 @@
 export default /* glsl */`
 vec3 transformed = vec3( position );
+
+#ifdef USE_ALPHAHASH
+
+	vPosition = vec3( position );
+
+#endif
 `;

+ 6 - 0
src/renderers/shaders/ShaderChunk/common.glsl.js

@@ -61,6 +61,12 @@ struct GeometricContext {
 #endif
 };
 
+#ifdef USE_ALPHAHASH
+
+	varying vec3 vPosition;
+
+#endif
+
 vec3 transformDirection( in vec3 dir, in mat4 matrix ) {
 
 	return normalize( ( matrix * vec4( dir, 0.0 ) ).xyz );

+ 2 - 0
src/renderers/shaders/ShaderLib/depth.glsl.js

@@ -52,6 +52,7 @@ export const fragment = /* glsl */`
 #include <map_pars_fragment>
 #include <alphamap_pars_fragment>
 #include <alphatest_pars_fragment>
+#include <alphahash_pars_fragment>
 #include <logdepthbuf_pars_fragment>
 #include <clipping_planes_pars_fragment>
 
@@ -72,6 +73,7 @@ void main() {
 	#include <map_fragment>
 	#include <alphamap_fragment>
 	#include <alphatest_fragment>
+	#include <alphahash_fragment>
 
 	#include <logdepthbuf_fragment>
 

+ 2 - 0
src/renderers/shaders/ShaderLib/distanceRGBA.glsl.js

@@ -51,6 +51,7 @@ varying vec3 vWorldPosition;
 #include <map_pars_fragment>
 #include <alphamap_pars_fragment>
 #include <alphatest_pars_fragment>
+#include <alphahash_pars_fragment>
 #include <clipping_planes_pars_fragment>
 
 void main () {
@@ -62,6 +63,7 @@ void main () {
 	#include <map_fragment>
 	#include <alphamap_fragment>
 	#include <alphatest_fragment>
+	#include <alphahash_fragment>
 
 	float dist = length( vWorldPosition - referencePosition );
 	dist = ( dist - nearDistance ) / ( farDistance - nearDistance );

+ 2 - 0
src/renderers/shaders/ShaderLib/meshbasic.glsl.js

@@ -56,6 +56,7 @@ uniform float opacity;
 #include <map_pars_fragment>
 #include <alphamap_pars_fragment>
 #include <alphatest_pars_fragment>
+#include <alphahash_pars_fragment>
 #include <aomap_pars_fragment>
 #include <lightmap_pars_fragment>
 #include <envmap_common_pars_fragment>
@@ -76,6 +77,7 @@ void main() {
 	#include <color_fragment>
 	#include <alphamap_fragment>
 	#include <alphatest_fragment>
+	#include <alphahash_fragment>
 	#include <specularmap_fragment>
 
 	ReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );

+ 2 - 0
src/renderers/shaders/ShaderLib/meshlambert.glsl.js

@@ -62,6 +62,7 @@ uniform float opacity;
 #include <map_pars_fragment>
 #include <alphamap_pars_fragment>
 #include <alphatest_pars_fragment>
+#include <alphahash_pars_fragment>
 #include <aomap_pars_fragment>
 #include <lightmap_pars_fragment>
 #include <emissivemap_pars_fragment>
@@ -92,6 +93,7 @@ void main() {
 	#include <color_fragment>
 	#include <alphamap_fragment>
 	#include <alphatest_fragment>
+	#include <alphahash_fragment>
 	#include <specularmap_fragment>
 	#include <normal_fragment_begin>
 	#include <normal_fragment_maps>

+ 2 - 0
src/renderers/shaders/ShaderLib/meshmatcap.glsl.js

@@ -58,6 +58,7 @@ varying vec3 vViewPosition;
 #include <map_pars_fragment>
 #include <alphamap_pars_fragment>
 #include <alphatest_pars_fragment>
+#include <alphahash_pars_fragment>
 #include <fog_pars_fragment>
 #include <normal_pars_fragment>
 #include <bumpmap_pars_fragment>
@@ -76,6 +77,7 @@ void main() {
 	#include <color_fragment>
 	#include <alphamap_fragment>
 	#include <alphatest_fragment>
+	#include <alphahash_fragment>
 	#include <normal_fragment_begin>
 	#include <normal_fragment_maps>
 

+ 2 - 0
src/renderers/shaders/ShaderLib/meshphong.glsl.js

@@ -64,6 +64,7 @@ uniform float opacity;
 #include <map_pars_fragment>
 #include <alphamap_pars_fragment>
 #include <alphatest_pars_fragment>
+#include <alphahash_pars_fragment>
 #include <aomap_pars_fragment>
 #include <lightmap_pars_fragment>
 #include <emissivemap_pars_fragment>
@@ -94,6 +95,7 @@ void main() {
 	#include <color_fragment>
 	#include <alphamap_fragment>
 	#include <alphatest_fragment>
+	#include <alphahash_fragment>
 	#include <specularmap_fragment>
 	#include <normal_fragment_begin>
 	#include <normal_fragment_maps>

+ 2 - 0
src/renderers/shaders/ShaderLib/meshphysical.glsl.js

@@ -130,6 +130,7 @@ varying vec3 vViewPosition;
 #include <map_pars_fragment>
 #include <alphamap_pars_fragment>
 #include <alphatest_pars_fragment>
+#include <alphahash_pars_fragment>
 #include <aomap_pars_fragment>
 #include <lightmap_pars_fragment>
 #include <emissivemap_pars_fragment>
@@ -165,6 +166,7 @@ void main() {
 	#include <color_fragment>
 	#include <alphamap_fragment>
 	#include <alphatest_fragment>
+	#include <alphahash_fragment>
 	#include <roughnessmap_fragment>
 	#include <metalnessmap_fragment>
 	#include <normal_fragment_begin>

+ 2 - 0
src/renderers/shaders/ShaderLib/meshtoon.glsl.js

@@ -60,6 +60,7 @@ uniform float opacity;
 #include <map_pars_fragment>
 #include <alphamap_pars_fragment>
 #include <alphatest_pars_fragment>
+#include <alphahash_pars_fragment>
 #include <aomap_pars_fragment>
 #include <lightmap_pars_fragment>
 #include <emissivemap_pars_fragment>
@@ -88,6 +89,7 @@ void main() {
 	#include <color_fragment>
 	#include <alphamap_fragment>
 	#include <alphatest_fragment>
+	#include <alphahash_fragment>
 	#include <normal_fragment_begin>
 	#include <normal_fragment_maps>
 	#include <emissivemap_fragment>

+ 2 - 0
src/renderers/shaders/ShaderLib/points.glsl.js

@@ -56,6 +56,7 @@ uniform float opacity;
 #include <color_pars_fragment>
 #include <map_particle_pars_fragment>
 #include <alphatest_pars_fragment>
+#include <alphahash_pars_fragment>
 #include <fog_pars_fragment>
 #include <logdepthbuf_pars_fragment>
 #include <clipping_planes_pars_fragment>
@@ -71,6 +72,7 @@ void main() {
 	#include <map_particle_fragment>
 	#include <color_fragment>
 	#include <alphatest_fragment>
+	#include <alphahash_fragment>
 
 	outgoingLight = diffuseColor.rgb;
 

+ 2 - 0
src/renderers/shaders/ShaderLib/sprite.glsl.js

@@ -52,6 +52,7 @@ uniform float opacity;
 #include <map_pars_fragment>
 #include <alphamap_pars_fragment>
 #include <alphatest_pars_fragment>
+#include <alphahash_pars_fragment>
 #include <fog_pars_fragment>
 #include <logdepthbuf_pars_fragment>
 #include <clipping_planes_pars_fragment>
@@ -67,6 +68,7 @@ void main() {
 	#include <map_fragment>
 	#include <alphamap_fragment>
 	#include <alphatest_fragment>
+	#include <alphahash_fragment>
 
 	outgoingLight = diffuseColor.rgb;
 

+ 2 - 0
src/renderers/webgl/WebGLProgram.js

@@ -509,6 +509,7 @@ function WebGLProgram( renderer, cacheKey, parameters, bindingStates ) {
 			parameters.roughnessMap ? '#define USE_ROUGHNESSMAP' : '',
 			parameters.metalnessMap ? '#define USE_METALNESSMAP' : '',
 			parameters.alphaMap ? '#define USE_ALPHAMAP' : '',
+			parameters.alphaHash ? '#define USE_ALPHAHASH' : '',
 
 			parameters.transmission ? '#define USE_TRANSMISSION' : '',
 			parameters.transmissionMap ? '#define USE_TRANSMISSIONMAP' : '',
@@ -730,6 +731,7 @@ function WebGLProgram( renderer, cacheKey, parameters, bindingStates ) {
 
 			parameters.alphaMap ? '#define USE_ALPHAMAP' : '',
 			parameters.alphaTest ? '#define USE_ALPHATEST' : '',
+			parameters.alphaHash ? '#define USE_ALPHAHASH' : '',
 
 			parameters.sheen ? '#define USE_SHEEN' : '',
 			parameters.sheenColorMap ? '#define USE_SHEEN_COLORMAP' : '',

+ 3 - 0
src/renderers/webgl/WebGLPrograms.js

@@ -152,6 +152,8 @@ function WebGLPrograms( renderer, cubemaps, cubeuvmaps, extensions, capabilities
 
 		const HAS_ALPHATEST = material.alphaTest > 0;
 
+		const HAS_ALPHAHASH = !! material.alphaHash;
+
 		const HAS_EXTENSIONS = !! material.extensions;
 
 		const HAS_ATTRIBUTE_UV1 = !! geometry.attributes.uv1;
@@ -232,6 +234,7 @@ function WebGLPrograms( renderer, cubemaps, cubeuvmaps, extensions, capabilities
 
 			alphaMap: HAS_ALPHAMAP,
 			alphaTest: HAS_ALPHATEST,
+			alphaHash: HAS_ALPHAHASH,
 
 			combine: material.combine,