Kaynağa Gözat

Add `LUTImageLoader`. (#26880)

* Working on LUTImageLoader

* Added loading LUT directly from an Image

* Removed unused png thumbnail

* Used the make screenshot because test failed

* Restored package.json and package-lock.json

* restored package-lock.json

* Added to existing example

* Removed item in files.json

* Update LUTImageLoader.js

Code style improvements.

* Added blank line to match mrdoob style

* Removed left-over comments

* Added cross origin

* Default now flipY = false, inverted image strips

---------

Co-authored-by: Michael Herzog <[email protected]>
Nik Lever 1 yıl önce
ebeveyn
işleme
c9692eb810

+ 162 - 0
examples/jsm/loaders/LUTImageLoader.js

@@ -0,0 +1,162 @@
+import {
+	Loader,
+	TextureLoader,
+	DataTexture,
+	Data3DTexture,
+	RGBAFormat,
+	UnsignedByteType,
+	ClampToEdgeWrapping,
+	LinearFilter,
+} from 'three';
+
+export class LUTImageLoader extends Loader {
+
+	constructor( flipVertical = false ) {
+		//The NeutralLUT.png has green at the bottom for Unreal ang green at the top for Unity URP Color Lookup 
+		//post-processing. If you're using lut image strips from a Unity pipeline then pass true to the constructor
+		
+		super();
+
+		this.flip = flipVertical;
+
+	}
+
+	load( url, onLoad, onProgress, onError ) {
+
+		const loader = new TextureLoader( this.manager );
+
+		loader.setCrossOrigin( this.crossOrigin );
+
+		loader.setPath( this.path );
+		loader.load( url, texture => {
+
+			try {
+
+				let imageData;
+
+				if ( texture.image.width < texture.image.height ) {
+
+					imageData = this.getImageData( texture );
+
+				} else {
+
+					imageData = this.horz2Vert( texture );
+
+				}
+
+				onLoad( this.parse( imageData.data, Math.min( texture.image.width, texture.image.height ) ) );
+
+			} catch ( e ) {
+
+				if ( onError ) {
+
+					onError( e );
+
+				} else {
+
+					console.error( e );
+
+				}
+
+				this.manager.itemError( url );
+
+			}
+
+		}, onProgress, onError );
+
+	}
+
+	getImageData( texture ) {
+
+		const width = texture.image.width;
+		const height = texture.image.height;
+
+		const canvas = document.createElement( 'canvas' );
+		canvas.width = width;
+		canvas.height = height;
+
+		const context = canvas.getContext( '2d' );
+
+		if ( this.flip === true ) {
+
+			context.scale( 1, - 1 );
+			context.translate( 0, - height );
+
+		}
+
+		context.drawImage( texture.image, 0, 0 );
+
+		return context.getImageData( 0, 0, width, height );
+
+	}
+
+	horz2Vert( texture ) {
+
+		const width = texture.image.height;
+		const height = texture.image.width;
+
+		const canvas = document.createElement( 'canvas' );
+		canvas.width = width;
+		canvas.height = height;
+
+		const context = canvas.getContext( '2d' );
+
+		if ( this.flip === true ) {
+
+			context.scale( 1, - 1 );
+			context.translate( 0, - height );
+
+		}
+
+		for ( let i = 0; i < width; i ++ ) {
+
+			const sy = i * width;
+			const dy = ( this.flip ) ? height - i * width : i * width;
+			context.drawImage( texture.image, sy, 0, width, width, 0, dy, width, width );
+
+		}
+
+		return context.getImageData( 0, 0, width, height );
+
+	}
+
+	parse( dataArray, size ) {
+
+		const data = new Uint8Array( dataArray );
+		const texture = new DataTexture();
+		texture.image.data = data;
+		texture.image.width = size;
+		texture.image.height = size * size;
+		texture.format = RGBAFormat;
+		texture.type = UnsignedByteType;
+		texture.magFilter = LinearFilter;
+		texture.minFilter = LinearFilter;
+		texture.wrapS = ClampToEdgeWrapping;
+		texture.wrapT = ClampToEdgeWrapping;
+		texture.generateMipmaps = false;
+		texture.needsUpdate = true;
+
+		const texture3D = new Data3DTexture();
+		texture3D.image.data = data;
+		texture3D.image.width = size;
+		texture3D.image.height = size;
+		texture3D.image.depth = size;
+		texture3D.format = RGBAFormat;
+		texture3D.type = UnsignedByteType;
+		texture3D.magFilter = LinearFilter;
+		texture3D.minFilter = LinearFilter;
+		texture3D.wrapS = ClampToEdgeWrapping;
+		texture3D.wrapT = ClampToEdgeWrapping;
+		texture3D.wrapR = ClampToEdgeWrapping;
+		texture3D.generateMipmaps = false;
+		texture3D.needsUpdate = true;
+
+		return {
+			size,
+			texture,
+			texture3D,
+		};
+
+	}
+
+}

BIN
examples/luts/B&WLUT.png


BIN
examples/luts/NeutralLUT.png


BIN
examples/luts/NightLUT.png


+ 14 - 1
examples/webgl_postprocessing_3dlut.html

@@ -37,6 +37,7 @@
 			import { LUTPass } from 'three/addons/postprocessing/LUTPass.js';
 			import { LUTCubeLoader } from 'three/addons/loaders/LUTCubeLoader.js';
 			import { LUT3dlLoader } from 'three/addons/loaders/LUT3dlLoader.js';
+			import { LUTImageLoader } from 'three/addons/loaders/LUTImageLoader.js';
 			import { GUI } from 'three/addons/libs/lil-gui.module.min.js';
 
 			const params = {
@@ -52,7 +53,10 @@
 				'Clayton 33.CUBE': null,
 				'Cubicle 99.CUBE': null,
 				'Remy 24.CUBE': null,
-				'Presetpro-Cinematic.3dl': null
+				'Presetpro-Cinematic.3dl': null,
+				'NeutralLUT': null,
+				'B&WLUT': null,
+				'NightLUT': null
 			};
 
 			let gui;
@@ -103,6 +107,15 @@
 
 							} );
 
+					} else if ( /\LUT$/i.test( name ) ){
+						
+						new LUTImageLoader()
+							.load( `luts/${name}.png`, function ( result ) {
+
+								lutMap[ name ] = result;
+
+							} );
+					
 					} else {
 
 						new LUT3dlLoader()