Browse Source

add ability to have texel encodings (RGBE,RGBM,etc.) on envMap and emissiveMap that can contain unbounded intensities.

Ben Houston 10 years ago
parent
commit
52a0262c2a

+ 10 - 0
src/Three.js

@@ -305,3 +305,13 @@ THREE.WrapAroundEnding = 2402;
 THREE.TrianglesDrawMode = 0;
 THREE.TriangleStripDrawMode = 1;
 THREE.TriangleFanDrawMode = 2;
+
+// Texture Encodings
+
+THREE.Linear = 3000; // No encoding at all.
+THREE.sRGB = 3001; // AKA gamma 2.2.
+THREE.RGBE = 3002; // AKA Radiance
+//THREE.LogLuv = 3003; TODO
+THREE.RGBM7 = 3004;
+THREE.RGBM16 = 3005;
+//THREE.RGBD = 3006; TODO

+ 4 - 0
src/renderers/WebGLRenderer.js

@@ -1962,6 +1962,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 		}
 
 		uniforms.envMap.value = material.envMap;
+		uniforms.envMapEncoding.value = material.envMap.encoding;
 		uniforms.flipEnvMap.value = ( material.envMap instanceof THREE.WebGLRenderTargetCube ) ? 1 : - 1;
 
 		uniforms.reflectivity.value = material.reflectivity;
@@ -2033,6 +2034,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 		if ( material.emissiveMap ) {
 
 			uniforms.emissiveMap.value = material.emissiveMap;
+			uniforms.emissiveMapEncoding.value = material.emissiveMap.encoding;
 
 		}
 
@@ -2053,6 +2055,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 		if ( material.emissiveMap ) {
 
 			uniforms.emissiveMap.value = material.emissiveMap;
+			uniforms.emissiveMapEncoding.value = material.emissiveMap.encoding;
 
 		}
 
@@ -2107,6 +2110,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 		if ( material.emissiveMap ) {
 
 			uniforms.emissiveMap.value = material.emissiveMap;
+			uniforms.emissiveMapEncoding.value = material.emissiveMap.encoding;
 
 		}
 

+ 1 - 1
src/renderers/shaders/ShaderChunk/emissivemap_fragment.glsl

@@ -2,7 +2,7 @@
 
 	vec4 emissiveColor = texture2D( emissiveMap, vUv );
 
-	emissiveColor.rgb = inputToLinear( emissiveColor.rgb );
+	emissiveColor.rgb = texelDecode( emissiveColor, emissiveMapEncoding ).rgb;
 
 	totalEmissiveLight *= emissiveColor.rgb;
 

+ 1 - 0
src/renderers/shaders/ShaderChunk/emissivemap_pars_fragment.glsl

@@ -1,5 +1,6 @@
 #ifdef USE_EMISSIVEMAP
 
 	uniform sampler2D emissiveMap;
+	uniform int emissiveMapEncoding;
 
 #endif

+ 85 - 0
src/renderers/shaders/ShaderChunk/encodings.glsl

@@ -0,0 +1,85 @@
+// These encodings should have the same integer values as THREE.Linear, THREE.sRGB, etc...
+#define ENCODING_Linear 3000
+#define ENCODING_sRGB   3001  // AKA gamma 2.2.
+#define ENCODING_RGBE   3002  // Radiance
+//#define ENCODING_LogLuv 3003
+#define ENCODING_RGBM7  3004
+#define ENCODING_RGBM16 3005
+//#define ENCODING_RGBM16 3007
+
+vec4 texelDecode( in vec4 encodedTexel, in int encoding ) {
+
+  // Q: should we use a switch statement here instead of a set of ifs?
+
+  if( encoding == ENCODING_Linear ) {
+    return encodedTexel;
+  }
+
+  if( encoding == ENCODING_sRGB ) {
+    return vec4( pow( encodedTexel.xyz, vec3( 2.2 ) ), encodedTexel.w );
+  }
+
+  if( encoding == ENCODING_RGBE ) {
+    return vec4( encodedTexel.xyz * exp2( encodedTexel.w*256.0 - 128.0 ), 1.0 );
+  }
+
+  // TODO
+  //if( encoding == ENCODING_LogLuv ) {
+  //}
+
+  if( encoding == ENCODING_RGBM7 ) {
+    return vec4( encodedTexel.xyz * encodedTexel.w * 7.0, 1.0 );
+  }
+
+  if( encoding == ENCODING_RGBM16 ) {
+    return vec4( encodedTexel.xyz * encodedTexel.w * 16.0, 1.0 );
+  }
+
+  // TODO
+  //if( encoding == ENCODING_RGBD ) {
+  //}
+
+  // return red when encoding not supported
+  return vec4( 1.0, 0.0, 0.0, 1.0 );
+
+}
+
+vec4 texelEncode( in vec4 linearRgba, in int encoding )
+{
+
+  // Q: should we use a switch statement here instead of a set of ifs?
+
+  if( encoding == ENCODING_Linear ) {
+    return linearRgba;
+  }
+
+  if( encoding == ENCODING_sRGB ) {
+    return vec4( pow( linearRgba.xyz, vec3( 0.4545 ) ), encodedTexel.w );
+  }
+
+  if( encoding == ENCODING_RGBE ) {
+    float maxComponent = max(max(linearRgba.r, linearRgba.g), linearRgba.b );
+    float fExp = ceil( log2(maxComponent) );
+    return vec4( linearRgba.rgb / exp2(fExp), (fExp + 128.0) / 255.0 );
+  }
+
+  // TODO
+  //if( encoding == ENCODING_LogLuv ) {
+  //}
+
+  // TODO
+  //if( encoding == ENCODING_RGBM7 ) {
+  //}
+
+  // TODO
+  //if( encoding == ENCODING_RGBM16 ) {
+  //}
+
+  // TODO
+  //if( encoding == ENCODING_RGBD ) {
+  //}
+
+  // return red when encoding not supported
+  return vec4( 1.0, 0.0, 0.0, 1.0 );
+
+}

+ 1 - 1
src/renderers/shaders/ShaderChunk/envmap_fragment.glsl

@@ -43,7 +43,7 @@
 		vec4 envColor = texture2D( envMap, reflectView.xy * 0.5 + 0.5 );
 	#endif
 
-	envColor.xyz = inputToLinear( envColor.xyz );
+	envColor = texelDecode( envColor, envMapEncoding );
 
 	#ifdef ENVMAP_BLENDING_MULTIPLY
 

+ 1 - 0
src/renderers/shaders/ShaderChunk/envmap_pars_fragment.glsl

@@ -10,6 +10,7 @@
 		uniform sampler2D envMap;
 	#endif
 	uniform float flipEnvMap;
+	uniform int envMapEncoding;
 
 	#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG ) || defined( STANDARD )
 

+ 2 - 2
src/renderers/shaders/ShaderChunk/lights_pars.glsl

@@ -186,7 +186,7 @@
 
 		#endif
 
-		envMapColor.rgb = inputToLinear( envMapColor.rgb );
+		envMapColor.rgb = texelDecode( envMapColor.rgb, envMapEncoding );
 
 		return PI * envMapColor.rgb * envMapIntensity;
 
@@ -278,7 +278,7 @@
 
 		#endif
 
-		envMapColor.rgb = inputToLinear( envMapColor.rgb );
+		envMapColor.rgb = texelDecode( envMapColor.rgb, envMapEncoding );
 
 		return envMapColor.rgb * envMapIntensity;
 

+ 5 - 0
src/renderers/shaders/ShaderLib.js

@@ -73,6 +73,7 @@ THREE.ShaderLib = {
 			"#endif",
 
 			THREE.ShaderChunk[ "common" ],
+			THREE.ShaderChunk[ "encodings" ],
 			THREE.ShaderChunk[ "color_pars_fragment" ],
 			THREE.ShaderChunk[ "uv_pars_fragment" ],
 			THREE.ShaderChunk[ "uv2_pars_fragment" ],
@@ -153,6 +154,7 @@ THREE.ShaderLib = {
 			THREE.ShaderChunk[ "uv2_pars_vertex" ],
 			THREE.ShaderChunk[ "envmap_pars_vertex" ],
 			THREE.ShaderChunk[ "bsdfs" ],
+			THREE.ShaderChunk[ "encodings" ],
 			THREE.ShaderChunk[ "lights_pars" ],
 			THREE.ShaderChunk[ "color_pars_vertex" ],
 			THREE.ShaderChunk[ "morphtarget_pars_vertex" ],
@@ -212,6 +214,7 @@ THREE.ShaderLib = {
 			THREE.ShaderChunk[ "emissivemap_pars_fragment" ],
 			THREE.ShaderChunk[ "envmap_pars_fragment" ],
 			THREE.ShaderChunk[ "bsdfs" ],
+			THREE.ShaderChunk[ "encodings" ],
 			THREE.ShaderChunk[ "ambient_pars" ],
 			THREE.ShaderChunk[ "lights_pars" ],
 			THREE.ShaderChunk[ "fog_pars_fragment" ],
@@ -377,6 +380,7 @@ THREE.ShaderLib = {
 			THREE.ShaderChunk[ "envmap_pars_fragment" ],
 			THREE.ShaderChunk[ "fog_pars_fragment" ],
 			THREE.ShaderChunk[ "bsdfs" ],
+			THREE.ShaderChunk[ "encodings" ],
 			THREE.ShaderChunk[ "ambient_pars" ],
 			THREE.ShaderChunk[ "lights_pars" ],
 			THREE.ShaderChunk[ "lights_phong_pars_fragment" ],
@@ -540,6 +544,7 @@ THREE.ShaderLib = {
 			THREE.ShaderChunk[ "envmap_pars_fragment" ],
 			THREE.ShaderChunk[ "fog_pars_fragment" ],
 			THREE.ShaderChunk[ "bsdfs" ],
+			THREE.ShaderChunk[ "encodings" ],
 			THREE.ShaderChunk[ "ambient_pars" ],
 			THREE.ShaderChunk[ "lights_pars" ],
 			THREE.ShaderChunk[ "lights_standard_pars_fragment" ],

+ 3 - 1
src/renderers/shaders/UniformsLib.js

@@ -16,6 +16,7 @@ THREE.UniformsLib = {
 		"alphaMap": { type: "t", value: null },
 
 		"envMap": { type: "t", value: null },
+		"envMapEncoding" : { type: "i", value: THREE.Linear },
 		"flipEnvMap": { type: "f", value: - 1 },
 		"reflectivity": { type: "f", value: 1.0 },
 		"refractionRatio": { type: "f", value: 0.98 }
@@ -38,7 +39,8 @@ THREE.UniformsLib = {
 
 	emissivemap: {
 
-		"emissiveMap": { type: "t", value: null }
+		"emissiveMap": { type: "t", value: null },
+		"emissiveMapEncoding": { type: "i", value: THREE.Linear }
 
 	},
 

+ 3 - 1
src/textures/Texture.js

@@ -35,7 +35,8 @@ THREE.Texture = function ( image, mapping, wrapS, wrapT, magFilter, minFilter, f
 	this.generateMipmaps = true;
 	this.premultiplyAlpha = false;
 	this.flipY = true;
-	this.unpackAlignment = 4; // valid values: 1, 2, 4, 8 (see http://www.khronos.org/opengles/sdk/docs/man/xhtml/glPixelStorei.xml)
+	this.unpackAlignment = 4;	// valid values: 1, 2, 4, 8 (see http://www.khronos.org/opengles/sdk/docs/man/xhtml/glPixelStorei.xml)
+	this.encoding = THREE.Linear;	// Values !== THREE.Linear only supported on envMap and emissiveMap (as these maps regularly have unbounded intensity values, i.e. via an *.hdr or *.exr image.)
 
 	this.version = 0;
 	this.onUpdate = null;
@@ -86,6 +87,7 @@ THREE.Texture.prototype = {
 		this.premultiplyAlpha = source.premultiplyAlpha;
 		this.flipY = source.flipY;
 		this.unpackAlignment = source.unpackAlignment;
+		this.encoding = source.encoding;
 
 		return this;