Pārlūkot izejas kodu

Merge pull request #11076 from brianchirls/remove-banding

Add parameter to Material to remove banding with dithering
Mr.doob 8 gadi atpakaļ
vecāks
revīzija
7f55016b84

+ 6 - 0
docs/api/materials/Material.html

@@ -198,6 +198,12 @@
 		Default is *false*.
 		</div>
 
+		<h3>[property:Boolean dithering]</h3>
+		<div>
+		Whether to apply dithering to the color to remove the appearance of banding.
+		Default is *false*.
+		</div>
+
 		<h3>[property:Integer shading]</h3>
 		<div>
 		Defines how the material is shaded.

+ 2 - 2
examples/webgl_lights_spotlight.html

@@ -54,8 +54,8 @@
 
 			var scene = new THREE.Scene();
 
-			var matFloor = new THREE.MeshPhongMaterial();
-			var matBox = new THREE.MeshPhongMaterial( { color: 0x4080ff } );
+			var matFloor = new THREE.MeshPhongMaterial( { dithering: true } );
+			var matBox = new THREE.MeshPhongMaterial( { color: 0x4080ff, dithering: true } );
 
 			var geoFloor = new THREE.BoxGeometry( 2000, 1, 2000 );
 			var geoBox = new THREE.BoxGeometry( 3, 1, 2 );

+ 6 - 0
src/materials/Material.js

@@ -52,6 +52,8 @@ function Material() {
 	this.polygonOffsetFactor = 0;
 	this.polygonOffsetUnits = 0;
 
+	this.dithering = false;
+
 	this.alphaTest = 0;
 	this.premultipliedAlpha = false;
 
@@ -218,6 +220,8 @@ Object.assign( Material.prototype, EventDispatcher.prototype, {
 		data.skinning = this.skinning;
 		data.morphTargets = this.morphTargets;
 
+		data.dithering = this.dithering;
+
 		// TODO: Copied from Object3D.toJSON
 
 		function extractFromCache( cache ) {
@@ -290,6 +294,8 @@ Object.assign( Material.prototype, EventDispatcher.prototype, {
 		this.polygonOffsetFactor = source.polygonOffsetFactor;
 		this.polygonOffsetUnits = source.polygonOffsetUnits;
 
+		this.dithering = source.dithering;
+
 		this.alphaTest = source.alphaTest;
 
 		this.premultipliedAlpha = source.premultipliedAlpha;

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

@@ -61,6 +61,8 @@ import normalmap_pars_fragment from './ShaderChunk/normalmap_pars_fragment.glsl'
 import packing from './ShaderChunk/packing.glsl';
 import premultiplied_alpha_fragment from './ShaderChunk/premultiplied_alpha_fragment.glsl';
 import project_vertex from './ShaderChunk/project_vertex.glsl';
+import dithering_fragment from './ShaderChunk/dithering_fragment.glsl';
+import dithering_pars_fragment from './ShaderChunk/dithering_pars_fragment.glsl';
 import roughnessmap_fragment from './ShaderChunk/roughnessmap_fragment.glsl';
 import roughnessmap_pars_fragment from './ShaderChunk/roughnessmap_pars_fragment.glsl';
 import shadowmap_pars_fragment from './ShaderChunk/shadowmap_pars_fragment.glsl';
@@ -172,6 +174,8 @@ export var ShaderChunk = {
 	packing: packing,
 	premultiplied_alpha_fragment: premultiplied_alpha_fragment,
 	project_vertex: project_vertex,
+	dithering_fragment: dithering_fragment,
+	dithering_pars_fragment: dithering_pars_fragment,
 	roughnessmap_fragment: roughnessmap_fragment,
 	roughnessmap_pars_fragment: roughnessmap_pars_fragment,
 	shadowmap_pars_fragment: shadowmap_pars_fragment,

+ 5 - 0
src/renderers/shaders/ShaderChunk/dithering_fragment.glsl

@@ -0,0 +1,5 @@
+#if defined( DITHERING )
+
+  gl_FragColor.rgb = dithering( gl_FragColor.rgb );
+
+#endif

+ 14 - 0
src/renderers/shaders/ShaderChunk/dithering_pars_fragment.glsl

@@ -0,0 +1,14 @@
+// based on https://www.shadertoy.com/view/MslGR8
+vec3 dithering( vec3 color ) {
+	//Calculate grid position
+	float grid_position = fract( dot( gl_FragCoord.xy - vec2( 0.5, 0.5 ) , vec2( 1.0 / 16.0, 10.0 / 36.0 ) + 0.25 ) );
+
+	//Shift the individual colors differently, thus making it even harder to see the dithering pattern
+	vec3 dither_shift_RGB = vec3( 0.25 / 255.0, -0.25 / 255.0, 0.25 / 255.0 );
+
+	//modify shift acording to grid position.
+	dither_shift_RGB = mix( 2.0 * dither_shift_RGB, -2.0 * dither_shift_RGB, grid_position );
+
+	//shift the color by dither_shift
+	return color + 0.5 / 255.0 + dither_shift_RGB;
+}

+ 1 - 0
src/renderers/shaders/ShaderLib/meshlambert_frag.glsl

@@ -75,6 +75,7 @@ void main() {
 
 	gl_FragColor = vec4( outgoingLight, diffuseColor.a );
 
+	#include <dithering_fragment>
 	#include <premultiplied_alpha_fragment>
 	#include <tonemapping_fragment>
 	#include <encodings_fragment>

+ 1 - 0
src/renderers/shaders/ShaderLib/meshphong_frag.glsl

@@ -60,6 +60,7 @@ void main() {
 
 	gl_FragColor = vec4( outgoingLight, diffuseColor.a );
 
+	#include <dithering_fragment>
 	#include <premultiplied_alpha_fragment>
 	#include <tonemapping_fragment>
 	#include <encodings_fragment>

+ 1 - 0
src/renderers/shaders/ShaderLib/meshphysical_frag.glsl

@@ -74,6 +74,7 @@ void main() {
 
 	gl_FragColor = vec4( outgoingLight, diffuseColor.a );
 
+	#include <dithering_fragment>
 	#include <premultiplied_alpha_fragment>
 	#include <tonemapping_fragment>
 	#include <encodings_fragment>

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

@@ -477,6 +477,9 @@ function WebGLProgram( renderer, code, material, parameters ) {
 			( parameters.toneMapping !== NoToneMapping ) ? ShaderChunk[ 'tonemapping_pars_fragment' ] : '',  // this code is required here because it is used by the toneMapping() function defined below
 			( parameters.toneMapping !== NoToneMapping ) ? getToneMappingFunction( "toneMapping", parameters.toneMapping ) : '',
 
+			parameters.dithering ? '#define DITHERING' : '',
+			parameters.dithering ? ShaderChunk[ 'dithering_pars_fragment' ] : '',
+
 			( parameters.outputEncoding || parameters.mapEncoding || parameters.envMapEncoding || parameters.emissiveMapEncoding ) ? ShaderChunk[ 'encodings_pars_fragment' ] : '', // this code is required here because it is used by the various encoding/decoding function defined below
 			parameters.mapEncoding ? getTexelDecodingFunction( 'mapTexelToLinear', parameters.mapEncoding ) : '',
 			parameters.envMapEncoding ? getTexelDecodingFunction( 'envMapTexelToLinear', parameters.envMapEncoding ) : '',

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

@@ -33,7 +33,7 @@ function WebGLPrograms( renderer, capabilities ) {
 		"maxMorphTargets", "maxMorphNormals", "premultipliedAlpha",
 		"numDirLights", "numPointLights", "numSpotLights", "numHemiLights", "numRectAreaLights",
 		"shadowMapEnabled", "shadowMapType", "toneMapping", 'physicallyCorrectLights',
-		"alphaTest", "doubleSided", "flipSided", "numClippingPlanes", "numClipIntersection", "depthPacking"
+		"alphaTest", "doubleSided", "flipSided", "numClippingPlanes", "numClipIntersection", "depthPacking", "dithering"
 	];
 
 
@@ -185,6 +185,8 @@ function WebGLPrograms( renderer, capabilities ) {
 			numClippingPlanes: nClipPlanes,
 			numClipIntersection: nClipIntersection,
 
+			dithering: material.dithering,
+
 			shadowMapEnabled: renderer.shadowMap.enabled && object.receiveShadow && lights.shadows.length > 0,
 			shadowMapType: renderer.shadowMap.type,