浏览代码

Added Float, Half float buffer support for HDR. Fixed a bug in
cube_uv_reflection map shader. (written by @spidersharma03, modified by @bhouston)

Ben Houston 9 年之前
父节点
当前提交
8a630a75df

+ 88 - 2
examples/js/loaders/HDRCubeMapLoader.js

@@ -2,15 +2,66 @@
  * @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;
+   };
+ }());
+
 THREE.HDRCubeMapLoader = function (manager) {
     this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager;
     // override in sub classes
     this.hdrLoader = new THREE.RGBELoader();
 }
 
-THREE.HDRCubeMapLoader.prototype.load = function(urls, onLoad, onProgress, onError) {
+THREE.HDRCubeMapLoader.prototype.load = function(type, urls, onLoad, onProgress, onError) {
     var texture = new THREE.CubeTexture( [] );
-    texture.encoding = THREE.RGBE;
+    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;
@@ -24,8 +75,43 @@ THREE.HDRCubeMapLoader.prototype.load = function(urls, onLoad, onProgress, onErr
 
                 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*256.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*256.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;
                 }

+ 1 - 1
examples/js/pmrem/PMREMGenerator.js

@@ -34,7 +34,7 @@
 	this.cubeLods = [];
 
 	var size = this.resolution;
-  var params = { format: THREE.RGBAFormat, magFilter: textureFilter, minFilter: textureFilter };
+  var params = { format: THREE.RGBAFormat, magFilter: textureFilter, minFilter: textureFilter, type: this.sourceTexture.type };
 
 	this.numLods = Math.log2( size ) - 2;
   for ( var i = 0; i < this.numLods; i ++ ) {

+ 1 - 1
examples/js/pmrem/PMREM_CubeUVPacker.js

@@ -11,7 +11,7 @@ THREE.PMREM_CubeUVPacker = function( cubeTextureLods, numLods ) {
 	var size = cubeTextureLods[ 0 ].width * 4;
 
 	this.CubeUVRenderTarget = new THREE.WebGLRenderTarget( size, size,
-	{ format: THREE.RGBAFormat, magFilter: THREE.LinearFilter, minFilter: THREE.LinearFilter } );
+	{ format: THREE.RGBAFormat, magFilter: THREE.LinearFilter, minFilter: THREE.LinearFilter, type:cubeTextureLods[ 0 ].type } );
 	this.CubeUVRenderTarget.texture.generateMipmaps = false;
                 this.CubeUVRenderTarget.mapping = THREE.CubeUVReflectionMapping;
 	this.camera = new THREE.OrthographicCamera( - size * 0.5, size * 0.5, - size * 0.5, size * 0.5, 0.0, 1000 );

+ 3 - 3
examples/webgl_materials_ibl_hdr.html

@@ -29,7 +29,7 @@
 		<div id="container"></div>
 		<div id="info"><a href="http://threejs.org" target="_blank">threejs</a> - PMREM Generator by Prashant Sharma and <a href="http://clara.io/" target="_blank">Ben Houston</a>.</div>
 
-		<script src="../build/three.min.js"></script>
+		<script src="../build/three.js"></script>
 		<script src="../examples/js/controls/OrbitControls.js"></script>
 		<script src="../src/loaders/BinaryTextureLoader.js"></script>
 		<script src="../examples/js/loaders/RGBELoader.js"></script>
@@ -113,7 +113,7 @@
 			var container, stats;
 			var params = {
 				projection: 'normal',
-				roughnessFactor: 1,
+				roughnessFactor: 0,
 				background: true,
 			};
 			var camera, scene, renderer, controls, objects = [];
@@ -216,7 +216,7 @@
 					//reflectionCube.encoding = THREE.sRGB;
 					//reflectionCube.format = THREE.RGBFormat;
 
-					hdrCubeMap = new THREE.HDRCubeMapLoader().load(hdrurls, onTextureLoad);
+					hdrCubeMap = new THREE.HDRCubeMapLoader().load(THREE.UnsignedByteType, hdrurls, onTextureLoad);
 
 					//                                                                hdrTexture = new THREE.RGBELoader().load( '../examples/textures/cube/hdrPisa/px.hdr', onHdrLoad );
 					var grass = new THREE.TextureLoader().load( '../examples/textures/terrain/grasslight-big.jpg' );

+ 11 - 9
src/renderers/shaders/ShaderChunk/cube_uv_reflection_fragment.glsl

@@ -7,7 +7,7 @@ int getFaceFromDirection(vec3 direction) {
         if(absDirection.x > absDirection.y )
             face = direction.x > 0.0 ? 0 : 3;
         else
-            face = direction.y > 0.0 ? 1 : 4;                            
+            face = direction.y > 0.0 ? 1 : 4;
     }
     else {
         if(absDirection.z > absDirection.y )
@@ -18,11 +18,13 @@ int getFaceFromDirection(vec3 direction) {
     return face;
 }
 
-vec2 MipLevelInfo( vec3 vec, float textureSize ) {
+vec2 MipLevelInfo( vec3 vec, float textureSize, float roughnessLevel, float roughness ) {
     float s = log2(textureSize*0.25) - 1.0;
-    float scale = pow(2.0, s);
-    vec3 dx = dFdx( vec * scale );
-    vec3 dy = dFdy( vec * scale );
+    float scale = pow(2.0, s - roughnessLevel);
+    float dxRoughness = dFdx(roughness);
+    float dyRoughness = dFdy(roughness);
+    vec3 dx = dFdx( vec * scale * dxRoughness );
+    vec3 dy = dFdy( vec * scale * dyRoughness );
     float d = max( dot( dx, dx ), dot( dy, dy ) );
     // Clamp the value to the max mip level counts. hard coded to 6 mips
     float rangeClamp = pow(2.0, (6.0 - 1.0) * 2.0);
@@ -81,7 +83,7 @@ vec2 getCubeUV(vec3 direction, float roughnessLevel, float mipLevel, float textu
     float s2 = (r.z/abs(r.x) + 1.0)*0.5;
     vec2 uv = offset + vec2(s1*scale, s2*scale);
     float min_x = offset.x + texelOffset; float max_x = offset.x + scale - texelOffset;
-    float min_y = offset.y + texelOffset; 
+    float min_y = offset.y + texelOffset;
     float max_y = offset.y + scale - texelOffset;
     float delx = max_x - min_x;
     float dely = max_y - min_y;
@@ -113,7 +115,7 @@ vec4 textureCubeUV(vec3 reflectedDirection, float roughness, float textureSize)
     float r1 = floor(roughnessVal);
     float r2 = r1 + 1.0;
     float t = fract(roughnessVal);
-    vec2 mipInfo = MipLevelInfo(reflectedDirection, textureSize);
+    vec2 mipInfo = MipLevelInfo(reflectedDirection, textureSize, r1, roughness);
     float s = mipInfo.y;
     float level0 = mipInfo.x;
     float level1 = level0 + 1.0;
@@ -130,7 +132,7 @@ vec4 textureCubeUV(vec3 reflectedDirection, float roughness, float textureSize)
     vec4 c1 = mix(color10 , color11,  s);
     vec4 c2 = mix(color20 , color21,  s);
     vec4 c3 = mix(c1 , c2,  t);
-    return vec4((c3.rgb)/(c3.rgb+1.0), 1.0);
+    return vec4(c3.rgb, 1.0);
 }
 
-#endif
+#endif

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

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