Преглед изворни кода

EXRLoader: Introduces output-format API (#31511)

* EXRLoader: introduces optional texture output format expansion

* EXRLoader: change API setOutputFormat
Guilherme Avila пре 5 месеци
родитељ
комит
0eb4c7a14e
1 измењених фајлова са 124 додато и 18 уклоњено
  1. 124 18
      examples/jsm/loaders/EXRLoader.js

+ 124 - 18
examples/jsm/loaders/EXRLoader.js

@@ -7,6 +7,7 @@ import {
 	LinearFilter,
 	LinearSRGBColorSpace,
 	RedFormat,
+	RGFormat,
 	RGBAFormat
 } from 'three';
 import * as fflate from '../libs/fflate.module.js';
@@ -113,6 +114,14 @@ class EXRLoader extends DataTextureLoader {
 		 */
 		this.type = HalfFloatType;
 
+		/**
+		 * Texture output format.
+		 *
+		 * @type {(RGBAFormat|RGFormat|RedFormat)}
+		 * @default RGBAFormat
+		 */
+		this.outputFormat = RGBAFormat;
+
 	}
 
 	/**
@@ -2374,7 +2383,7 @@ class EXRLoader extends DataTextureLoader {
 
 		}
 
-		function setupDecoder( EXRHeader, dataView, uInt8Array, offset, outputType ) {
+		function setupDecoder( EXRHeader, dataView, uInt8Array, offset, outputType, outputFormat ) {
 
 			const EXRDecoder = {
 				size: 0,
@@ -2385,6 +2394,7 @@ class EXRLoader extends DataTextureLoader {
 				height: EXRHeader.dataWindow.yMax - EXRHeader.dataWindow.yMin + 1,
 				inputChannels: EXRHeader.channels,
 				channelByteOffsets: {},
+				shouldExpand: false,
 				scanOrder: null,
 				totalBytes: null,
 				columns: null,
@@ -2462,17 +2472,16 @@ class EXRLoader extends DataTextureLoader {
 
 			// RGB images will be converted to RGBA format, preventing software emulation in select devices.
 			let fillAlpha = false;
+			let invalidOutput = false;
 
+			// Validate if input texture contain supported channels
 			if ( channels.R && channels.G && channels.B ) {
 
-				fillAlpha = ! channels.A;
 				EXRDecoder.outputChannels = 4;
-				EXRDecoder.decodeChannels = { R: 0, G: 1, B: 2, A: 3 };
 
 			} else if ( channels.Y ) {
 
 				EXRDecoder.outputChannels = 1;
-				EXRDecoder.decodeChannels = { Y: 0 };
 
 			} else {
 
@@ -2480,6 +2489,83 @@ class EXRLoader extends DataTextureLoader {
 
 			}
 
+			// Setup output texture configuration
+			switch ( EXRDecoder.outputChannels ) {
+
+				case 4:
+
+					if ( outputFormat == RGBAFormat ) {
+
+						fillAlpha = ! channels.A;
+						EXRDecoder.format = RGBAFormat;
+						EXRDecoder.colorSpace = LinearSRGBColorSpace;
+						EXRDecoder.outputChannels = 4;
+						EXRDecoder.decodeChannels = { R: 0, G: 1, B: 2, A: 3 };
+
+					} else if ( outputFormat == RGFormat ) {
+
+						EXRDecoder.format = RGFormat;
+						EXRDecoder.colorSpace = NoColorSpace;
+						EXRDecoder.outputChannels = 2;
+						EXRDecoder.decodeChannels = { R: 0, G: 1 };
+
+					} else if ( outputFormat == RedFormat ) {
+
+						EXRDecoder.format = RedFormat;
+						EXRDecoder.colorSpace = NoColorSpace;
+						EXRDecoder.outputChannels = 1;
+						EXRDecoder.decodeChannels = { R: 0 };
+
+					} else  {
+
+						invalidOutput = true;
+
+					}
+
+					break;
+
+				case 1:
+
+					if ( outputFormat == RGBAFormat ) {
+
+						fillAlpha = true;
+						EXRDecoder.format = RGBAFormat;
+						EXRDecoder.colorSpace = LinearSRGBColorSpace;
+						EXRDecoder.outputChannels = 4;
+						EXRDecoder.shouldExpand = true;
+						EXRDecoder.decodeChannels = { Y: 0 };
+
+					} else if ( outputFormat == RGFormat ) {
+
+						EXRDecoder.format = RGFormat;
+						EXRDecoder.colorSpace = NoColorSpace;
+						EXRDecoder.outputChannels = 2;
+						EXRDecoder.shouldExpand = true;
+						EXRDecoder.decodeChannels = { Y: 0 };
+
+					} else if ( outputFormat == RedFormat ) {
+
+						EXRDecoder.format = RedFormat;
+						EXRDecoder.colorSpace = NoColorSpace;
+						EXRDecoder.outputChannels = 1;
+						EXRDecoder.decodeChannels = { Y: 0 };
+
+					} else  {
+
+						invalidOutput = true;
+
+					}
+
+					break;
+
+				default:
+
+					invalidOutput = true;
+
+			}
+
+			if (invalidOutput) throw new Error( 'EXRLoader.parse: invalid output format for specified file.' );
+
 			if ( EXRDecoder.type == 1 ) {
 
 				// half
@@ -2569,18 +2655,6 @@ class EXRLoader extends DataTextureLoader {
 
 			}
 
-			if ( EXRDecoder.outputChannels == 4 ) {
-
-				EXRDecoder.format = RGBAFormat;
-				EXRDecoder.colorSpace = LinearSRGBColorSpace;
-
-			} else {
-
-				EXRDecoder.format = RedFormat;
-				EXRDecoder.colorSpace = NoColorSpace;
-
-			}
-
 			if ( EXRHeader.spec.singleTile ) {
 
 				EXRDecoder.blockHeight = EXRHeader.tiles.ySize;
@@ -2626,11 +2700,30 @@ class EXRLoader extends DataTextureLoader {
 		const EXRHeader = parseHeader( bufferDataView, buffer, offset );
 
 		// get input compression information and prepare decoding.
-		const EXRDecoder = setupDecoder( EXRHeader, bufferDataView, uInt8Array, offset, this.type );
+		const EXRDecoder = setupDecoder( EXRHeader, bufferDataView, uInt8Array, offset, this.type, this.outputFormat );
 
 		// parse input data
 		EXRDecoder.decode();
 
+		// output texture post-processing
+		if ( EXRDecoder.shouldExpand ) {
+
+			const byteArray = EXRDecoder.byteArray;
+
+			if ( this.outputFormat == RGBAFormat ) {
+
+				for ( let i = 0; i < byteArray.length; i += 4 )
+					byteArray [i + 2 ] = ( byteArray [ i + 1 ] = byteArray[ i ] );
+
+			} else if ( this.outputFormat == RGFormat ) {
+
+				for ( let i = 0; i < byteArray.length; i += 2 )
+					byteArray [ i + 1 ] = byteArray[ i ] ;
+
+			}
+
+		}
+
 		return {
 			header: EXRHeader,
 			width: EXRDecoder.width,
@@ -2647,7 +2740,7 @@ class EXRLoader extends DataTextureLoader {
 	 * Sets the texture type.
 	 *
 	 * @param {(HalfFloatType|FloatType)} value - The texture type to set.
-	 * @return {RGBMLoader} A reference to this loader.
+	 * @return {EXRLoader} A reference to this loader.
 	 */
 	setDataType( value ) {
 
@@ -2656,6 +2749,19 @@ class EXRLoader extends DataTextureLoader {
 
 	}
 
+	/**
+	 * Sets texture output format. Defaults to `RGBAFormat`.
+	 *
+	 * @param {(RGBAFormat|RGFormat|RedFormat)} value - Texture output format.
+	 * @return {EXRLoader} A reference to this loader.
+	 */
+	setOutputFormat( value ) {
+
+		this.outputFormat = value;
+		return this;
+
+	}
+
 	load( url, onLoad, onProgress, onError ) {
 
 		function onLoadCallback( texture, texData ) {

粤ICP备19079148号