diff --git a/src/nodes/display/ColorAdjustment.js b/src/nodes/display/ColorAdjustment.js index b01c5426be3276..8c0c2ab09ca121 100644 --- a/src/nodes/display/ColorAdjustment.js +++ b/src/nodes/display/ColorAdjustment.js @@ -11,8 +11,8 @@ import { LinearSRGBColorSpace } from '../../constants.js'; * Computes a grayscale value for the given RGB color value. * * @method - * @param {vec3} color - The color value to compute the grayscale for. - * @return {vec3} The grayscale color. + * @param {Node} color - The color value to compute the grayscale for. + * @return {Node} The grayscale color. */ export const grayscale = /*@__PURE__*/ Fn( ( [ color ] ) => { @@ -24,9 +24,9 @@ export const grayscale = /*@__PURE__*/ Fn( ( [ color ] ) => { * Super-saturates or desaturates the given RGB color. * * @method - * @param {vec3} color - The input color. - * @param {float} [adjustment=1] - Specifies the amount of the conversion. A value under `1` desaturates the color, a value over `1` super-saturates it. - * @return {vec3} The saturated color. + * @param {Node} color - The input color. + * @param {Node} [adjustment=1] - Specifies the amount of the conversion. A value under `1` desaturates the color, a value over `1` super-saturates it. + * @return {Node} The saturated color. */ export const saturation = /*@__PURE__*/ Fn( ( [ color, adjustment = float( 1 ) ] ) => { @@ -40,9 +40,9 @@ export const saturation = /*@__PURE__*/ Fn( ( [ color, adjustment = float( 1 ) ] * compared to {@link ColorAdjustment#saturation}. * * @method - * @param {vec3} color - The input color. - * @param {float} [adjustment=1] - Controls the intensity of the vibrance effect. - * @return {vec3} The updated color. + * @param {Node} color - The input color. + * @param {Node} [adjustment=1] - Controls the intensity of the vibrance effect. + * @return {Node} The updated color. */ export const vibrance = /*@__PURE__*/ Fn( ( [ color, adjustment = float( 1 ) ] ) => { @@ -59,9 +59,9 @@ export const vibrance = /*@__PURE__*/ Fn( ( [ color, adjustment = float( 1 ) ] ) * Updates the hue component of the given RGB color while preserving its luminance and saturation. * * @method - * @param {vec3} color - The input color. - * @param {float} [adjustment=1] - Defines the degree of hue rotation in radians. A positive value rotates the hue clockwise, while a negative value rotates it counterclockwise. - * @return {vec3} The updated color. + * @param {Node} color - The input color. + * @param {Node} [adjustment=1] - Defines the degree of hue rotation in radians. A positive value rotates the hue clockwise, while a negative value rotates it counterclockwise. + * @return {Node} The updated color. */ export const hue = /*@__PURE__*/ Fn( ( [ color, adjustment = float( 1 ) ] ) => { @@ -77,9 +77,9 @@ export const hue = /*@__PURE__*/ Fn( ( [ color, adjustment = float( 1 ) ] ) => { * Computes the luminance for the given RGB color value. * * @method - * @param {vec3} color - The color value to compute the luminance for. - * @param {vec3?} luminanceCoefficients - The luminance coefficients. By default predefined values of the current working color space are used. - * @return {vec3} The luminance. + * @param {Node} color - The color value to compute the luminance for. + * @param {Node?} luminanceCoefficients - The luminance coefficients. By default predefined values of the current working color space are used. + * @return {Node} The luminance. */ export const luminance = ( color, @@ -94,13 +94,13 @@ export const luminance = ( * or AgX Log), and will return output in the same space. Output may require clamping >=0. * * @method - * @param {vec4} color Input (-Infinity < input < +Infinity) - * @param {number | vec3} slope Slope (0 ≤ slope < +Infinity) - * @param {number | vec3} offset Offset (-Infinity < offset < +Infinity; typically -1 < offset < 1) - * @param {number | vec3} power Power (0 < power < +Infinity) - * @param {number} saturation Saturation (0 ≤ saturation < +Infinity; typically 0 ≤ saturation < 4) - * @param {vec3} luminanceCoefficients Luminance coefficients for saturation term, typically Rec. 709 - * @return Output, -Infinity < output < +Infinity + * @param {Node} color Input (-Infinity < input < +Infinity) + * @param {Node} slope Slope (0 ≤ slope < +Infinity) + * @param {Node} offset Offset (-Infinity < offset < +Infinity; typically -1 < offset < 1) + * @param {Node} power Power (0 < power < +Infinity) + * @param {Node} saturation Saturation (0 ≤ saturation < +Infinity; typically 0 ≤ saturation < 4) + * @param {Node} luminanceCoefficients Luminance coefficients for saturation term, typically Rec. 709 + * @return {Node} Output, -Infinity < output < +Infinity * * References: * - ASC CDL v1.2 diff --git a/src/nodes/display/ColorSpaceFunctions.js b/src/nodes/display/ColorSpaceFunctions.js index 85c5dfe19db928..32f76e610228a2 100644 --- a/src/nodes/display/ColorSpaceFunctions.js +++ b/src/nodes/display/ColorSpaceFunctions.js @@ -7,8 +7,8 @@ import { Fn } from '../tsl/TSLCore.js'; * Converts the given color value from sRGB to linear-sRGB color space. * * @method - * @param {vec3} color - The sRGB color. - * @return {vec3} The linear-sRGB color. + * @param {Node} color - The sRGB color. + * @return {Node} The linear-sRGB color. */ export const sRGBTransferEOTF = /*@__PURE__*/ Fn( ( [ color ] ) => { @@ -32,8 +32,8 @@ export const sRGBTransferEOTF = /*@__PURE__*/ Fn( ( [ color ] ) => { * Converts the given color value from linear-sRGB to sRGB color space. * * @method - * @param {vec3} color - The linear-sRGB color. - * @return {vec3} The sRGB color. + * @param {Node} color - The linear-sRGB color. + * @return {Node} The sRGB color. */ export const sRGBTransferOETF = /*@__PURE__*/ Fn( ( [ color ] ) => { diff --git a/src/nodes/display/ToneMappingFunctions.js b/src/nodes/display/ToneMappingFunctions.js index fc445b44474d26..f1ed48a828b712 100644 --- a/src/nodes/display/ToneMappingFunctions.js +++ b/src/nodes/display/ToneMappingFunctions.js @@ -9,9 +9,9 @@ import { mul, sub, div } from '../math/OperatorNode.js'; * Linear tone mapping, exposure only. * * @method - * @param {vec3} color - The color that should be tone mapped. - * @param {float} exposure - The exposure. - * @return {vec3} The tone mapped color. + * @param {Node} color - The color that should be tone mapped. + * @param {Node} exposure - The exposure. + * @return {Node} The tone mapped color. */ export const linearToneMapping = /*@__PURE__*/ Fn( ( [ color, exposure ] ) => { @@ -32,9 +32,9 @@ export const linearToneMapping = /*@__PURE__*/ Fn( ( [ color, exposure ] ) => { * Reference: {@link https://www.cs.utah.edu/docs/techreports/2002/pdf/UUCS-02-001.pdf} * * @method - * @param {vec3} color - The color that should be tone mapped. - * @param {float} exposure - The exposure. - * @return {vec3} The tone mapped color. + * @param {Node} color - The color that should be tone mapped. + * @param {Node} exposure - The exposure. + * @return {Node} The tone mapped color. */ export const reinhardToneMapping = /*@__PURE__*/ Fn( ( [ color, exposure ] ) => { @@ -57,9 +57,9 @@ export const reinhardToneMapping = /*@__PURE__*/ Fn( ( [ color, exposure ] ) => * Reference: {@link http://filmicworlds.com/blog/filmic-tonemapping-operators/} * * @method - * @param {vec3} color - The color that should be tone mapped. - * @param {float} exposure - The exposure. - * @return {vec3} The tone mapped color. + * @param {Node} color - The color that should be tone mapped. + * @param {Node} exposure - The exposure. + * @return {Node} The tone mapped color. */ export const cineonToneMapping = /*@__PURE__*/ Fn( ( [ color, exposure ] ) => { @@ -98,9 +98,9 @@ const RRTAndODTFit = /*@__PURE__*/ Fn( ( [ color ] ) => { * Reference: {@link https://github.com/selfshadow/ltc_code/blob/master/webgl/shaders/ltc/ltc_blit.fs} * * @method - * @param {vec3} color - The color that should be tone mapped. - * @param {float} exposure - The exposure. - * @return {vec3} The tone mapped color. + * @param {Node} color - The color that should be tone mapped. + * @param {Node} exposure - The exposure. + * @return {Node} The tone mapped color. */ export const acesFilmicToneMapping = /*@__PURE__*/ Fn( ( [ color, exposure ] ) => { @@ -156,9 +156,9 @@ const agxDefaultContrastApprox = /*@__PURE__*/ Fn( ( [ x_immutable ] ) => { * AgX tone mapping. * * @method - * @param {vec3} color - The color that should be tone mapped. - * @param {float} exposure - The exposure. - * @return {vec3} The tone mapped color. + * @param {Node} color - The color that should be tone mapped. + * @param {Node} exposure - The exposure. + * @return {Node} The tone mapped color. */ export const agxToneMapping = /*@__PURE__*/ Fn( ( [ color, exposure ] ) => { @@ -197,9 +197,9 @@ export const agxToneMapping = /*@__PURE__*/ Fn( ( [ color, exposure ] ) => { * Reference: {@link https://modelviewer.dev/examples/tone-mapping} * * @method - * @param {vec3} color - The color that should be tone mapped. - * @param {float} exposure - The exposure. - * @return {vec3} The tone mapped color. + * @param {Node} color - The color that should be tone mapped. + * @param {Node} exposure - The exposure. + * @return {Node} The tone mapped color. */ export const neutralToneMapping = /*@__PURE__*/ Fn( ( [ color, exposure ] ) => { diff --git a/src/nodes/geometry/RangeNode.js b/src/nodes/geometry/RangeNode.js index 6b93a04d564eea..a3786116de83ac 100644 --- a/src/nodes/geometry/RangeNode.js +++ b/src/nodes/geometry/RangeNode.js @@ -12,6 +12,17 @@ import { InstancedBufferAttribute } from '../../core/InstancedBufferAttribute.js let min = null; let max = null; +/** + * `RangeNode` generates random instanced attribute data in a defined range. + * An exemplary use case for this utility node is to generate random per-instance + * colors: + * ```js + * const material = new MeshBasicNodeMaterial(); + * material.colorNode = range( new Color( 0x000000 ), new Color( 0xFFFFFF ) ); + * const mesh = new InstancedMesh( geometry, material, count ); + * ``` + * @augments Node + */ class RangeNode extends Node { static get type() { @@ -20,15 +31,39 @@ class RangeNode extends Node { } + /** + * Constructs a new range node. + * + * @param {Node} [minNode=float()] - A node defining the lower bound of the range. + * @param {Node} [maxNode=float()] - A node defining the upper bound of the range. + */ constructor( minNode = float(), maxNode = float() ) { super(); + /** + * A node defining the lower bound of the range. + * + * @type {Node} + * @default float() + */ this.minNode = minNode; + + /** + * A node defining the upper bound of the range. + * + * @type {Node} + * @default float() + */ this.maxNode = maxNode; } + /** + * Returns the vector length which is computed based on the range definition. + * + * @return {Number} The vector length. + */ getVectorLength( builder ) { const minLength = builder.getTypeLength( getValueType( this.minNode.value ) ); @@ -38,6 +73,12 @@ class RangeNode extends Node { } + /** + * This method is overwritten since the node type is inferred from range definition. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {String} The node type. + */ getNodeType( builder ) { return builder.object.count > 1 ? builder.getTypeFromLength( this.getVectorLength( builder ) ) : 'float'; @@ -65,11 +106,11 @@ class RangeNode extends Node { max.setScalar( 0 ); if ( minLength === 1 ) min.setScalar( minValue ); - else if ( minValue.isColor ) min.set( minValue.r, minValue.g, minValue.b ); + else if ( minValue.isColor ) min.set( minValue.r, minValue.g, minValue.b, 1 ); else min.set( minValue.x, minValue.y, minValue.z || 0, minValue.w || 0 ); if ( maxLength === 1 ) max.setScalar( maxValue ); - else if ( maxValue.isColor ) max.set( maxValue.r, maxValue.g, maxValue.b ); + else if ( maxValue.isColor ) max.set( maxValue.r, maxValue.g, maxValue.b, 1 ); else max.set( maxValue.x, maxValue.y, maxValue.z || 0, maxValue.w || 0 ); const stride = 4; diff --git a/src/nodes/math/ConditionalNode.js b/src/nodes/math/ConditionalNode.js index 6b312b63869cfc..9566308a2af3c9 100644 --- a/src/nodes/math/ConditionalNode.js +++ b/src/nodes/math/ConditionalNode.js @@ -2,6 +2,19 @@ import Node from '../core/Node.js'; import { property } from '../core/PropertyNode.js'; import { addMethodChaining, nodeProxy } from '../tsl/TSLCore.js'; +/** + * Represents a logical `if/else` statement. Can be used as an alternative + * to the `If()`/`Else()` syntax. + * + * The corresponding TSL `select()` looks like so: + * ```js + * velocity = position.greaterThanEqual( limit ).select( velocity.negate(), velocity ); + * ``` + * The `select()` method is called in a chaining fashion on a codition. The parameter nodes of `select()` + * determine the outcome of the entire statement. + * + * @augments Node + */ class ConditionalNode extends Node { static get type() { @@ -10,17 +23,47 @@ class ConditionalNode extends Node { } + /** + * Constructs a new conditional node. + * + * @param {Node} condNode - The node that defines the condition. + * @param {Node} ifNode - The node that is evaluate when the condition ends up `true`. + * @param {Node?} [elseNode=null] - The node that is evaluate when the condition ends up `false`. + */ constructor( condNode, ifNode, elseNode = null ) { super(); + /** + * The node that defines the condition. + * + * @type {Node} + */ this.condNode = condNode; + /** + * The node that is evaluate when the condition ends up `true`. + * + * @type {Node} + */ this.ifNode = ifNode; + + /** + * The node that is evaluate when the condition ends up `false`. + * + * @type {Node} + */ this.elseNode = elseNode; } + /** + * This method is overwritten since the node type is inferred from the if/else + * nodes. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {String} The node type. + */ getNodeType( builder ) { const ifType = this.ifNode.getNodeType( builder ); diff --git a/src/nodes/math/Hash.js b/src/nodes/math/Hash.js index fe226cf36b709e..45fea21fd2808d 100644 --- a/src/nodes/math/Hash.js +++ b/src/nodes/math/Hash.js @@ -1,5 +1,14 @@ import { Fn } from '../tsl/TSLBase.js'; +/** @module Hash **/ + +/** + * Generates a hash value in the range `[0, 1]` from the given seed. + * + * @method + * @param {Node} seed - The seed. + * @return {Node} The hash value. + */ export const hash = /*@__PURE__*/ Fn( ( [ seed ] ) => { // Taken from https://www.shadertoy.com/view/XlGcRh, originally from pcg-random.org diff --git a/src/nodes/math/MathNode.js b/src/nodes/math/MathNode.js index 9f62a3b56cc085..51c6a72c73d4f1 100644 --- a/src/nodes/math/MathNode.js +++ b/src/nodes/math/MathNode.js @@ -2,6 +2,16 @@ import TempNode from '../core/TempNode.js'; import { sub, mul, div } from './OperatorNode.js'; import { addMethodChaining, nodeObject, nodeProxy, float, vec2, vec3, vec4, Fn } from '../tsl/TSLCore.js'; +/** + * This node represents a variety of mathematical methods available in shaders. + * They are divided into three categories: + * + * - Methods with one input like `sin`, `cos` or `normalize`. + * - Methods with two inputs like `dot`, `cross` or `pow`. + * - Methods with three inputs like `mix`, `clamp` or `smoothstep`. + * + * @augments TempNode + */ class MathNode extends TempNode { static get type() { @@ -10,18 +20,58 @@ class MathNode extends TempNode { } + /** + * Constructs a new math node. + * + * @param {String} method - The method name. + * @param {Node} aNode - The first input. + * @param {Node?} [bNode=null] - The second input. + * @param {Node?} [cNode=null] - The third input. + */ constructor( method, aNode, bNode = null, cNode = null ) { super(); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.method = method; + /** + * The first input. + * + * @type {Node} + */ this.aNode = aNode; + + /** + * The second input. + * + * @type {Node?} + * @default null + */ this.bNode = bNode; + + /** + * The third input. + * + * @type {Node?} + * @default null + */ this.cNode = cNode; } + /** + * The input type is inferred from the node types of the input nodes. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {String} The input type. + */ getInputType( builder ) { const aType = this.aNode.getNodeType( builder ); @@ -50,6 +100,12 @@ class MathNode extends TempNode { } + /** + * The selected method as well as the input type determine the node type of this node. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {String} The node type. + */ getNodeType( builder ) { const method = this.method; diff --git a/src/nodes/math/MathUtils.js b/src/nodes/math/MathUtils.js index 35ffd944a84ef5..274c2acfe95b4d 100644 --- a/src/nodes/math/MathUtils.js +++ b/src/nodes/math/MathUtils.js @@ -1,8 +1,52 @@ import { sub, mul, div, add } from './OperatorNode.js'; import { PI, pow, sin } from './MathNode.js'; -// remapping functions https://iquilezles.org/articles/functions/ +/** @module MathUtils **/ + +/** + * A function that remaps the `[0,1]` interval into the `[0,1]` interval. + * The corners are mapped to `0` and the center to `1`. + * Reference: {@link https://iquilezles.org/articles/functions/}. + * + * @method + * @param {Node} x - The value to remap. + * @param {Node} k - Allows to control the remapping functions shape by rising the parabolar to a power `k`. + * @return {Node} The remapped value. + */ export const parabola = ( x, k ) => pow( mul( 4.0, x.mul( sub( 1.0, x ) ) ), k ); + +/** + * A function that remaps the `[0,1]` interval into the `[0,1]` interval. + * Expands the sides and compresses the center, and keeps `0.5` mapped to `0.5`. + * Reference: {@link https://iquilezles.org/articles/functions/}. + * + * @method + * @param {Node} x - The value to remap. + * @param {Node} k - `k=1` is the identity curve,`k<1` produces the classic `gain()` shape, and `k>1` produces "s" shaped curces. + * @return {Node} The remapped value. + */ export const gain = ( x, k ) => x.lessThan( 0.5 ) ? parabola( x.mul( 2.0 ), k ).div( 2.0 ) : sub( 1.0, parabola( mul( sub( 1.0, x ), 2.0 ), k ).div( 2.0 ) ); + +/** + * A function that remaps the `[0,1]` interval into the `[0,1]` interval. + * A generalization of the `parabola()`. Keeps the corners mapped to 0 but allows the control of the shape one either side of the curve. + * Reference: {@link https://iquilezles.org/articles/functions/}. + * + * @method + * @param {Node} x - The value to remap. + * @param {Node} a - First control paramter. + * @param {Node} b - Second control paramter. + * @return {Node} The remapped value. + */ export const pcurve = ( x, a, b ) => pow( div( pow( x, a ), add( pow( x, a ), pow( sub( 1.0, x ), b ) ) ), 1.0 / a ); + +/** + * A phase shifted sinus curve that starts at zero and ends at zero, with bouncing behavior. + * Reference: {@link https://iquilezles.org/articles/functions/}. + * + * @method + * @param {Node} x - The value to compute the sin for. + * @param {Node} k - Controls the amount of bounces. + * @return {Node} The result value. + */ export const sinc = ( x, k ) => sin( PI.mul( k.mul( x ).sub( 1.0 ) ) ).div( PI.mul( k.mul( x ).sub( 1.0 ) ) ); diff --git a/src/nodes/math/OperatorNode.js b/src/nodes/math/OperatorNode.js index 48e02f1b4e3593..50600d7d459bec 100644 --- a/src/nodes/math/OperatorNode.js +++ b/src/nodes/math/OperatorNode.js @@ -1,6 +1,12 @@ import TempNode from '../core/TempNode.js'; import { addMethodChaining, nodeProxy } from '../tsl/TSLCore.js'; +/** + * This node represents basic mathematical and logical operations like addition, + * subtraction or comparisons (e.g. `equal()`). + * + * @augments TempNode + */ class OperatorNode extends TempNode { static get type() { @@ -9,6 +15,14 @@ class OperatorNode extends TempNode { } + /** + * Constructs a new operator node. + * + * @param {String} op - The operator. + * @param {Node} aNode - The first input. + * @param {Node} bNode - The second input. + * @param {...Node} params - Additional input parameters. + */ constructor( op, aNode, bNode, ...params ) { super(); @@ -28,12 +42,37 @@ class OperatorNode extends TempNode { } + /** + * The operator. + * + * @type {String} + */ this.op = op; + + /** + * The first input. + * + * @type {Node} + */ this.aNode = aNode; + + /** + * The second input. + * + * @type {Node} + */ this.bNode = bNode; } + /** + * This method is overwritten since the node type is inferred from the operator + * and the input node types. + * + * @param {NodeBuilder} builder - The current node builder. + * @param {String} output - The current output string. + * @return {String} The node type. + */ getNodeType( builder, output ) { const op = this.op; diff --git a/src/nodes/math/TriNoise3D.js b/src/nodes/math/TriNoise3D.js index c0428826928d9f..7e3ceee7d56c54 100644 --- a/src/nodes/math/TriNoise3D.js +++ b/src/nodes/math/TriNoise3D.js @@ -3,7 +3,9 @@ import { Loop } from '../utils/LoopNode.js'; import { float, vec3, Fn } from '../tsl/TSLBase.js'; -export const tri = /*@__PURE__*/ Fn( ( [ x ] ) => { +/** @module TriNoise3D **/ + +const tri = /*@__PURE__*/ Fn( ( [ x ] ) => { return x.fract().sub( .5 ).abs(); @@ -15,7 +17,7 @@ export const tri = /*@__PURE__*/ Fn( ( [ x ] ) => { ] } ); -export const tri3 = /*@__PURE__*/ Fn( ( [ p ] ) => { +const tri3 = /*@__PURE__*/ Fn( ( [ p ] ) => { return vec3( tri( p.z.add( tri( p.y.mul( 1. ) ) ) ), tri( p.z.add( tri( p.x.mul( 1. ) ) ) ), tri( p.y.add( tri( p.x.mul( 1. ) ) ) ) ); @@ -27,9 +29,20 @@ export const tri3 = /*@__PURE__*/ Fn( ( [ p ] ) => { ] } ); -export const triNoise3D = /*@__PURE__*/ Fn( ( [ p_immutable, spd, time ] ) => { +/** @module Hash **/ + +/** + * Generates a noise value from the given position, speed and time parameters. + * + * @method + * @param {Node} position - The position. + * @param {Node} speed - The speed. + * @param {Node} time - The time. + * @return {Node} The generated noise. + */ +export const triNoise3D = /*@__PURE__*/ Fn( ( [ position, speed, time ] ) => { - const p = vec3( p_immutable ).toVar(); + const p = vec3( position ).toVar(); const z = float( 1.4 ).toVar(); const rz = float( 0.0 ).toVar(); const bp = vec3( p ).toVar(); @@ -37,7 +50,7 @@ export const triNoise3D = /*@__PURE__*/ Fn( ( [ p_immutable, spd, time ] ) => { Loop( { start: float( 0.0 ), end: float( 3.0 ), type: 'float', condition: '<=' }, () => { const dg = vec3( tri3( bp.mul( 2.0 ) ) ).toVar(); - p.addAssign( dg.add( time.mul( float( 0.1 ).mul( spd ) ) ) ); + p.addAssign( dg.add( time.mul( float( 0.1 ).mul( speed ) ) ) ); bp.mulAssign( 1.8 ); z.mulAssign( 1.5 ); p.mulAssign( 1.2 ); @@ -54,8 +67,8 @@ export const triNoise3D = /*@__PURE__*/ Fn( ( [ p_immutable, spd, time ] ) => { name: 'triNoise3D', type: 'float', inputs: [ - { name: 'p', type: 'vec3' }, - { name: 'spd', type: 'float' }, + { name: 'position', type: 'vec3' }, + { name: 'speed', type: 'float' }, { name: 'time', type: 'float' } ] } ); diff --git a/src/nodes/pmrem/PMREMNode.js b/src/nodes/pmrem/PMREMNode.js index 856c421f8e75b1..336e7230778c6f 100644 --- a/src/nodes/pmrem/PMREMNode.js +++ b/src/nodes/pmrem/PMREMNode.js @@ -12,6 +12,13 @@ let _generator = null; const _cache = new WeakMap(); +/** + * Generates the cubeUV size based on the given image height. + * + * @private + * @param {Number} imageHeight - The image height. + * @return {{texelWidth: Number,texelHeight: Number, maxMip: Number}} The result object. + */ function _generateCubeUVSize( imageHeight ) { const maxMip = Math.log2( imageHeight ) - 2; @@ -24,6 +31,13 @@ function _generateCubeUVSize( imageHeight ) { } +/** + * Generates a PMREM from the given texture . + * + * @private + * @param {Texture} texture - The texture to create the PMREM for. + * @return {Texture} The PMREM. + */ function _getPMREMFromTexture( texture ) { let cacheTexture = _cache.get( texture ); @@ -71,6 +85,17 @@ function _getPMREMFromTexture( texture ) { } +/** + * This node represents a PMREM which is a special type of preprocessed + * environment map intended for PBR materials. + * + * ```js + * const material = new MeshStandardNodeMaterial(); + * material.envNode = pmremTexture( envMap ); + * ``` + * + * @augments TempNode + */ class PMREMNode extends TempNode { static get type() { @@ -79,31 +104,107 @@ class PMREMNode extends TempNode { } + /** + * Constructs a new function overloading node. + * + * @param {Texture} texture - The input texture. + * @param {Node} [uvNode=null] - The uv node. + * @param {Node} [levelNode=null] - The level node. + */ constructor( value, uvNode = null, levelNode = null ) { super( 'vec3' ); + /** + * Reference to the input texture. + * + * @private + * @type {Texture} + */ this._value = value; + + /** + * Reference to the generated PMREM. + * + * @private + * @type {Texture} + * @default null + */ this._pmrem = null; + /** + * The uv node. + * + * @type {Node} + */ this.uvNode = uvNode; + + /** + * The level node. + * + * @type {Node} + */ this.levelNode = levelNode; + /** + * Reference to a PMREM generator. + * + * @private + * @type {PMREMGenerator} + * @default null + */ this._generator = null; const defaultTexture = new Texture(); defaultTexture.isRenderTargetTexture = true; + /** + * The texture node holding the generated PMREM. + * + * @private + * @type {TextureNode} + */ this._texture = texture( defaultTexture ); + /** + * A uniform representing the PMREM's width. + * + * @private + * @type {UniformNode} + */ this._width = uniform( 0 ); + + /** + * A uniform representing the PMREM's height. + * + * @private + * @type {UniformNode} + */ this._height = uniform( 0 ); + + /** + * A uniform representing the PMREM's max Mip. + * + * @private + * @type {UniformNode} + */ this._maxMip = uniform( 0 ); + /** + * The `updateBeforeType` is set to `NodeUpdateType.RENDER`. + * + * @type {String} + * @default 'render' + */ this.updateBeforeType = NodeUpdateType.RENDER; } + /** + * The node's texture value. + * + * @type {Texture} + */ set value( value ) { this._value = value; @@ -117,6 +218,11 @@ class PMREMNode extends TempNode { } + /** + * Uses the given PMREM texture to update internal values. + * + * @param {Texture} texture - The PMREM texture. + */ updateFromTexture( texture ) { const cubeUVSize = _generateCubeUVSize( texture.image.height ); @@ -211,6 +317,13 @@ class PMREMNode extends TempNode { export default PMREMNode; +/** + * Returns `true` if the given cube map image has been fully loaded. + * + * @private + * @param {Array<(Image|Object)>} image - The cube map image. + * @return {Boolean} Whether the given cube map is ready or not. + */ function isCubeMapReady( image ) { if ( image === null || image === undefined ) return false; @@ -229,6 +342,13 @@ function isCubeMapReady( image ) { } +/** + * Returns `true` if the given equirectangular image has been fully loaded. + * + * @private + * @param {(Image|Object)} image - The equirectangular image. + * @return {Boolean} Whether the given cube map is ready or not. + */ function isEquirectangularMapReady( image ) { if ( image === null || image === undefined ) return false;