Bläddra i källkod

Merge pull request #19111 from sciecode/dev-exrloader-half

EXRLoader: add support HalfFloat texture from Float image
Mr.doob 5 år sedan
förälder
incheckning
4265cb31d7
2 ändrade filer med 96 tillägg och 92 borttagningar
  1. 48 46
      examples/js/loaders/EXRLoader.js
  2. 48 46
      examples/jsm/loaders/EXRLoader.js

+ 48 - 46
examples/js/loaders/EXRLoader.js

@@ -117,18 +117,19 @@ THREE.EXRLoader.prototype = Object.assign( Object.create( THREE.DataTextureLoade
 
 		const logBase = Math.pow( 2.7182818, 2.2 );
 
+		var tmpDataView = new DataView( new ArrayBuffer( 8 ) );
+
 		function frexp( value ) {
 
 			if ( value === 0 ) return [ value, 0 ];
 
-			var data = new DataView( new ArrayBuffer( 8 ) );
-			data.setFloat64( 0, value );
+			tmpDataView.setFloat64( 0, value );
 
-			var bits = ( data.getUint32( 0 ) >>> 20 ) & 0x7FF;
+			var bits = ( tmpDataView.getUint32( 0 ) >>> 20 ) & 0x7FF;
 			if ( bits === 0 ) { // denormal
 
-				data.setFloat64( 0, value * Math.pow( 2, 64 ) ); // exp + 64
-				bits = ( ( data.getUint32( 0 ) >>> 20 ) & 0x7FF ) - 64;
+				tmpDataView.setFloat64( 0, value * Math.pow( 2, 64 ) ); // exp + 64
+				bits = ( ( tmpDataView.getUint32( 0 ) >>> 20 ) & 0x7FF ) - 64;
 
 			}
 			var exponent = bits - 1022;
@@ -1686,6 +1687,12 @@ THREE.EXRLoader.prototype = Object.assign( Object.create( THREE.DataTextureLoade
 
 		}
 
+		function decodeFloat32( dataView, offset ) {
+
+			return encodeFloat16( parseFloat32( dataView, offset ) );
+
+		}
+
 		// https://stackoverflow.com/questions/5678432/decompressing-half-precision-floats-in-javascript
 		function decodeFloat16( binary ) {
 
@@ -1704,60 +1711,54 @@ THREE.EXRLoader.prototype = Object.assign( Object.create( THREE.DataTextureLoade
 
 		}
 
-		var encodeFloat16 = ( function () {
-
-			// Source: http://gamedev.stackexchange.com/questions/17326/conversion-of-a-number-from-single-precision-floating-point-representation-to-a/17410#17410
-
-			var floatView = new Float32Array( 1 );
-			var int32View = new Int32Array( floatView.buffer );
+		// http://gamedev.stackexchange.com/questions/17326/conversion-of-a-number-from-single-precision-floating-point-representation-to-a/17410#17410
+		function encodeFloat16( val ) {
 
 			/* 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 */
+			 * by James Tursa?s half-precision code.
+			*/
 
-				/* If zero, or denormal, or exponent underflows too much for a denormal
-				 * half, return signed zero. */
-				if ( e < 103 ) return bits;
+			tmpDataView.setFloat32( 0, val );
+			var x = tmpDataView.getInt32( 0 );
 
-				/* If NaN, return NaN. If Inf or exponent overflow, return Inf. */
-				if ( e > 142 ) {
+			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 */
 
-					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 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 ) {
 
-				/* If exponent underflows but not too much, return a denormal */
-				if ( e < 113 ) {
+				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;
 
-					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;
+			}
 
-				}
+			/* If exponent underflows but not too much, return a denormal */
+			if ( e < 113 ) {
 
-				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;
+				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;
 
-		} )();
+		}
 
 		function parseUint16( dataView, offset ) {
 
@@ -2056,7 +2057,8 @@ THREE.EXRLoader.prototype = Object.assign( Object.create( THREE.DataTextureLoade
 
 				case THREE.HalfFloatType:
 
-					throw 'EXRLoader.parse: unsupported HalfFloatType texture for FloatType image file.';
+					getValue = decodeFloat32;
+					size_t = FLOAT32_SIZE;
 
 			}
 

+ 48 - 46
examples/jsm/loaders/EXRLoader.js

@@ -132,18 +132,19 @@ EXRLoader.prototype = Object.assign( Object.create( DataTextureLoader.prototype
 
 		const logBase = Math.pow( 2.7182818, 2.2 );
 
+		var tmpDataView = new DataView( new ArrayBuffer( 8 ) );
+
 		function frexp( value ) {
 
 			if ( value === 0 ) return [ value, 0 ];
 
-			var data = new DataView( new ArrayBuffer( 8 ) );
-			data.setFloat64( 0, value );
+			tmpDataView.setFloat64( 0, value );
 
-			var bits = ( data.getUint32( 0 ) >>> 20 ) & 0x7FF;
+			var bits = ( tmpDataView.getUint32( 0 ) >>> 20 ) & 0x7FF;
 			if ( bits === 0 ) { // denormal
 
-				data.setFloat64( 0, value * Math.pow( 2, 64 ) ); // exp + 64
-				bits = ( ( data.getUint32( 0 ) >>> 20 ) & 0x7FF ) - 64;
+				tmpDataView.setFloat64( 0, value * Math.pow( 2, 64 ) ); // exp + 64
+				bits = ( ( tmpDataView.getUint32( 0 ) >>> 20 ) & 0x7FF ) - 64;
 
 			}
 			var exponent = bits - 1022;
@@ -1701,6 +1702,12 @@ EXRLoader.prototype = Object.assign( Object.create( DataTextureLoader.prototype
 
 		}
 
+		function decodeFloat32( dataView, offset ) {
+
+			return encodeFloat16( parseFloat32( dataView, offset ) );
+
+		}
+
 		// https://stackoverflow.com/questions/5678432/decompressing-half-precision-floats-in-javascript
 		function decodeFloat16( binary ) {
 
@@ -1719,60 +1726,54 @@ EXRLoader.prototype = Object.assign( Object.create( DataTextureLoader.prototype
 
 		}
 
-		var encodeFloat16 = ( function () {
-
-			// Source: http://gamedev.stackexchange.com/questions/17326/conversion-of-a-number-from-single-precision-floating-point-representation-to-a/17410#17410
-
-			var floatView = new Float32Array( 1 );
-			var int32View = new Int32Array( floatView.buffer );
+		// http://gamedev.stackexchange.com/questions/17326/conversion-of-a-number-from-single-precision-floating-point-representation-to-a/17410#17410
+		function encodeFloat16( val ) {
 
 			/* 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 */
+			 * by James Tursa?s half-precision code.
+			*/
 
-				/* If zero, or denormal, or exponent underflows too much for a denormal
-				 * half, return signed zero. */
-				if ( e < 103 ) return bits;
+			tmpDataView.setFloat32( 0, val );
+			var x = tmpDataView.getInt32( 0 );
 
-				/* If NaN, return NaN. If Inf or exponent overflow, return Inf. */
-				if ( e > 142 ) {
+			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 */
 
-					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 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 ) {
 
-				/* If exponent underflows but not too much, return a denormal */
-				if ( e < 113 ) {
+				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;
 
-					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;
+			}
 
-				}
+			/* If exponent underflows but not too much, return a denormal */
+			if ( e < 113 ) {
 
-				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;
+				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;
 
-		} )();
+		}
 
 		function parseUint16( dataView, offset ) {
 
@@ -2071,7 +2072,8 @@ EXRLoader.prototype = Object.assign( Object.create( DataTextureLoader.prototype
 
 				case HalfFloatType:
 
-					throw 'EXRLoader.parse: unsupported HalfFloatType texture for FloatType image file.';
+					getValue = decodeFloat32;
+					size_t = FLOAT32_SIZE;
 
 			}