File size: 2,661 Bytes
a28eca3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
import { TempNode } from 'three/webgpu';
import { nodeObject, Fn, float, uniform, vec3, vec4, mix } from 'three/tsl';

/** @module Lut3DNode **/

/**
 * A post processing node for color grading via lookup tables.
 *
 * @augments TempNode
 */
class Lut3DNode extends TempNode {

	static get type() {

		return 'Lut3DNode';

	}

	/**
	 * Constructs a new LUT node.
	 *
	 * @param {Node} inputNode - The node that represents the input of the effect.
	 * @param {TextureNode} lutNode - A texture node that represents the lookup table.
	 * @param {Number} size - The size of the lookup table.
	 * @param {Node<float>} intensityNode - Controls the intensity of the effect.
	 */
	constructor( inputNode, lutNode, size, intensityNode ) {

		super( 'vec4' );

		/**
		 * The node that represents the input of the effect.
		 *
		 * @type {Node}
		 */
		this.inputNode = inputNode;

		/**
		 * A texture node that represents the lookup table.
		 *
		 * @type {TextureNode}
		 */
		this.lutNode = lutNode;

		/**
		 * The size of the lookup table.
		 *
		 * @type {UniformNode<float>}
		 */
		this.size = uniform( size );

		/**
		 * Controls the intensity of the effect.
		 *
		 * @type {Node<float>}
		 */
		this.intensityNode = intensityNode;

	}

	/**
	 * This method is used to setup the effect's TSL code.
	 *
	 * @param {NodeBuilder} builder - The current node builder.
	 * @return {ShaderCallNodeInternal}
	 */
	setup() {

		const { inputNode, lutNode } = this;

		const sampleLut = ( uv ) => lutNode.sample( uv );

		const lut3D = Fn( () => {

			const base = inputNode;

			// pull the sample in by half a pixel so the sample begins at the center of the edge pixels.

			const pixelWidth = float( 1.0 ).div( this.size );
			const halfPixelWidth = float( 0.5 ).div( this.size );
			const uvw = vec3( halfPixelWidth ).add( base.rgb.mul( float( 1.0 ).sub( pixelWidth ) ) );

			const lutValue = vec4( sampleLut( uvw ).rgb, base.a );

			return vec4( mix( base, lutValue, this.intensityNode ) );

		} );

		const outputNode = lut3D();

		return outputNode;

	}

}

export default Lut3DNode;

/**
 * TSL function for creating a LUT node for color grading via post processing.
 *
 * @function
 * @param {Node} node - The node that represents the input of the effect.
 * @param {TextureNode} lut - A texture node that represents the lookup table.
 * @param {Number} size - The size of the lookup table.
 * @param {Node<float> | Number} intensity - Controls the intensity of the effect.
 * @returns {Lut3DNode}
 */
export const lut3D = ( node, lut, size, intensity ) => nodeObject( new Lut3DNode( nodeObject( node ), nodeObject( lut ), size, nodeObject( intensity ) ) );