소스 검색

more work on PMREM - split out Encodings.js, Half.js

Ben Houston 9 년 전
부모
커밋
4bf3b5806f

+ 1 - 0
examples/files.js

@@ -119,6 +119,7 @@ var files = {
 		"webgl_materials_cubemap_refraction",
 		"webgl_materials_cubemap_refraction",
 		"webgl_materials_displacementmap",
 		"webgl_materials_displacementmap",
 		"webgl_materials_envmaps",
 		"webgl_materials_envmaps",
+		"webgl_materials_envmaps_hdr",
 		"webgl_materials_grass",
 		"webgl_materials_grass",
 		"webgl_materials_lightmap",
 		"webgl_materials_lightmap",
 		"webgl_materials_nodes",
 		"webgl_materials_nodes",

+ 26 - 0
examples/js/Encodings.js

@@ -0,0 +1,26 @@
+/**
+ * @author Ben Houston / http://clara.io / bhouston
+ * @author Prashant Sharma / spidersharma03
+ */
+
+THREE.Encodings = function() {
+  if( THREE.toHalf === undefined ) throw new Error("THREE.Encodings is required for HDRCubeMapLoader when loading half data.");
+}
+
+THREE.Encodings.RGBEByteToRGBFloat = function( sourceArray, sourceOffset, destArray, destOffset ) {
+  var e = sourceArray[sourceOffset+3];
+  var scale = Math.pow(2.0, e - 128.0) / 255.0;
+
+  destArray[destOffset+0] = sourceArray[sourceOffset+0] * scale;
+  destArray[destOffset+1] = sourceArray[sourceOffset+1] * scale;
+  destArray[destOffset+2] = sourceArray[sourceOffset+2] * scale;
+}
+
+THREE.Encodings.RGBEByteToRGBHalf = function( sourceArray, sourceOffset, destArray, destOffset ) {
+  var e = sourceArray[sourceOffset+3];
+  var scale = Math.pow(2.0, e - 128.0) / 255.0;
+
+  destArray[destOffset+0] = THREE.toHalf( sourceArray[sourceOffset+0] * scale );
+  destArray[destOffset+1] = THREE.toHalf( sourceArray[sourceOffset+1] * scale );
+  destArray[destOffset+2] = THREE.toHalf( sourceArray[sourceOffset+2] * scale );
+}

+ 51 - 0
examples/js/Half.js

@@ -0,0 +1,51 @@
+/**
+ * @author Prashant Sharma / spidersharma03
+ */
+
+THREE.toHalf = (function() {
+  var floatView = new Float32Array(1);
+  var int32View = new Int32Array(floatView.buffer);
+
+  /* This method is faster than the OpenEXR implementation (very often
+   * used, eg. in Ogre), with the additional benefit of rounding, inspired
+   * by James Tursa?s half-precision code. */
+  return function toHalf(val) {
+
+    floatView[0] = val;
+    var x = int32View[0];
+
+    var bits = (x >> 16) & 0x8000; /* Get the sign */
+    var m = (x >> 12) & 0x07ff; /* Keep one extra bit for rounding */
+    var e = (x >> 23) & 0xff; /* Using int is faster here */
+
+    /* If zero, or denormal, or exponent underflows too much for a denormal
+     * half, return signed zero. */
+    if (e < 103) {
+      return bits;
+    }
+
+    /* If NaN, return NaN. If Inf or exponent overflow, return Inf. */
+    if (e > 142) {
+      bits |= 0x7c00;
+      /* If exponent was 0xff and one mantissa bit was set, it means NaN,
+           * not Inf, so make sure we set one mantissa bit too. */
+      bits |= ((e == 255) ? 0 : 1) && (x & 0x007fffff);
+      return bits;
+    }
+
+    /* If exponent underflows but not too much, return a denormal */
+    if (e < 113) {
+      m |= 0x0800;
+      /* Extra rounding may overflow and set mantissa to 0 and exponent
+       * to 1, which is OK. */
+      bits |= (m >> (114 - e)) + ((m >> (113 - e)) & 1);
+      return bits;
+    }
+
+    bits |= ((e - 112) << 10) | (m >> 1);
+    /* Extra rounding. An overflow will set mantissa to 0 and increment
+     * the exponent, which is OK. */
+    bits += m & 1;
+    return bits;
+  };
+}());

+ 75 - 146
examples/js/loaders/HDRCubeMapLoader.js

@@ -1,153 +1,82 @@
 /**
 /**
- * @author Prashant Sharma / spidersharma03
- */
-
- var toHalf = (function() {
-   var floatView = new Float32Array(1);
-   var int32View = new Int32Array(floatView.buffer);
-
-   /* This method is faster than the OpenEXR implementation (very often
-    * used, eg. in Ogre), with the additional benefit of rounding, inspired
-    * by James Tursa?s half-precision code. */
-   return function toHalf(val) {
-
-     floatView[0] = val;
-     var x = int32View[0];
-
-     var bits = (x >> 16) & 0x8000; /* Get the sign */
-     var m = (x >> 12) & 0x07ff; /* Keep one extra bit for rounding */
-     var e = (x >> 23) & 0xff; /* Using int is faster here */
-
-     /* If zero, or denormal, or exponent underflows too much for a denormal
-      * half, return signed zero. */
-     if (e < 103) {
-       return bits;
-     }
-
-     /* If NaN, return NaN. If Inf or exponent overflow, return Inf. */
-     if (e > 142) {
-       bits |= 0x7c00;
-       /* If exponent was 0xff and one mantissa bit was set, it means NaN,
-            * not Inf, so make sure we set one mantissa bit too. */
-       bits |= ((e == 255) ? 0 : 1) && (x & 0x007fffff);
-       return bits;
-     }
-
-     /* If exponent underflows but not too much, return a denormal */
-     if (e < 113) {
-       m |= 0x0800;
-       /* Extra rounding may overflow and set mantissa to 0 and exponent
-        * to 1, which is OK. */
-       bits |= (m >> (114 - e)) + ((m >> (113 - e)) & 1);
-       return bits;
-     }
-
-     bits |= ((e - 112) << 10) | (m >> 1);
-     /* Extra rounding. An overflow will set mantissa to 0 and increment
-      * the exponent, which is OK. */
-     bits += m & 1;
-     return bits;
-   };
- }());
+* @author Prashant Sharma / spidersharma03
+* @author Ben Houston / http://clara.io / bhouston
+*/
 
 
 THREE.HDRCubeMapLoader = function (manager) {
 THREE.HDRCubeMapLoader = function (manager) {
-    this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager;
-    // override in sub classes
-    this.hdrLoader = new THREE.RGBELoader();
+  this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager;
+  // override in sub classes
+  this.hdrLoader = new THREE.RGBELoader();
+
+  if( THREE.Encodings === undefined ) throw new Error( "HDRCubeMapLoader requires THREE.Encodings" );
 }
 }
 
 
 THREE.HDRCubeMapLoader.prototype.load = function(type, urls, onLoad, onProgress, onError) {
 THREE.HDRCubeMapLoader.prototype.load = function(type, urls, onLoad, onProgress, onError) {
-    var texture = new THREE.CubeTexture( [] );
-    type = (type === undefined) ? THREE.UnsignedByteType : type;
-    texture.encoding = THREE.Linear;
-    if(type === THREE.UnsignedByteType)
-        texture.encoding = THREE.RGBE;
-    var scope = this.hdrLoader;
-
-    var loaded = 0;
-
-     function loadHDRData(i, onLoad, onProgress, onError) {
-        var loader = new THREE.XHRLoader( this.manager );
-        loader.setResponseType( 'arraybuffer' );
-
-        loader.load( urls[i], function ( buffer ) {
-                loaded++;
-
-                var texData = scope._parser( buffer );
-
-                texData.type = type;
-
-                if ( ! texData ) return;
-
-                if(type === THREE.FloatType) {
-                    var floatdata = new Float32Array(texData.data.length);
-                    for( var j=0; j<floatdata.length; j+=4)
-                    {
-                        var r = texData.data[j]/255;
-                        var g = texData.data[j+1]/255;
-                        var b = texData.data[j+2]/255;
-                        var e = texData.data[j+3]/255;
-                        var d = Math.pow(2.0, e*255.0 - 128.0);
-                        floatdata[j]   = r * d;
-                        floatdata[j+1] = g * d;
-                        floatdata[j+2] = b * d;
-                        floatdata[j+3] = 1.0;
-                    }
-                    texData.data = floatdata;
-                }
-                if(type === THREE.HalfFloatType) {
-                    var floatdata = new Uint16Array(texData.data.length);
-                    for( var j=0; j<floatdata.length; j+=4)
-                    {
-                        var r = texData.data[j]/255;
-                        var g = texData.data[j+1]/255;
-                        var b = texData.data[j+2]/255;
-                        var e = texData.data[j+3]/255;
-                        var d = Math.pow(2.0, e*255.0 - 128.0);
-                        floatdata[j]   = toHalf(r * d);
-                        floatdata[j+1] = toHalf(g * d);
-                        floatdata[j+2] = toHalf(b * d);
-                        floatdata[j+3] = toHalf(1.0);
-                    }
-                    texData.data = floatdata;
-                }
-
-                if ( undefined !== texData.image ) {
-                        texture[i].images = texData.image;
-                }
-                else if ( undefined !== texData.data ) {
-                        var dataTexture = new THREE.DataTexture(texData.data, texData.width, texData.height);
-                        dataTexture.format = texData.format;
-                        dataTexture.type = texData.type;
-                        dataTexture.minFilter = THREE.LinearFilter;
-                        dataTexture.magFilter = THREE.LinearFilter;
-                        dataTexture.generateMipmaps = false;
-                        texture.images[i] = dataTexture;
-                }
-
-                if(loaded === 6) {
-                        texture.needsUpdate = true;
-
-                        if ( undefined !== texData.format ) {
-
-                                texture.format = texData.format;
-
-                        }
-                        if ( undefined !== texData.type ) {
-
-                                texture.type = texData.type;
-
-                        }
-                        texture.minFilter = THREE.LinearFilter;
-                        texture.magFilter = THREE.LinearFilter;
-                        texture.generateMipmaps = false;
-                        if ( onLoad ) onLoad( texture );
-                }
-        }, onProgress, onError );
-    }
-
-    for(var i=0; i<urls.length; i++) {
-        loadHDRData(i, onLoad, onProgress, onError);
-    }
-    return texture;
+  var texture = new THREE.CubeTexture( [] );
+
+  texture.type = type;
+  texture.encoding = (type === THREE.UnsignedByteType) ? THREE.RGBEEncoding : THREE.LinearEncoding;
+  texture.format = (type === THREE.UnsignedByteType ) ? THREE.RGBAFormat : THREE.RGBFormat;
+  texture.minFilter = THREE.LinearFilter;
+  texture.magFilter = THREE.LinearFilter;
+  texture.generateMipmaps = false;
+
+  var scope = this.hdrLoader;
+
+  var loaded = 0;
+
+  function loadHDRData(i, onLoad, onProgress, onError) {
+    var loader = new THREE.XHRLoader( this.manager );
+    loader.setResponseType( 'arraybuffer' );
+
+    loader.load( urls[i], function ( buffer ) {
+      loaded++;
+
+      var texData = scope._parser( buffer );
+
+      if ( ! texData ) return;
+
+      if(type === THREE.FloatType) {
+        var numElements = ( texData.data.length / 4 )*3;
+        var floatdata = new Float32Array( numElements );
+        for( var j=0; j<numElements; j++) {
+          THREE.Encodings.RGBEByteToRGBFloat( texData.data, j*4, floatdata, j*3 );
+        }
+        texData.data = floatdata;
+      }
+      else if(type === THREE.HalfFloatType) {
+        var numElements = ( texData.data.length / 4 )*3;
+        var halfdata = new Uint16Array( numElements );
+        for( var j=0; j<numElements; j++) {
+          THREE.Encodings.RGBEByteToRGBHalf( texData.data, j*4, floatdata, j*3 );
+        }
+        texData.data = floatdata;
+      }
+
+      if ( undefined !== texData.image ) {
+        texture[i].images = texData.image;
+      }
+      else if ( undefined !== texData.data ) {
+        var dataTexture = new THREE.DataTexture(texData.data, texData.width, texData.height);
+        dataTexture.format = texture.format;
+        dataTexture.type = texture.type;
+        dataTexture.encoding = texture.encoding;
+        dataTexture.minFilter = texture.minFilter;
+        dataTexture.magFilter = texture.magFilter;
+        dataTexture.generateMipmaps = texture.generateMipmaps;
+
+        texture.images[i] = dataTexture;
+      }
+
+      if(loaded === 6) {
+        texture.needsUpdate = true;
+        if ( onLoad ) onLoad( texture );
+      }
+    }, onProgress, onError );
+  }
+
+  for(var i=0; i<urls.length; i++) {
+    loadHDRData(i, onLoad, onProgress, onError);
+  }
+  return texture;
 };
 };

+ 13 - 15
examples/js/pmrem/PMREMGenerator.js

@@ -28,7 +28,7 @@
 	this.sourceTexture = cubeTexture;
 	this.sourceTexture = cubeTexture;
 
 
   // encoded formats do not interpolate well, thus turn off interpolation for them
   // encoded formats do not interpolate well, thus turn off interpolation for them
-  var textureFilter = ( this.sourceTexture.encoding === THREE.Linear ) ? THREE.LinearFilter : THREE.NearestFilter;
+  var textureFilter = ( this.sourceTexture.encoding === THREE.LinearEncoding ) ? THREE.LinearFilter : THREE.NearestFilter;
   this.sourceTexture.minFilter = this.sourceTexture.magFilter = textureFilter;
   this.sourceTexture.minFilter = this.sourceTexture.magFilter = textureFilter;
 
 
 	this.cubeLods = [];
 	this.cubeLods = [];
@@ -40,7 +40,7 @@
   for ( var i = 0; i < this.numLods; i ++ ) {
   for ( var i = 0; i < this.numLods; i ++ ) {
 		var renderTarget = new THREE.WebGLRenderTargetCube( size, size, params );
 		var renderTarget = new THREE.WebGLRenderTargetCube( size, size, params );
 		renderTarget.texture.generateMipmaps = false;
 		renderTarget.texture.generateMipmaps = false;
-    renderTarget.encoding = this.sourceTexture.encoding;
+    renderTarget.texture.encoding = this.sourceTexture.encoding;
 		this.cubeLods.push( renderTarget );
 		this.cubeLods.push( renderTarget );
 		size = Math.max( 16, size / 2 );
 		size = Math.max( 16, size / 2 );
 	}
 	}
@@ -54,8 +54,8 @@
 	this.scene.add( this.planeMesh );
 	this.scene.add( this.planeMesh );
 	this.scene.add( this.camera );
 	this.scene.add( this.camera );
 
 
-	this.shader.uniforms[ "sourceTexture" ].value = this.sourceTexture;
-	this.shader.uniforms[ "encoding" ].value = this.sourceTexture.encoding;
+	this.shader.uniforms[ "envMap" ].value = this.sourceTexture;
+  this.shader.envMap = this.sourceTexture;
 };
 };
 
 
 THREE.PMREMGenerator.prototype = {
 THREE.PMREMGenerator.prototype = {
@@ -64,7 +64,8 @@ THREE.PMREMGenerator.prototype = {
 
 
 	update: function( renderer ) {
 	update: function( renderer ) {
 
 
-		this.shader.uniforms[ "sourceTexture" ].value = this.sourceTexture;
+		this.shader.uniforms[ "envMap" ].value = this.sourceTexture;
+    this.shader.envMap = this.sourceTexture;
 		for ( var i = 0; i < this.numLods; i ++ ) {
 		for ( var i = 0; i < this.numLods; i ++ ) {
 
 
 			var r = i / ( this.numLods - 1 );
 			var r = i / ( this.numLods - 1 );
@@ -73,7 +74,7 @@ THREE.PMREMGenerator.prototype = {
 			this.shader.uniforms[ "mapSize" ].value = size;
 			this.shader.uniforms[ "mapSize" ].value = size;
 			this.renderToCubeMapTarget( renderer, this.cubeLods[ i ] );
 			this.renderToCubeMapTarget( renderer, this.cubeLods[ i ] );
 			if ( i < 5 )
 			if ( i < 5 )
-			this.shader.uniforms[ "sourceTexture" ].value = this.cubeLods[ i ];
+			this.shader.uniforms[ "envMap" ].value = this.cubeLods[ i ];
 
 
 		}
 		}
 
 
@@ -104,8 +105,7 @@ THREE.PMREMGenerator.prototype = {
         "faceIndex": { type: 'i', value: 0 },
         "faceIndex": { type: 'i', value: 0 },
         "roughness": { type: 'f', value: 0.5 },
         "roughness": { type: 'f', value: 0.5 },
         "mapSize": { type: 'f', value: 0.5 },
         "mapSize": { type: 'f', value: 0.5 },
-        "sourceTexture": { type: 't', value: null },
-        "encoding": { type: 'i', value: 3002},
+        "envMap": { type: 't', value: null },
         "testColor": { type: 'v3', value: new THREE.Vector3( 1, 1, 1 ) }
         "testColor": { type: 'v3', value: new THREE.Vector3( 1, 1, 1 ) }
       },
       },
 
 
@@ -120,10 +120,9 @@ THREE.PMREMGenerator.prototype = {
         "varying vec2 vUv;\n\
         "varying vec2 vUv;\n\
         uniform int faceIndex;\n\
         uniform int faceIndex;\n\
         uniform float roughness;\n\
         uniform float roughness;\n\
-        uniform samplerCube sourceTexture;\n\
+        uniform samplerCube envMap;\n\
         uniform float mapSize;\n\
         uniform float mapSize;\n\
         uniform vec3 testColor;\n\
         uniform vec3 testColor;\n\
-        uniform int encoding;\n\
         \n\
         \n\
         float rnd(vec2 uv) {\n\
         float rnd(vec2 uv) {\n\
            return fract(sin(dot(uv, vec2(12.9898, 78.233) * 2.0)) * 43758.5453);\n\
            return fract(sin(dot(uv, vec2(12.9898, 78.233) * 2.0)) * 43758.5453);\n\
@@ -172,9 +171,8 @@ THREE.PMREMGenerator.prototype = {
            else\n\
            else\n\
                color = vec4(1.0,0.0,1.0,1.0);\n\
                color = vec4(1.0,0.0,1.0,1.0);\n\
            return color;\n\
            return color;\n\
-        }" +
-  			THREE.ShaderChunk[ "encodings" ] +
-        "void main() {\n\
+        }\n\
+        void main() {\n\
            vec3 sampleDirection;\n\
            vec3 sampleDirection;\n\
            vec2 uv = vUv*2.0 - 1.0;\n\
            vec2 uv = vUv*2.0 - 1.0;\n\
            float offset = -1.0/mapSize;\n\
            float offset = -1.0/mapSize;\n\
@@ -211,11 +209,11 @@ THREE.PMREMGenerator.prototype = {
                vect = ImportanceSampleGGX(vec2(float(i) / float(NumSamples), rand), vecSpace, roughness);\n\
                vect = ImportanceSampleGGX(vec2(float(i) / float(NumSamples), rand), vecSpace, roughness);\n\
                float dotProd = dot(vect, normalize(sampleDirection));\n\
                float dotProd = dot(vect, normalize(sampleDirection));\n\
                weight += dotProd;\n\
                weight += dotProd;\n\
-               vec3 color = texelDecode(textureCube(sourceTexture, vect), encoding).rgb;\n\
+               vec3 color = envMapTexelToLinear(textureCube(envMap,vect)).rgb;\n\
                rgbColor.rgb += color;\n\
                rgbColor.rgb += color;\n\
            }\n\
            }\n\
            rgbColor /= float(NumSamples);\n\
            rgbColor /= float(NumSamples);\n\
-           gl_FragColor = texelEncode( vec4( rgbColor, 1.0 ), encoding );\n\
+           gl_FragColor = linearToOutputTexel( vec4( rgbColor, 1.0 ) );\n\
         }"
         }"
       }
       }
     );
     );

+ 3 - 1
examples/webgl_materials_ibl_hdr.html → examples/webgl_materials_envmaps_hdr.html

@@ -38,6 +38,8 @@
 		<script src="../examples/js/Detector.js"></script>
 		<script src="../examples/js/Detector.js"></script>
 		<script src="../examples/js/libs/stats.min.js"></script>
 		<script src="../examples/js/libs/stats.min.js"></script>
 
 
+		<script src="../examples/js/Half.js"></script>
+		<script src="../examples/js/Encodings.js"></script>
     <script src="../examples/js/pmrem/PMREMGenerator.js"></script>
     <script src="../examples/js/pmrem/PMREMGenerator.js"></script>
     <script src="../examples/js/pmrem/PMREM_CubeUVPacker.js"></script>
     <script src="../examples/js/pmrem/PMREM_CubeUVPacker.js"></script>
     <script src="../examples/js/libs/dat.gui.min.js"></script>
     <script src="../examples/js/libs/dat.gui.min.js"></script>
@@ -301,7 +303,7 @@
 				container.appendChild( renderer.domElement );
 				container.appendChild( renderer.domElement );
 
 
 				renderer.gammaInput = true;
 				renderer.gammaInput = true;
-				renderer.gammaOutput = true;
+				renderer.gammaOutput = false;
 
 
                                                                 var renderScene = new THREE.RenderPass(scene, camera);
                                                                 var renderScene = new THREE.RenderPass(scene, camera);
 
 

+ 4 - 4
src/renderers/shaders/ShaderChunk/cube_uv_reflection_fragment.glsl

@@ -125,10 +125,10 @@ vec4 textureCubeUV(vec3 reflectedDirection, float roughness, float textureSize)
     vec2 uv_11 = getCubeUV(reflectedDirection, r1, level1, textureSize);
     vec2 uv_11 = getCubeUV(reflectedDirection, r1, level1, textureSize);
     vec2 uv_20 = getCubeUV(reflectedDirection, r2, level0, textureSize);
     vec2 uv_20 = getCubeUV(reflectedDirection, r2, level0, textureSize);
     vec2 uv_21 = getCubeUV(reflectedDirection, r2, level1, textureSize);
     vec2 uv_21 = getCubeUV(reflectedDirection, r2, level1, textureSize);
-    vec4 color10 = texelDecode(texture2D(envMap, uv_10), envMapEncoding);
-    vec4 color11 = texelDecode(texture2D(envMap, uv_11), envMapEncoding);
-    vec4 color20 = texelDecode(texture2D(envMap, uv_20), envMapEncoding);
-    vec4 color21 = texelDecode(texture2D(envMap, uv_21), envMapEncoding);
+    vec4 color10 = envMapTexelToLinear(texture2D(envMap, uv_10));
+    vec4 color11 = envMapTexelToLinear(texture2D(envMap, uv_11));
+    vec4 color20 = envMapTexelToLinear(texture2D(envMap, uv_20));
+    vec4 color21 = envMapTexelToLinear(texture2D(envMap, uv_21));
     vec4 c1 = mix(color10 , color11,  s);
     vec4 c1 = mix(color10 , color11,  s);
     vec4 c2 = mix(color20 , color21,  s);
     vec4 c2 = mix(color20 , color21,  s);
     vec4 c3 = mix(c1 , c2,  t);
     vec4 c3 = mix(c1 , c2,  t);