|
|
@@ -1,5 +1,5 @@
|
|
|
import { HalfFloatType, RenderTarget, Vector2, Vector3, TempNode, QuadMesh, NodeMaterial, RendererUtils, NodeUpdateType } from 'three/webgpu';
|
|
|
-import { nodeObject, Fn, float, uv, passTexture, uniform, Loop, texture, luminance, smoothstep, mix, vec4, uniformArray, add, int } from 'three/tsl';
|
|
|
+import { nodeObject, Fn, float, uv, passTexture, uniform, Loop, texture, luminance, smoothstep, mix, vec4, uniformArray, add, int, array } from 'three/tsl';
|
|
|
|
|
|
const _quadMesh = /*@__PURE__*/ new QuadMesh();
|
|
|
const _size = /*@__PURE__*/ new Vector2();
|
|
|
@@ -106,6 +106,15 @@ class BloomNode extends TempNode {
|
|
|
*/
|
|
|
this.smoothWidth = uniform( 0.01 );
|
|
|
|
|
|
+ /**
|
|
|
+ * A per-mip tint color for the bloom, applied during the composite pass.
|
|
|
+ * Defaults to white (no tint) for each of the mips. Mutate the vectors to
|
|
|
+ * colorize the bloom (e.g. for a warm or anamorphic look).
|
|
|
+ *
|
|
|
+ * @type {Array<Vector3>}
|
|
|
+ */
|
|
|
+ this.bloomTintColors = [ new Vector3( 1, 1, 1 ), new Vector3( 1, 1, 1 ), new Vector3( 1, 1, 1 ), new Vector3( 1, 1, 1 ), new Vector3( 1, 1, 1 ) ];
|
|
|
+
|
|
|
/**
|
|
|
* Scale factor for the internal render targets.
|
|
|
*
|
|
|
@@ -420,23 +429,8 @@ class BloomNode extends TempNode {
|
|
|
|
|
|
// composite material
|
|
|
|
|
|
- const bloomFactors = uniformArray( [ 1.0, 0.8, 0.6, 0.4, 0.2 ] );
|
|
|
- const bloomTintColors = uniformArray( [ new Vector3( 1, 1, 1 ), new Vector3( 1, 1, 1 ), new Vector3( 1, 1, 1 ), new Vector3( 1, 1, 1 ), new Vector3( 1, 1, 1 ) ] );
|
|
|
-
|
|
|
- const lerpBloomFactor = Fn( ( [ factor, radius ] ) => {
|
|
|
-
|
|
|
- const mirrorFactor = float( 1.2 ).sub( factor );
|
|
|
- return mix( factor, mirrorFactor, radius );
|
|
|
-
|
|
|
- } ).setLayout( {
|
|
|
- name: 'lerpBloomFactor',
|
|
|
- type: 'float',
|
|
|
- inputs: [
|
|
|
- { name: 'factor', type: 'float' },
|
|
|
- { name: 'radius', type: 'float' },
|
|
|
- ]
|
|
|
- } );
|
|
|
-
|
|
|
+ const bloomFactors = array( [ float( 1.0 ), float( 0.8 ), float( 0.6 ), float( 0.4 ), float( 0.2 ) ] );
|
|
|
+ const bloomTintColors = uniformArray( this.bloomTintColors );
|
|
|
|
|
|
const compositePass = Fn( () => {
|
|
|
|
|
|
@@ -513,10 +507,28 @@ class BloomNode extends TempNode {
|
|
|
|
|
|
}
|
|
|
|
|
|
+ // Merge adjacent taps into single bilinear fetches (linear sampling).
|
|
|
+
|
|
|
+ const centerWeight = coefficients[ 0 ];
|
|
|
+ const offsets = [];
|
|
|
+ const weights = [];
|
|
|
+
|
|
|
+ for ( let i = 1; i < kernelRadius; i += 2 ) {
|
|
|
+
|
|
|
+ const wa = coefficients[ i ];
|
|
|
+ const wb = ( i + 1 ) < kernelRadius ? coefficients[ i + 1 ] : 0;
|
|
|
+ const w = wa + wb;
|
|
|
+
|
|
|
+ offsets.push( ( i * wa + ( i + 1 ) * wb ) / w );
|
|
|
+ weights.push( w );
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
//
|
|
|
|
|
|
const colorTexture = texture( null );
|
|
|
- const gaussianCoefficients = uniformArray( coefficients );
|
|
|
+ const gaussianOffsets = array( offsets.map( ( value ) => float( value ) ) );
|
|
|
+ const gaussianWeights = array( weights.map( ( value ) => float( value ) ) );
|
|
|
const invSize = uniform( new Vector2() );
|
|
|
const direction = uniform( new Vector2( 0.5, 0.5 ) );
|
|
|
|
|
|
@@ -525,13 +537,12 @@ class BloomNode extends TempNode {
|
|
|
|
|
|
const separableBlurPass = Fn( () => {
|
|
|
|
|
|
- const diffuseSum = sampleTexel( uvNode ).rgb.mul( gaussianCoefficients.element( 0 ) ).toVar();
|
|
|
+ const diffuseSum = sampleTexel( uvNode ).rgb.mul( centerWeight ).toVar();
|
|
|
|
|
|
- Loop( { start: int( 1 ), end: int( kernelRadius ), type: 'int', condition: '<' }, ( { i } ) => {
|
|
|
+ Loop( { start: int( 0 ), end: int( offsets.length ), type: 'int', condition: '<' }, ( { i } ) => {
|
|
|
|
|
|
- const x = float( i );
|
|
|
- const w = gaussianCoefficients.element( i );
|
|
|
- const uvOffset = direction.mul( invSize ).mul( x );
|
|
|
+ const w = gaussianWeights.element( i );
|
|
|
+ const uvOffset = direction.mul( invSize ).mul( gaussianOffsets.element( i ) );
|
|
|
const sample1 = sampleTexel( uvNode.add( uvOffset ) ).rgb;
|
|
|
const sample2 = sampleTexel( uvNode.sub( uvOffset ) ).rgb;
|
|
|
diffuseSum.addAssign( add( sample1, sample2 ).mul( w ) );
|
|
|
@@ -558,6 +569,20 @@ class BloomNode extends TempNode {
|
|
|
|
|
|
}
|
|
|
|
|
|
+const lerpBloomFactor = Fn( ( [ factor, radius ] ) => {
|
|
|
+
|
|
|
+ const mirrorFactor = float( 1.2 ).sub( factor );
|
|
|
+ return mix( factor, mirrorFactor, radius );
|
|
|
+
|
|
|
+} ).setLayout( {
|
|
|
+ name: 'lerpBloomFactor',
|
|
|
+ type: 'float',
|
|
|
+ inputs: [
|
|
|
+ { name: 'factor', type: 'float' },
|
|
|
+ { name: 'radius', type: 'float' },
|
|
|
+ ]
|
|
|
+} );
|
|
|
+
|
|
|
/**
|
|
|
* TSL function for creating a bloom effect.
|
|
|
*
|