Parcourir la source

EXRLoader: add RGBE - UnsignedByteType support

Guilherme Avila il y a 5 ans
Parent
commit
819b64a2eb

+ 82 - 6
examples/js/loaders/EXRLoader.js

@@ -117,6 +117,39 @@ THREE.EXRLoader.prototype = Object.assign( Object.create( THREE.DataTextureLoade
 
 		const logBase = Math.pow( 2.7182818, 2.2 );
 
+		function frexp( value ) {
+
+			if ( value === 0 ) return [ value, 0 ];
+
+			var data = new DataView( new ArrayBuffer( 8 ) );
+			data.setFloat64( 0, value );
+
+			var bits = ( data.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;
+
+			}
+			var exponent = bits - 1022;
+			var mantissa = ldexp( value, - exponent );
+
+			return [ mantissa, exponent ];
+
+		}
+
+		function ldexp( mantissa, exponent ) {
+
+			var steps = Math.min( 3, Math.ceil( Math.abs( exponent ) / 1023 ) );
+			var result = mantissa;
+
+			for ( var i = 0; i < steps; i ++ )
+				result *= Math.pow( 2, Math.floor( ( exponent + i ) / steps ) );
+
+			return result;
+
+		}
+
 		function reverseLutFromBitmap( bitmap, lut ) {
 
 			var k = 0;
@@ -1959,6 +1992,7 @@ THREE.EXRLoader.prototype = Object.assign( Object.create( THREE.DataTextureLoade
 
 			switch ( this.type ) {
 
+				case THREE.UnsignedByteType:
 				case THREE.FloatType:
 
 					getValue = parseFloat16;
@@ -1977,6 +2011,7 @@ THREE.EXRLoader.prototype = Object.assign( Object.create( THREE.DataTextureLoade
 
 			switch ( this.type ) {
 
+				case THREE.UnsignedByteType:
 				case THREE.FloatType:
 
 					getValue = parseFloat32;
@@ -2015,6 +2050,7 @@ THREE.EXRLoader.prototype = Object.assign( Object.create( THREE.DataTextureLoade
 		// Fill initially with 1s for the alpha value if the texture is not RGBA, RGB values will be overwritten
 		switch ( this.type ) {
 
+			case THREE.UnsignedByteType:
 			case THREE.FloatType:
 
 				var byteArray = new Float32Array( size );
@@ -2113,12 +2149,51 @@ THREE.EXRLoader.prototype = Object.assign( Object.create( THREE.DataTextureLoade
 
 		}
 
+		if ( this.type === THREE.UnsignedByteType ) {
+
+			let v;
+			const size = byteArray.length;
+			const RGBEArray = new Uint8Array( size );
+
+			for ( let i = 0; i < size; i += 4 ) {
+
+				const red = byteArray[ size - ( i + 4 ) ];
+				const green = byteArray[ size - ( i + 3 ) ];
+				const blue = byteArray[ size - ( i + 2 ) ];
+
+				v = ( red > green ) ? red : green;
+				v = ( blue > v ) ? blue : v;
+
+				if ( v < 1e-32 ) {
+
+					RGBEArray[ i ] = RGBEArray[ i + 1 ] = RGBEArray[ i + 2 ] = RGBEArray[ i + 3 ] = 0;
+
+				} else {
+
+					const res = frexp( v );
+					v = res[ 0 ] * 256 / v;
+
+					RGBEArray[ i ] = red * v;
+					RGBEArray[ i + 1 ] = green * v;
+					RGBEArray[ i + 2 ] = blue * v;
+					RGBEArray[ i + 3 ] = res[ 1 ] + 128;
+
+				}
+
+			}
+
+			byteArray = RGBEArray;
+
+		}
+
+		let format = ( this.type === THREE.UnsignedByteType ) ? THREE.RGBEFormat : ( numChannels === 4 ) ? THREE.RGBAFormat : THREE.RGBFormat;
+
 		return {
 			header: EXRHeader,
 			width: width,
 			height: height,
 			data: byteArray,
-			format: numChannels === 4 ? THREE.RGBAFormat : THREE.RGBFormat,
+			format: format,
 			type: this.type
 		};
 
@@ -2137,15 +2212,16 @@ THREE.EXRLoader.prototype = Object.assign( Object.create( THREE.DataTextureLoade
 
 			switch ( texture.type ) {
 
-				case THREE.FloatType:
+				case THREE.UnsignedByteType:
 
-					texture.encoding = THREE.LinearEncoding;
-					texture.minFilter = THREE.LinearFilter;
-					texture.magFilter = THREE.LinearFilter;
+					texture.encoding = THREE.RGBEEncoding;
+					texture.minFilter = THREE.NearestFilter;
+					texture.magFilter = THREE.NearestFilter;
 					texture.generateMipmaps = false;
-					texture.flipY = false;
+					texture.flipY = true;
 					break;
 
+				case THREE.FloatType:
 				case THREE.HalfFloatType:
 
 					texture.encoding = THREE.LinearEncoding;

+ 87 - 7
examples/jsm/loaders/EXRLoader.js

@@ -15,8 +15,12 @@ import {
 	HalfFloatType,
 	LinearEncoding,
 	LinearFilter,
+	NearestFilter,
 	RGBAFormat,
-	RGBFormat
+	RGBEEncoding,
+	RGBEFormat,
+	RGBFormat,
+	UnsignedByteType
 } from "../../../build/three.module.js";
 import { Zlib } from "../libs/inflate.module.min.js";
 
@@ -128,6 +132,39 @@ EXRLoader.prototype = Object.assign( Object.create( DataTextureLoader.prototype
 
 		const logBase = Math.pow( 2.7182818, 2.2 );
 
+		function frexp( value ) {
+
+			if ( value === 0 ) return [ value, 0 ];
+
+			var data = new DataView( new ArrayBuffer( 8 ) );
+			data.setFloat64( 0, value );
+
+			var bits = ( data.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;
+
+			}
+			var exponent = bits - 1022;
+			var mantissa = ldexp( value, - exponent );
+
+			return [ mantissa, exponent ];
+
+		}
+
+		function ldexp( mantissa, exponent ) {
+
+			var steps = Math.min( 3, Math.ceil( Math.abs( exponent ) / 1023 ) );
+			var result = mantissa;
+
+			for ( var i = 0; i < steps; i ++ )
+				result *= Math.pow( 2, Math.floor( ( exponent + i ) / steps ) );
+
+			return result;
+
+		}
+
 		function reverseLutFromBitmap( bitmap, lut ) {
 
 			var k = 0;
@@ -1970,6 +2007,7 @@ EXRLoader.prototype = Object.assign( Object.create( DataTextureLoader.prototype
 
 			switch ( this.type ) {
 
+				case UnsignedByteType:
 				case FloatType:
 
 					getValue = parseFloat16;
@@ -1988,6 +2026,7 @@ EXRLoader.prototype = Object.assign( Object.create( DataTextureLoader.prototype
 
 			switch ( this.type ) {
 
+				case UnsignedByteType:
 				case FloatType:
 
 					getValue = parseFloat32;
@@ -2026,6 +2065,7 @@ EXRLoader.prototype = Object.assign( Object.create( DataTextureLoader.prototype
 		// Fill initially with 1s for the alpha value if the texture is not RGBA, RGB values will be overwritten
 		switch ( this.type ) {
 
+			case UnsignedByteType:
 			case FloatType:
 
 				var byteArray = new Float32Array( size );
@@ -2124,12 +2164,51 @@ EXRLoader.prototype = Object.assign( Object.create( DataTextureLoader.prototype
 
 		}
 
+		if ( this.type === UnsignedByteType ) {
+
+			let v;
+			const size = byteArray.length;
+			const RGBEArray = new Uint8Array( size );
+
+			for ( let i = 0; i < size; i += 4 ) {
+
+				const red = byteArray[ size - ( i + 4 ) ];
+				const green = byteArray[ size - ( i + 3 ) ];
+				const blue = byteArray[ size - ( i + 2 ) ];
+
+				v = ( red > green ) ? red : green;
+				v = ( blue > v ) ? blue : v;
+
+				if ( v < 1e-32 ) {
+
+					RGBEArray[ i ] = RGBEArray[ i + 1 ] = RGBEArray[ i + 2 ] = RGBEArray[ i + 3 ] = 0;
+
+				} else {
+
+					const res = frexp( v );
+					v = res[ 0 ] * 256 / v;
+
+					RGBEArray[ i ] = red * v;
+					RGBEArray[ i + 1 ] = green * v;
+					RGBEArray[ i + 2 ] = blue * v;
+					RGBEArray[ i + 3 ] = res[ 1 ] + 128;
+
+				}
+
+			}
+
+			byteArray = RGBEArray;
+
+		}
+
+		let format = ( this.type === UnsignedByteType ) ? RGBEFormat : ( numChannels === 4 ) ? RGBAFormat : RGBFormat;
+
 		return {
 			header: EXRHeader,
 			width: width,
 			height: height,
 			data: byteArray,
-			format: numChannels === 4 ? RGBAFormat : RGBFormat,
+			format: format,
 			type: this.type
 		};
 
@@ -2148,15 +2227,16 @@ EXRLoader.prototype = Object.assign( Object.create( DataTextureLoader.prototype
 
 			switch ( texture.type ) {
 
-				case FloatType:
+				case UnsignedByteType:
 
-					texture.encoding = LinearEncoding;
-					texture.minFilter = LinearFilter;
-					texture.magFilter = LinearFilter;
+					texture.encoding = RGBEEncoding;
+					texture.minFilter = NearestFilter;
+					texture.magFilter = NearestFilter;
 					texture.generateMipmaps = false;
-					texture.flipY = false;
+					texture.flipY = true;
 					break;
 
+				case FloatType:
 				case HalfFloatType:
 
 					texture.encoding = LinearEncoding;

+ 1 - 1
examples/webgl_materials_envmaps_exr.html

@@ -78,7 +78,7 @@
 				};
 
 				new EXRLoader()
-					.setDataType( THREE.FloatType )
+					.setDataType( THREE.UnsignedByteType )
 					.load( 'textures/piz_compressed.exr', function ( texture ) {
 
 						exrCubeRenderTarget = pmremGenerator.fromEquirectangular( texture );