diff --git a/src/materials/nodes/InstancedPointsNodeMaterial.js b/src/materials/nodes/InstancedPointsNodeMaterial.js index 0d7278225f5bdd..4c28af986f1f6c 100644 --- a/src/materials/nodes/InstancedPointsNodeMaterial.js +++ b/src/materials/nodes/InstancedPointsNodeMaterial.js @@ -13,6 +13,15 @@ import { PointsMaterial } from '../PointsMaterial.js'; const _defaultValues = /*@__PURE__*/ new PointsMaterial(); +/** + * Unlike WebGL, WebGPU can render point primitives only with a size + * of one pixel. This type node material can be used to mimic the WebGL + * points rendering by rendering small planes via instancing. + * + * This material should be used with {@link InstancedPointsGeometry}. + * + * @augments NodeMaterial + */ class InstancedPointsNodeMaterial extends NodeMaterial { static get type() { @@ -21,39 +30,75 @@ class InstancedPointsNodeMaterial extends NodeMaterial { } - constructor( params = {} ) { + /** + * Constructs a new instanced points node material. + * + * @param {Object?} parameters - The configuration parameter. + */ + constructor( parameters = {} ) { super(); - this.lights = false; - - this.useAlphaToCoverage = true; - - this.useColor = params.vertexColors; - + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ + this.isInstancedPointsNodeMaterial = true; + + /** + * Whether vertex colors should be used or not. If set to `true`, + * each point instance can receive a custom color value. + * + * @type {Boolean} + * @default false + */ + this.useColor = parameters.vertexColors; + + /** + * The points width in pixels. + * + * @type {Number} + * @default 1 + */ this.pointWidth = 1; + /** + * This node can be used to define the colors for each instance. + * + * @type {Node?} + * @default null + */ this.pointColorNode = null; + /** + * This node can be used to define the width for each point instance. + * + * @type {Node?} + * @default null + */ this.pointWidthNode = null; + this._useAlphaToCoverage = true; + this.setDefaultValues( _defaultValues ); - this.setValues( params ); + this.setValues( parameters ); } + /** + * Setups the vertex and fragment stage of this node material. + * + * @param {NodeBuilder} builder - The current node builder. + */ setup( builder ) { - this.setupShaders( builder ); - - super.setup( builder ); + const { renderer } = builder; - } - - setupShaders( { renderer } ) { - - const useAlphaToCoverage = this.alphaToCoverage; + const useAlphaToCoverage = this._useAlphaToCoverage; const useColor = this.useColor; this.vertexNode = Fn( () => { @@ -132,19 +177,27 @@ class InstancedPointsNodeMaterial extends NodeMaterial { } )(); + super.setup( builder ); + } + /** + * Whether alpha to coverage should be used or not. + * + * @type {Boolean} + * @default true + */ get alphaToCoverage() { - return this.useAlphaToCoverage; + return this._useAlphaToCoverage; } set alphaToCoverage( value ) { - if ( this.useAlphaToCoverage !== value ) { + if ( this._useAlphaToCoverage !== value ) { - this.useAlphaToCoverage = value; + this._useAlphaToCoverage = value; this.needsUpdate = true; } diff --git a/src/materials/nodes/Line2NodeMaterial.js b/src/materials/nodes/Line2NodeMaterial.js index 5613913748d90b..7a2835020b2327 100644 --- a/src/materials/nodes/Line2NodeMaterial.js +++ b/src/materials/nodes/Line2NodeMaterial.js @@ -16,6 +16,12 @@ import { NoBlending } from '../../constants.js'; const _defaultValues = /*@__PURE__*/ new LineDashedMaterial(); +/** + * This node material can be used to render lines with a size larger than one + * by representing them as instanced meshes. + * + * @augments NodeMaterial + */ class Line2NodeMaterial extends NodeMaterial { static get type() { @@ -24,49 +30,120 @@ class Line2NodeMaterial extends NodeMaterial { } - constructor( params = {} ) { + /** + * Constructs a new node material for wide line rendering. + * + * @param {Object?} parameters - The configuration parameter. + */ + constructor( parameters = {} ) { super(); - this.lights = false; + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ + this.isLine2NodeMaterial = true; this.setDefaultValues( _defaultValues ); - this.useAlphaToCoverage = true; - this.useColor = params.vertexColors; - this.useDash = params.dashed; - this.useWorldUnits = false; - + /** + * Whether vertex colors should be used or not. + * + * @type {Boolean} + * @default false + */ + this.useColor = parameters.vertexColors; + + /** + * The dash offset. + * + * @type {Number} + * @default 0 + */ this.dashOffset = 0; + + /** + * The line width. + * + * @type {Number} + * @default 0 + */ this.lineWidth = 1; + /** + * Defines the lines color. + * + * @type {Node?} + * @default null + */ this.lineColorNode = null; + /** + * Defines the offset. + * + * @type {Node?} + * @default null + */ this.offsetNode = null; + + /** + * Defines the dash scale. + * + * @type {Node?} + * @default null + */ this.dashScaleNode = null; + + /** + * Defines the dash size. + * + * @type {Node?} + * @default null + */ this.dashSizeNode = null; + + /** + * Defines the gap size. + * + * @type {Node?} + * @default null + */ this.gapSizeNode = null; + /** + * Blending is set to `NoBlending` since transparency + * is not supported, yet. + * + * @type {Number} + * @default 0 + */ this.blending = NoBlending; - this.setValues( params ); + this._useDash = parameters.dashed; + this._useAlphaToCoverage = true; + this._useWorldUnits = false; + + this.setValues( parameters ); } + /** + * Setups the vertex and fragment stage of this node material. + * + * @param {NodeBuilder} builder - The current node builder. + */ setup( builder ) { - this.setupShaders( builder ); - - super.setup( builder ); - - } - - setupShaders( { renderer } ) { + const { renderer } = builder; - const useAlphaToCoverage = this.alphaToCoverage; + const useAlphaToCoverage = this._useAlphaToCoverage; const useColor = this.useColor; - const useDash = this.dashed; - const useWorldUnits = this.worldUnits; + const useDash = this._useDash; + const useWorldUnits = this._useWorldUnits; const trimSegment = Fn( ( { start, end } ) => { @@ -394,56 +471,74 @@ class Line2NodeMaterial extends NodeMaterial { } - } + super.setup( builder ); + } + /** + * Whether the lines should sized in world units or not. + * When set to `false` the unit is pixel. + * + * @type {Boolean} + * @default false + */ get worldUnits() { - return this.useWorldUnits; + return this._useWorldUnits; } set worldUnits( value ) { - if ( this.useWorldUnits !== value ) { + if ( this._useWorldUnits !== value ) { - this.useWorldUnits = value; + this._useWorldUnits = value; this.needsUpdate = true; } } - + /** + * Whether the lines should be dashed or not. + * + * @type {Boolean} + * @default false + */ get dashed() { - return this.useDash; + return this._useDash; } set dashed( value ) { - if ( this.useDash !== value ) { + if ( this._useDash !== value ) { - this.useDash = value; + this._useDash = value; this.needsUpdate = true; } } - + /** + * Whether alpha to coverage should be used or not. + * + * @type {Boolean} + * @default true + */ get alphaToCoverage() { - return this.useAlphaToCoverage; + return this._useAlphaToCoverage; } set alphaToCoverage( value ) { - if ( this.useAlphaToCoverage !== value ) { + if ( this._useAlphaToCoverage !== value ) { - this.useAlphaToCoverage = value; + this._useAlphaToCoverage = value; this.needsUpdate = true; } diff --git a/src/materials/nodes/MeshPhysicalNodeMaterial.js b/src/materials/nodes/MeshPhysicalNodeMaterial.js index b06062ae5b0afd..e480b338787e19 100644 --- a/src/materials/nodes/MeshPhysicalNodeMaterial.js +++ b/src/materials/nodes/MeshPhysicalNodeMaterial.js @@ -11,6 +11,11 @@ import { MeshPhysicalMaterial } from '../MeshPhysicalMaterial.js'; const _defaultValues = /*@__PURE__*/ new MeshPhysicalMaterial(); +/** + * Node material version of `MeshPhysicalMaterial`. + * + * @augments MeshStandardNodeMaterial + */ class MeshPhysicalNodeMaterial extends MeshStandardNodeMaterial { static get type() { @@ -19,33 +24,243 @@ class MeshPhysicalNodeMaterial extends MeshStandardNodeMaterial { } + /** + * Constructs a new mesh physical node material. + * + * @param {Object?} parameters - The configuration parameter. + */ constructor( parameters ) { super(); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isMeshPhysicalNodeMaterial = true; + /** + * The clearcoat of physical materials is by default inferred from the `clearcoat` + * and `clearcoatMap` properties. This node property allows to overwrite the default + * and define the clearcoat with a node instead. + * + * If you don't want to overwrite the clearcoat but modify the existing + * value instead, use {@link module:MaterialNode.materialClearcoat}. + * + * @type {Node?} + * @default null + */ this.clearcoatNode = null; + + /** + * The clearcoat roughness of physical materials is by default inferred from the `clearcoatRoughness` + * and `clearcoatRoughnessMap` properties. This node property allows to overwrite the default + * and define the clearcoat roughness with a node instead. + * + * If you don't want to overwrite the clearcoat roughness but modify the existing + * value instead, use {@link module:MaterialNode.materialClearcoatRoughness}. + * + * @type {Node?} + * @default null + */ this.clearcoatRoughnessNode = null; + + /** + * The clearcoat normal of physical materials is by default inferred from the `clearcoatNormalMap` + * property. This node property allows to overwrite the default + * and define the clearcoat normal with a node instead. + * + * If you don't want to overwrite the clearcoat normal but modify the existing + * value instead, use {@link module:MaterialNode.materialClearcoatNormal}. + * + * @type {Node?} + * @default null + */ this.clearcoatNormalNode = null; + /** + * The sheen of physical materials is by default inferred from the `sheen`, `sheenColor` + * and `sheenColorMap` properties. This node property allows to overwrite the default + * and define the sheen with a node instead. + * + * If you don't want to overwrite the sheen but modify the existing + * value instead, use {@link module:MaterialNode.materialSheen}. + * + * @type {Node?} + * @default null + */ this.sheenNode = null; + + /** + * The sheen roughness of physical materials is by default inferred from the `sheenRoughness` and + * `sheenRoughnessMap` properties. This node property allows to overwrite the default + * and define the sheen roughness with a node instead. + * + * If you don't want to overwrite the sheen roughness but modify the existing + * value instead, use {@link module:MaterialNode.materialSheenRoughness}. + * + * @type {Node?} + * @default null + */ this.sheenRoughnessNode = null; + /** + * The iridescence of physical materials is by default inferred from the `iridescence` + * property. This node property allows to overwrite the default + * and define the iridescence with a node instead. + * + * If you don't want to overwrite the iridescence but modify the existing + * value instead, use {@link module:MaterialNode.materialIridescence}. + * + * @type {Node?} + * @default null + */ this.iridescenceNode = null; + + /** + * The iridescence IOR of physical materials is by default inferred from the `iridescenceIOR` + * property. This node property allows to overwrite the default + * and define the iridescence IOR with a node instead. + * + * If you don't want to overwrite the iridescence IOR but modify the existing + * value instead, use {@link module:MaterialNode.materialIridescenceIOR}. + * + * @type {Node?} + * @default null + */ this.iridescenceIORNode = null; + + /** + * The iridescence thickness of physical materials is by default inferred from the `iridescenceThicknessRange` + * and `iridescenceThicknessMap` properties. This node property allows to overwrite the default + * and define the iridescence thickness with a node instead. + * + * If you don't want to overwrite the iridescence thickness but modify the existing + * value instead, use {@link module:MaterialNode.materialIridescenceThickness}. + * + * @type {Node?} + * @default null + */ this.iridescenceThicknessNode = null; + /** + * The specular intensity of physical materials is by default inferred from the `specularIntensity` + * and `specularIntensityMap` properties. This node property allows to overwrite the default + * and define the specular intensity with a node instead. + * + * If you don't want to overwrite the specular intensity but modify the existing + * value instead, use {@link module:MaterialNode.materialSpecularIntensity}. + * + * @type {Node?} + * @default null + */ this.specularIntensityNode = null; + + /** + * The specular color of physical materials is by default inferred from the `specularColor` + * and `specularColorMap` properties. This node property allows to overwrite the default + * and define the specular color with a node instead. + * + * If you don't want to overwrite the specular color but modify the existing + * value instead, use {@link module:MaterialNode.materialSpecularColor}. + * + * @type {Node?} + * @default null + */ this.specularColorNode = null; + /** + * The ior of physical materials is by default inferred from the `ior` + * property. This node property allows to overwrite the default + * and define the ior with a node instead. + * + * If you don't want to overwrite the ior but modify the existing + * value instead, use {@link module:MaterialNode.materialIOR}. + * + * @type {Node?} + * @default null + */ this.iorNode = null; + + /** + * The transmission of physical materials is by default inferred from the `transmission` and + * `transmissionMap` properties. This node property allows to overwrite the default + * and define the transmission with a node instead. + * + * If you don't want to overwrite the transmission but modify the existing + * value instead, use {@link module:MaterialNode.materialTransmission}. + * + * @type {Node?} + * @default null + */ this.transmissionNode = null; + + /** + * The thickness of physical materials is by default inferred from the `thickness` and + * `thicknessMap` properties. This node property allows to overwrite the default + * and define the thickness with a node instead. + * + * If you don't want to overwrite the thickness but modify the existing + * value instead, use {@link module:MaterialNode.materialThickness}. + * + * @type {Node?} + * @default null + */ this.thicknessNode = null; + + /** + * The attenuation distance of physical materials is by default inferred from the + * `attenuationDistance` property. This node property allows to overwrite the default + * and define the attenuation distance with a node instead. + * + * If you don't want to overwrite the attenuation distance but modify the existing + * value instead, use {@link module:MaterialNode.materialAttenuationDistance}. + * + * @type {Node?} + * @default null + */ this.attenuationDistanceNode = null; + + /** + * The attenuation color of physical materials is by default inferred from the + * `attenuationColor` property. This node property allows to overwrite the default + * and define the attenuation color with a node instead. + * + * If you don't want to overwrite the attenuation color but modify the existing + * value instead, use {@link module:MaterialNode.materialAttenuationColor}. + * + * @type {Node?} + * @default null + */ this.attenuationColorNode = null; + + /** + * The dispersion of physical materials is by default inferred from the + * `dispersion` property. This node property allows to overwrite the default + * and define the dispersion with a node instead. + * + * If you don't want to overwrite the dispersion but modify the existing + * value instead, use {@link module:MaterialNode.materialDispersion}. + * + * @type {Node?} + * @default null + */ this.dispersionNode = null; + /** + * The anisotropy of physical materials is by default inferred from the + * `anisotropy` property. This node property allows to overwrite the default + * and define the anisotropy with a node instead. + * + * If you don't want to overwrite the anisotropy but modify the existing + * value instead, use {@link module:MaterialNode.materialAnisotropy}. + * + * @type {Node?} + * @default null + */ this.anisotropyNode = null; this.setDefaultValues( _defaultValues ); @@ -54,42 +269,81 @@ class MeshPhysicalNodeMaterial extends MeshStandardNodeMaterial { } + /** + * Whether the lighting model should use clearcoat or not. + * + * @type {Boolean} + * @default true + */ get useClearcoat() { return this.clearcoat > 0 || this.clearcoatNode !== null; } + /** + * Whether the lighting model should use iridescence or not. + * + * @type {Boolean} + * @default true + */ get useIridescence() { return this.iridescence > 0 || this.iridescenceNode !== null; } + /** + * Whether the lighting model should use sheen or not. + * + * @type {Boolean} + * @default true + */ get useSheen() { return this.sheen > 0 || this.sheenNode !== null; } + /** + * Whether the lighting model should use anisotropy or not. + * + * @type {Boolean} + * @default true + */ get useAnisotropy() { return this.anisotropy > 0 || this.anisotropyNode !== null; } + /** + * Whether the lighting model should use transmission or not. + * + * @type {Boolean} + * @default true + */ get useTransmission() { return this.transmission > 0 || this.transmissionNode !== null; } + /** + * Whether the lighting model should use dispersion or not. + * + * @type {Boolean} + * @default true + */ get useDispersion() { return this.dispersion > 0 || this.dispersionNode !== null; } + /** + * Setups the specular related node variables. + */ setupSpecular() { const iorNode = this.iorNode ? float( this.iorNode ) : materialIOR; @@ -100,12 +354,22 @@ class MeshPhysicalNodeMaterial extends MeshStandardNodeMaterial { } + /** + * Setups the lighting model. + * + * @return {PhysicalLightingModel} The lighting model. + */ setupLightingModel( /*builder*/ ) { return new PhysicalLightingModel( this.useClearcoat, this.useSheen, this.useIridescence, this.useAnisotropy, this.useTransmission, this.useDispersion ); } + /** + * Setups the physical specific node variables. + * + * @param {NodeBuilder} builder - The current node builder. + */ setupVariants( builder ) { super.setupVariants( builder ); @@ -201,6 +465,11 @@ class MeshPhysicalNodeMaterial extends MeshStandardNodeMaterial { } + /** + * Setups the clearcoat normal node. + * + * @return {Node} The clearcoat noraml. + */ setupClearcoatNormal() { return this.clearcoatNormalNode ? vec3( this.clearcoatNormalNode ) : materialClearcoatNormal; diff --git a/src/materials/nodes/MeshSSSNodeMaterial.js b/src/materials/nodes/MeshSSSNodeMaterial.js index 064d9e4b896fe3..3c5736f48a173d 100644 --- a/src/materials/nodes/MeshSSSNodeMaterial.js +++ b/src/materials/nodes/MeshSSSNodeMaterial.js @@ -4,16 +4,49 @@ import { transformedNormalView } from '../../nodes/accessors/Normal.js'; import { positionViewDirection } from '../../nodes/accessors/Position.js'; import { float, vec3 } from '../../nodes/tsl/TSLBase.js'; -class SSSLightingModel extends PhysicalLightingModel { - - constructor( useClearcoat, useSheen, useIridescence, useSSS ) { +/** @module MeshSSSNodeMaterial **/ - super( useClearcoat, useSheen, useIridescence ); +/** + * Represents the lighting model for {@link MeshSSSNodeMaterial}. + * + * @augments PhysicalLightingModel + */ +class SSSLightingModel extends PhysicalLightingModel { - this.useSSS = useSSS; + /** + * Constructs a new physical lighting model. + * + * @param {Boolean} [clearcoat=false] - Whether clearcoat is supported or not. + * @param {Boolean} [sheen=false] - Whether sheen is supported or not. + * @param {Boolean} [iridescence=false] - Whether iridescence is supported or not. + * @param {Boolean} [anisotropy=false] - Whether anisotropy is supported or not. + * @param {Boolean} [transmission=false] - Whether transmission is supported or not. + * @param {Boolean} [dispersion=false] - Whether dispersion is supported or not. + * @param {Boolean} [sss=false] - Whether SSS is supported or not. + */ + constructor( clearcoat = false, sheen = false, iridescence = false, anisotropy = false, transmission = false, dispersion = false, sss = false ) { + + super( clearcoat, sheen, iridescence, anisotropy, transmission, dispersion ); + + /** + * Whether the lighting model should use SSS or not. + * + * @type {Boolean} + * @default false + */ + this.useSSS = sss; } + /** + * Extends the default implementation with a SSS term. + * + * Reference: [Approximating Translucency for a Fast, Cheap and Convincing Subsurface Scattering Look]{@link https://colinbarrebrisebois.com/2011/03/07/gdc-2011-approximating-translucency-for-a-fast-cheap-and-convincing-subsurface-scattering-look/} + * + * @param {Object} input - The input data. + * @param {StackNode} stack - The current stack. + * @param {NodeBuilder} builder - The current node builder. + */ direct( { lightDirection, lightColor, reflectedLight }, stack, builder ) { if ( this.useSSS === true ) { @@ -36,6 +69,12 @@ class SSSLightingModel extends PhysicalLightingModel { } +/** + * This node material is an experimental extension of {@link MeshPhysicalNodeMaterial} + * that implements a Subsurface scattering (SSS) term. + * + * @augments MeshPhysicalNodeMaterial + */ class MeshSSSNodeMaterial extends MeshPhysicalNodeMaterial { static get type() { @@ -44,28 +83,80 @@ class MeshSSSNodeMaterial extends MeshPhysicalNodeMaterial { } + /** + * Constructs a new mesh SSS node material. + * + * @param {Object?} parameters - The configuration parameter. + */ constructor( parameters ) { super( parameters ); + /** + * Represents the thickness color. + * + * @type {Node?} + * @default null + */ this.thicknessColorNode = null; + + /** + * Represents the distortion factor. + * + * @type {Node?} + */ this.thicknessDistortionNode = float( 0.1 ); + + /** + * Represents the thickness ambient factor. + * + * @type {Node?} + */ this.thicknessAmbientNode = float( 0.0 ); + + /** + * Represents the thickness attenuation. + * + * @type {Node?} + */ this.thicknessAttenuationNode = float( .1 ); + + /** + * Represents the thickness power. + * + * @type {Node?} + */ this.thicknessPowerNode = float( 2.0 ); + + /** + * Represents the thickness scale. + * + * @type {Node?} + */ this.thicknessScaleNode = float( 10.0 ); } + /** + * Whether the lighting model should use SSS or not. + * + * @type {Boolean} + * @default true + */ get useSSS() { return this.thicknessColorNode !== null; } + /** + * Setups the lighting model. + * + * @return {SSSLightingModel} The lighting model. + */ setupLightingModel( /*builder*/ ) { - return new SSSLightingModel( this.useClearcoat, this.useSheen, this.useIridescence, this.useSSS ); + return new SSSLightingModel( this.useClearcoat, this.useSheen, this.useIridescence, this.useAnisotropy, this.useTransmission, this.useDispersion, this.useSSS ); } diff --git a/src/materials/nodes/NodeMaterial.js b/src/materials/nodes/NodeMaterial.js index 4063f968842dd3..f30a2cdae55c54 100644 --- a/src/materials/nodes/NodeMaterial.js +++ b/src/materials/nodes/NodeMaterial.js @@ -400,7 +400,7 @@ class NodeMaterial extends Material { } /** - * Setups the vertex and fragment stahge of this node material. + * Setups the vertex and fragment stage of this node material. * * @param {NodeBuilder} builder - The current node builder. */ diff --git a/src/materials/nodes/VolumeNodeMaterial.js b/src/materials/nodes/VolumeNodeMaterial.js index 39940174305e48..0927a2ec10d4ef 100644 --- a/src/materials/nodes/VolumeNodeMaterial.js +++ b/src/materials/nodes/VolumeNodeMaterial.js @@ -8,7 +8,14 @@ import { Fn, varying, float, vec2, vec3, vec4 } from '../../nodes/tsl/TSLBase.js import { min, max } from '../../nodes/math/MathNode.js'; import { Loop, Break } from '../../nodes/utils/LoopNode.js'; import { texture3D } from '../../nodes/accessors/Texture3DNode.js'; - +import { Color } from '../../math/Color.js'; + +/** + * Node material intended for volume rendering. The volumetic data are + * defined with an instance of {@link Data3DTexture}. + * + * @augments NodeMaterial + */ class VolumeNodeMaterial extends NodeMaterial { static get type() { @@ -17,18 +24,85 @@ class VolumeNodeMaterial extends NodeMaterial { } - constructor( params = {} ) { + /** + * Constructs a new volume node material. + * + * @param {Object?} parameters - The configuration parameter. + */ + constructor( parameters ) { super(); - this.lights = false; + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isVolumeNodeMaterial = true; + + /** + * The base color of the volume. + * + * @type {Color} + * @default 100 + */ + this.base = new Color( 0xffffff ); + + /** + * A 3D data texture holding the volumetric data. + * + * @type {Data3DTexture?} + * @default null + */ + this.map = null; + + /** + * This number of samples for each ray that hits the mesh's surface + * and travels through the volume. + * + * @type {Number} + * @default 100 + */ + this.steps = 100; + + /** + * Callback for {@link VolumeNodeMaterial#testNode}. + * + * @callback testNodeCallback + * @param {Data3DTexture} map - The 3D texture. + * @param {Node} mapValue - The sampled value inside the volume. + * @param {Node} probe - The probe which is the entry point of the ray on the mesh's surface. + * @param {Node} finalColor - The final color. + */ + + /** + * The volume rendering of this material works by shooting rays + * from the camera position through each fragment of the mesh's + * surface and sample the inner volume in a raymarching fashion + * mutiple times. + * + * This node can be used to assign a callback function of type `Fn` + * that will be exexuted per sample. The callback receives the + * texture, the sampled texture value as well as position on the surface + * where the rays enters the volume. The last parameter is a color + * that allows the callback to determine the final color. + * + * @type {testNodeCallback?} + * @default null + */ this.testNode = null; - this.setValues( params ); + this.setValues( parameters ); } + /** + * Setups the vertex and fragment stage of this node material. + * + * @param {NodeBuilder} builder - The current node builder. + */ setup( builder ) { const map = texture3D( this.map, null, 0 ); diff --git a/src/materials/nodes/manager/NodeMaterialObserver.js b/src/materials/nodes/manager/NodeMaterialObserver.js index d7865a70fb6bf7..6a193f594093fd 100644 --- a/src/materials/nodes/manager/NodeMaterialObserver.js +++ b/src/materials/nodes/manager/NodeMaterialObserver.js @@ -51,18 +51,65 @@ const refreshUniforms = [ 'transmissionMap' ]; +/** + * This class is used by {@link WebGPURenderer} as management component. + * It's primary purpose is to determine whether render objects require a + * refresh right before they are going to be rendered or not. + */ class NodeMaterialObserver { + /** + * Constructs a new node material observer. + * + * @param {NodeBuilder} builder - The node builder. + */ constructor( builder ) { + /** + * A node material can be used by more than one render object so the + * monitor must maintain a list of render objects. + * + * @type {WeakMap} + */ this.renderObjects = new WeakMap(); + + /** + * Whether the material uses node objects or not. + * + * @type {Boolean} + */ this.hasNode = this.containsNode( builder ); + + /** + * Whether the node builder's 3D object is animated or not. + * + * @type {Boolean} + */ this.hasAnimation = builder.object.isSkinnedMesh === true; + + /** + * A list of all possible material uniforms + * + * @type {Array} + */ this.refreshUniforms = refreshUniforms; + + /** + * Holds the current render ID from the node frame. + * + * @type {Number} + * @default 0 + */ this.renderId = 0; } + /** + * Returns `true` if the given render object is verified for the first time of this observer. + * + * @param {RenderObject} renderObject - The render object. + * @return {Boolean} Whether the given render object is verified for the first time of this observer. + */ firstInitialization( renderObject ) { const hasInitialized = this.renderObjects.has( renderObject ); @@ -79,6 +126,12 @@ class NodeMaterialObserver { } + /** + * Returns monitoring data for the given render object. + * + * @param {RenderObject} renderObject - The render object. + * @return {Object} The monitoring data. + */ getRenderObjectData( renderObject ) { let data = this.renderObjects.get( renderObject ); @@ -132,6 +185,13 @@ class NodeMaterialObserver { } + /** + * Returns an attribute data structure holding the attributes versions for + * monitoring. + * + * @param {Object} attributes - The geometry attributes. + * @return {Object} An object for monitoring the versions of attributes. + */ getAttributesData( attributes ) { const attributesData = {}; @@ -150,6 +210,13 @@ class NodeMaterialObserver { } + /** + * Returns `true` if the node builder's material uses + * node properties. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {Boolean} Whether the node builder's material uses node properties or not. + */ containsNode( builder ) { const material = builder.material; @@ -168,6 +235,13 @@ class NodeMaterialObserver { } + /** + * Returns a material data structure holding the material property values for + * monitoring. + * + * @param {Material} material - The material. + * @return {Object} An object for monitoring material properties. + */ getMaterialData( material ) { const data = {}; @@ -202,6 +276,12 @@ class NodeMaterialObserver { } + /** + * Returns `true` if the given render object has not changed its state. + * + * @param {RenderObject} renderObject - The render object. + * @return {Boolean} Whether the given render object has changed its state or not. + */ equals( renderObject ) { const { object, material, geometry } = renderObject; @@ -382,6 +462,13 @@ class NodeMaterialObserver { } + /** + * Checks if the given render object requires a refresh. + * + * @param {RenderObject} renderObject - The render object. + * @param {NodeFrame} nodeFrame - The current node frame. + * @return {Boolean} Whether the given render object requires a refresh or not. + */ needsRefresh( renderObject, nodeFrame ) { if ( this.hasNode || this.hasAnimation || this.firstInitialization( renderObject ) ) diff --git a/src/nodes/accessors/MaterialNode.js b/src/nodes/accessors/MaterialNode.js index a7a880911f57ec..8f8397d37aaf1f 100644 --- a/src/nodes/accessors/MaterialNode.js +++ b/src/nodes/accessors/MaterialNode.js @@ -161,15 +161,15 @@ class MaterialNode extends Node { } else if ( scope === MaterialNode.SPECULAR_INTENSITY ) { - const specularIntensity = this.getFloat( scope ); + const specularIntensityNode = this.getFloat( scope ); - if ( material.specularMap ) { + if ( material.specularIntensityMap && material.specularIntensityMap.isTexture === true ) { - node = specularIntensity.mul( this.getTexture( scope ).a ); + node = specularIntensityNode.mul( this.getTexture( scope ).a ); } else { - node = specularIntensity; + node = specularIntensityNode; } @@ -499,7 +499,7 @@ export const materialSpecularIntensity = /*@__PURE__*/ nodeImmutable( MaterialNo * TSL object that represents the specular color of the current material. * The value is composed via `specularColor` * `specularMap.rgb`. * - * @type {Node} + * @type {Node} */ export const materialSpecularColor = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.SPECULAR_COLOR ); @@ -544,7 +544,7 @@ export const materialNormal = /*@__PURE__*/ nodeImmutable( MaterialNode, Materia /** * TSL object that represents the clearcoat of the current material. - * The value is composed via `clearcoat` * `clearcoat.r` + * The value is composed via `clearcoat` * `clearcoatMap.r` * * @type {Node} */