瀏覽代碼

Updated RGBELoader module.

Mr.doob 6 年之前
父節點
當前提交
a97975569b
共有 1 個文件被更改,包括 120 次插入25 次删除
  1. 120 25
      examples/jsm/loaders/RGBELoader.js

+ 120 - 25
examples/jsm/loaders/RGBELoader.js

@@ -6,6 +6,7 @@ import {
 	DataTextureLoader,
 	DefaultLoadingManager,
 	FloatType,
+	HalfFloatType,
 	LinearEncoding,
 	LinearFilter,
 	NearestFilter,
@@ -326,8 +327,84 @@ RGBELoader.prototype._parser = function ( buffer ) {
 
 			return data_rgba;
 
+		};
+
+	var 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;
+
+	};
+
+	var RGBEByteToRGBHalf = ( 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 );
+
+		/* 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. */
+		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;
+
 		}
-	;
+
+		return function ( sourceArray, sourceOffset, destArray, destOffset ) {
+
+			var e = sourceArray[ sourceOffset + 3 ];
+			var scale = Math.pow( 2.0, e - 128.0 ) / 255.0;
+
+			destArray[ destOffset + 0 ] = toHalf( sourceArray[ sourceOffset + 0 ] * scale );
+			destArray[ destOffset + 1 ] = toHalf( sourceArray[ sourceOffset + 1 ] * scale );
+			destArray[ destOffset + 2 ] = toHalf( sourceArray[ sourceOffset + 2 ] * scale );
+
+		};
+
+	} )();
 
 	var byteArray = new Uint8Array( buffer );
 	byteArray.pos = 0;
@@ -337,46 +414,55 @@ RGBELoader.prototype._parser = function ( buffer ) {
 
 		var w = rgbe_header_info.width,
 			h = rgbe_header_info.height,
-			image_rgba_data = RGBE_ReadPixels_RLE( byteArray.subarray( byteArray.pos ), w, h )
-		;
+			image_rgba_data = RGBE_ReadPixels_RLE( byteArray.subarray( byteArray.pos ), w, h );
+
 		if ( RGBE_RETURN_FAILURE !== image_rgba_data ) {
 
-			if ( this.type === UnsignedByteType ) {
+			switch ( this.type ) {
 
-				var data = image_rgba_data;
-				var format = RGBEFormat; // handled as THREE.RGBAFormat in shaders
-				var type = UnsignedByteType;
+				case UnsignedByteType:
 
-			} else if ( this.type === FloatType ) {
+					var data = image_rgba_data;
+					var format = RGBEFormat; // handled as THREE.RGBAFormat in shaders
+					var type = UnsignedByteType;
+					break;
 
-				var RGBEByteToRGBFloat = function ( sourceArray, sourceOffset, destArray, destOffset ) {
+				case FloatType:
 
-					var e = sourceArray[ sourceOffset + 3 ];
-					var scale = Math.pow( 2.0, e - 128.0 ) / 255.0;
+					var numElements = ( image_rgba_data.length / 4 ) * 3;
+					var floatArray = new Float32Array( numElements );
 
-					destArray[ destOffset + 0 ] = sourceArray[ sourceOffset + 0 ] * scale;
-					destArray[ destOffset + 1 ] = sourceArray[ sourceOffset + 1 ] * scale;
-					destArray[ destOffset + 2 ] = sourceArray[ sourceOffset + 2 ] * scale;
+					for ( var j = 0; j < numElements; j ++ ) {
 
-				};
+						RGBEByteToRGBFloat( image_rgba_data, j * 4, floatArray, j * 3 );
 
-				var numElements = ( image_rgba_data.length / 4 ) * 3;
-				var floatArray = new Float32Array( numElements );
+					}
 
-				for ( var j = 0; j < numElements; j ++ ) {
+					var data = floatArray;
+					var format = RGBFormat;
+					var type = FloatType;
+					break;
 
-					RGBEByteToRGBFloat( image_rgba_data, j * 4, floatArray, j * 3 );
+				case HalfFloatType:
 
-				}
+					var numElements = ( image_rgba_data.length / 4 ) * 3;
+					var halfArray = new Uint16Array( numElements );
 
-				var data = floatArray;
-				var format = RGBFormat;
-				var type = FloatType;
+					for ( var j = 0; j < numElements; j ++ ) {
 
+						RGBEByteToRGBHalf( image_rgba_data, j * 4, halfArray, j * 3 );
 
-			} else {
+					}
 
-				console.error( 'THREE.RGBELoader: unsupported type: ', this.type );
+					var data = halfArray;
+					var format = RGBFormat;
+					var type = HalfFloatType;
+					break;
+
+				default:
+
+					console.error( 'THREE.RGBELoader: unsupported type: ', this.type );
+					break;
 
 			}
 
@@ -429,6 +515,15 @@ RGBELoader.prototype.load = function ( url, onLoad, onProgress, onError ) {
 				texture.flipY = true;
 				break;
 
+			case HalfFloatType:
+
+				texture.encoding = LinearEncoding;
+				texture.minFilter = LinearFilter;
+				texture.magFilter = LinearFilter;
+				texture.generateMipmaps = false;
+				texture.flipY = true;
+				break;
+
 		}
 
 		if ( onLoad ) onLoad( texture, texData );