Bladeren bron

Add parameter to Material to remove banding with dithering

Brian Chirls 8 jaren geleden
bovenliggende
commit
c40466c4a2

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

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

+ 2 - 2
examples/webgl_lights_spotlight.html

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

+ 2 - 0
src/materials/Material.js

@@ -52,6 +52,8 @@ function Material() {
 	this.polygonOffsetFactor = 0;
 	this.polygonOffsetFactor = 0;
 	this.polygonOffsetUnits = 0;
 	this.polygonOffsetUnits = 0;
 
 
+	this.removeBanding = false;
+
 	this.alphaTest = 0;
 	this.alphaTest = 0;
 	this.premultipliedAlpha = false;
 	this.premultipliedAlpha = false;
 
 

+ 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 packing from './ShaderChunk/packing.glsl';
 import premultiplied_alpha_fragment from './ShaderChunk/premultiplied_alpha_fragment.glsl';
 import premultiplied_alpha_fragment from './ShaderChunk/premultiplied_alpha_fragment.glsl';
 import project_vertex from './ShaderChunk/project_vertex.glsl';
 import project_vertex from './ShaderChunk/project_vertex.glsl';
+import removebanding_fragment from './ShaderChunk/removebanding_fragment.glsl';
+import removebanding_pars_fragment from './ShaderChunk/removebanding_pars_fragment.glsl';
 import roughnessmap_fragment from './ShaderChunk/roughnessmap_fragment.glsl';
 import roughnessmap_fragment from './ShaderChunk/roughnessmap_fragment.glsl';
 import roughnessmap_pars_fragment from './ShaderChunk/roughnessmap_pars_fragment.glsl';
 import roughnessmap_pars_fragment from './ShaderChunk/roughnessmap_pars_fragment.glsl';
 import shadowmap_pars_fragment from './ShaderChunk/shadowmap_pars_fragment.glsl';
 import shadowmap_pars_fragment from './ShaderChunk/shadowmap_pars_fragment.glsl';
@@ -172,6 +174,8 @@ export var ShaderChunk = {
 	packing: packing,
 	packing: packing,
 	premultiplied_alpha_fragment: premultiplied_alpha_fragment,
 	premultiplied_alpha_fragment: premultiplied_alpha_fragment,
 	project_vertex: project_vertex,
 	project_vertex: project_vertex,
+	removebanding_fragment: removebanding_fragment,
+	removebanding_pars_fragment: removebanding_pars_fragment,
 	roughnessmap_fragment: roughnessmap_fragment,
 	roughnessmap_fragment: roughnessmap_fragment,
 	roughnessmap_pars_fragment: roughnessmap_pars_fragment,
 	roughnessmap_pars_fragment: roughnessmap_pars_fragment,
 	shadowmap_pars_fragment: shadowmap_pars_fragment,
 	shadowmap_pars_fragment: shadowmap_pars_fragment,

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

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

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

@@ -0,0 +1,14 @@
+// based on https://www.shadertoy.com/view/MslGR8
+vec3 removeBanding( 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 );
 	gl_FragColor = vec4( outgoingLight, diffuseColor.a );
 
 
+	#include <removebanding_fragment>
 	#include <premultiplied_alpha_fragment>
 	#include <premultiplied_alpha_fragment>
 	#include <tonemapping_fragment>
 	#include <tonemapping_fragment>
 	#include <encodings_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 );
 	gl_FragColor = vec4( outgoingLight, diffuseColor.a );
 
 
+	#include <removebanding_fragment>
 	#include <premultiplied_alpha_fragment>
 	#include <premultiplied_alpha_fragment>
 	#include <tonemapping_fragment>
 	#include <tonemapping_fragment>
 	#include <encodings_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 );
 	gl_FragColor = vec4( outgoingLight, diffuseColor.a );
 
 
+	#include <removebanding_fragment>
 	#include <premultiplied_alpha_fragment>
 	#include <premultiplied_alpha_fragment>
 	#include <tonemapping_fragment>
 	#include <tonemapping_fragment>
 	#include <encodings_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 ) ? 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.toneMapping !== NoToneMapping ) ? getToneMappingFunction( "toneMapping", parameters.toneMapping ) : '',
 
 
+			parameters.removeBanding ? '#define REMOVE_BANDING' : '',
+			parameters.removeBanding ? ShaderChunk[ 'removebanding_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.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.mapEncoding ? getTexelDecodingFunction( 'mapTexelToLinear', parameters.mapEncoding ) : '',
 			parameters.envMapEncoding ? getTexelDecodingFunction( 'envMapTexelToLinear', parameters.envMapEncoding ) : '',
 			parameters.envMapEncoding ? getTexelDecodingFunction( 'envMapTexelToLinear', parameters.envMapEncoding ) : '',

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

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