From e0809bb223f9a0fa82947f74222f1902333295d3 Mon Sep 17 00:00:00 2001 From: sunag Date: Fri, 12 Aug 2022 01:24:13 -0300 Subject: [PATCH] New WebGLNodeBuilder + Nodes: transmission (#24453) * Cache CheckerNode if necessary * Nodes: Refactor, ior, specular, transmission nodes * update example * add transmission example * update transmission * update transmission (2) * update screenshot --- examples/files.json | 1 + .../materials/MeshPhysicalNodeMaterial.js | 16 + examples/jsm/nodes/procedural/CheckerNode.js | 4 +- .../jsm/renderers/webgl/nodes/SlotNode.js | 12 +- .../renderers/webgl/nodes/WebGLNodeBuilder.js | 533 +++++++++--------- .../jsm/renderers/webgl/nodes/WebGLNodes.js | 6 +- .../webgl/nodes/WebGLPhysicalContextNode.js | 45 -- .../webgl_nodes_loader_gltf_transmission.jpg | Bin 0 -> 43837 bytes .../webgl_nodes_loader_gltf_transmission.html | 161 ++++++ ...ebgl_nodes_materials_instance_uniform.html | 16 +- 10 files changed, 483 insertions(+), 311 deletions(-) delete mode 100644 examples/jsm/renderers/webgl/nodes/WebGLPhysicalContextNode.js create mode 100644 examples/screenshots/webgl_nodes_loader_gltf_transmission.jpg create mode 100644 examples/webgl_nodes_loader_gltf_transmission.html diff --git a/examples/files.json b/examples/files.json index 801c875cbbe2d6..84feb7a1c232b2 100644 --- a/examples/files.json +++ b/examples/files.json @@ -230,6 +230,7 @@ ], "webgl / nodes": [ "webgl_nodes_loader_gltf_iridescence", + "webgl_nodes_loader_gltf_transmission", "webgl_nodes_loader_gltf_sheen", "webgl_nodes_materials_instance_uniform", "webgl_nodes_materials_physical_clearcoat", diff --git a/examples/jsm/nodes/materials/MeshPhysicalNodeMaterial.js b/examples/jsm/nodes/materials/MeshPhysicalNodeMaterial.js index f63d0007448c97..83c201bfb820b0 100644 --- a/examples/jsm/nodes/materials/MeshPhysicalNodeMaterial.js +++ b/examples/jsm/nodes/materials/MeshPhysicalNodeMaterial.js @@ -23,6 +23,14 @@ export default class MeshPhysicalNodeMaterial extends MeshStandardNodeMaterial { this.iridescenceIORNode = null; this.iridescenceThicknessNode = null; + this.specularIntensityNode = null; + this.specularColorNode = null; + + this.transmissionNode = null; + this.thicknessNode = null; + this.attenuationDistanceNode = null; + this.attenuationColorNode = null; + this.sheen = 0; this.clearcoat = 0; this.iridescence = 0; @@ -47,6 +55,14 @@ export default class MeshPhysicalNodeMaterial extends MeshStandardNodeMaterial { this.iridescenceIORNode = source.iridescenceIORNode; this.iridescenceThicknessNode = source.iridescenceThicknessNode; + this.specularIntensityNode = source.specularIntensityNode; + this.specularColorNode = source.specularColorNode; + + this.transmissionNode = source.transmissionNode; + this.thicknessNode = source.thicknessNode; + this.attenuationDistanceNode = source.attenuationDistanceNode; + this.attenuationColorNode = source.attenuationColorNode; + return super.copy( source ); } diff --git a/examples/jsm/nodes/procedural/CheckerNode.js b/examples/jsm/nodes/procedural/CheckerNode.js index 8c449e83ca3fb5..2ffb73d639342e 100644 --- a/examples/jsm/nodes/procedural/CheckerNode.js +++ b/examples/jsm/nodes/procedural/CheckerNode.js @@ -1,4 +1,4 @@ -import Node from '../core/Node.js'; +import TempNode from '../core/TempNode.js'; import { ShaderNode, uv, add, mul, floor, mod, sign } from '../shadernode/ShaderNodeBaseElements.js'; const checkerShaderNode = new ShaderNode( ( inputs ) => { @@ -13,7 +13,7 @@ const checkerShaderNode = new ShaderNode( ( inputs ) => { } ); -class CheckerNode extends Node { +class CheckerNode extends TempNode { constructor( uvNode = uv() ) { diff --git a/examples/jsm/renderers/webgl/nodes/SlotNode.js b/examples/jsm/renderers/webgl/nodes/SlotNode.js index fbabcd37afcb16..ee797cc7419bb7 100644 --- a/examples/jsm/renderers/webgl/nodes/SlotNode.js +++ b/examples/jsm/renderers/webgl/nodes/SlotNode.js @@ -2,12 +2,16 @@ import Node from 'three-nodes/core/Node.js'; class SlotNode extends Node { - constructor( node, name, nodeType ) { + constructor( params ) { - super( nodeType ); + super( params.nodeType ); - this.node = node; - this.name = name; + this.node = null; + this.source = null; + this.target = null; + this.inclusionType = 'replace'; + + Object.assign( this, params ); } diff --git a/examples/jsm/renderers/webgl/nodes/WebGLNodeBuilder.js b/examples/jsm/renderers/webgl/nodes/WebGLNodeBuilder.js index 1cd865179657fc..eee67677514eaa 100644 --- a/examples/jsm/renderers/webgl/nodes/WebGLNodeBuilder.js +++ b/examples/jsm/renderers/webgl/nodes/WebGLNodeBuilder.js @@ -2,7 +2,6 @@ import NodeBuilder, { defaultShaderStages } from 'three-nodes/core/NodeBuilder.j import NodeFrame from 'three-nodes/core/NodeFrame.js'; import SlotNode from './SlotNode.js'; import GLSLNodeParser from 'three-nodes/parsers/GLSLNodeParser.js'; -import WebGLPhysicalContextNode from './WebGLPhysicalContextNode.js'; import { PerspectiveCamera, ShaderChunk, ShaderLib, UniformsUtils, UniformsLib, LinearEncoding, RGBAFormat, UnsignedByteType, sRGBEncoding } from 'three'; @@ -16,7 +15,7 @@ const nodeShaderLib = { MeshBasicNodeMaterial: ShaderLib.basic, PointsNodeMaterial: ShaderLib.points, MeshStandardNodeMaterial: ShaderLib.standard, - MeshPhysicalMaterial: ShaderLib.physical + MeshPhysicalNodeMaterial: ShaderLib.physical }; const glslMethods = { @@ -44,8 +43,12 @@ class WebGLNodeBuilder extends NodeBuilder { this.shader = shader; this.slots = { vertex: [], fragment: [] }; + this._parseShaderLib(); + this._parseInclude( 'fragment', 'lights_physical_fragment', 'clearcoat_normal_fragment_begin', 'transmission_fragment' ); this._parseObject(); + this._sortSlotsToFlow(); + } getMethod( method ) { @@ -58,8 +61,6 @@ class WebGLNodeBuilder extends NodeBuilder { this.slots[ shaderStage ].push( slotNode ); - return this.addFlow( shaderStage, slotNode ); - } addFlowCode( code ) { @@ -74,20 +75,12 @@ class WebGLNodeBuilder extends NodeBuilder { } - _parseObject() { - - const { material, renderer } = this; + _parseShaderLib() { - let type = material.type; + const type = this.material.type; // shader lib - if ( material.isMeshPhysicalNodeMaterial ) type = 'MeshPhysicalMaterial'; - else if ( material.isMeshStandardNodeMaterial ) type = 'MeshStandardNodeMaterial'; - else if ( material.isMeshBasicNodeMaterial ) type = 'MeshBasicNodeMaterial'; - else if ( material.isPointsNodeMaterial ) type = 'PointsNodeMaterial'; - else if ( material.isLineBasicNodeMaterial ) type = 'LineBasicNodeMaterial'; - if ( nodeShaderLib[ type ] !== undefined ) { const shaderLib = nodeShaderLib[ type ]; @@ -99,9 +92,20 @@ class WebGLNodeBuilder extends NodeBuilder { } + } + + _parseObject() { + + const { material, renderer } = this; + if ( renderer.toneMappingNode?.isNode === true ) { - this.replaceCode( 'fragment', getIncludeSnippet( 'tonemapping_fragment' ), '' ); + this.addSlot( 'fragment', new SlotNode( { + node: material.colorNode, + nodeType: 'vec4', + source: getIncludeSnippet( 'tonemapping_fragment' ), + target: '' + } ) ); } @@ -109,129 +113,308 @@ class WebGLNodeBuilder extends NodeBuilder { if ( material.colorNode && material.colorNode.isNode ) { - this.addSlot( 'fragment', new SlotNode( material.colorNode, 'COLOR', 'vec4' ) ); + this.addSlot( 'fragment', new SlotNode( { + node: material.colorNode, + nodeType: 'vec4', + source: getIncludeSnippet( 'color_fragment' ), + target: 'diffuseColor = %RESULT%;', + inclusionType: 'append' + } ) ); } if ( material.opacityNode && material.opacityNode.isNode ) { - this.addSlot( 'fragment', new SlotNode( material.opacityNode, 'OPACITY', 'float' ) ); + this.addSlot( 'fragment', new SlotNode( { + node: material.opacityNode, + nodeType: 'float', + source: getIncludeSnippet( 'alphatest_fragment' ), + target: 'diffuseColor.a = %RESULT%;', + inclusionType: 'append' + } ) ); } if ( material.normalNode && material.normalNode.isNode ) { - this.addSlot( 'fragment', new SlotNode( material.normalNode, 'NORMAL', 'vec3' ) ); + this.addSlot( 'fragment', new SlotNode( { + node: material.normalNode, + nodeType: 'vec3', + source: getIncludeSnippet( 'normal_fragment_begin' ), + target: 'normal = %RESULT%;', + inclusionType: 'append' + } ) ); } if ( material.emissiveNode && material.emissiveNode.isNode ) { - this.addSlot( 'fragment', new SlotNode( material.emissiveNode, 'EMISSIVE', 'vec3' ) ); + this.addSlot( 'fragment', new SlotNode( { + node: material.emissiveNode, + nodeType: 'vec3', + source: getIncludeSnippet( 'emissivemap_fragment' ), + target: 'totalEmissiveRadiance = %RESULT%;', + inclusionType: 'append' + } ) ); } - if ( material.metalnessNode && material.metalnessNode.isNode ) { + if ( material.isMeshStandardNodeMaterial ) { - this.addSlot( 'fragment', new SlotNode( material.metalnessNode, 'METALNESS', 'float' ) ); + if ( material.metalnessNode && material.metalnessNode.isNode ) { - } + this.addSlot( 'fragment', new SlotNode( { + node: material.metalnessNode, + nodeType: 'float', + source: getIncludeSnippet( 'metalnessmap_fragment' ), + target: 'metalnessFactor = %RESULT%;', + inclusionType: 'append' + } ) ); - if ( material.roughnessNode && material.roughnessNode.isNode ) { + } - this.addSlot( 'fragment', new SlotNode( material.roughnessNode, 'ROUGHNESS', 'float' ) ); + if ( material.roughnessNode && material.roughnessNode.isNode ) { - } + this.addSlot( 'fragment', new SlotNode( { + node: material.roughnessNode, + nodeType: 'float', + source: getIncludeSnippet( 'roughnessmap_fragment' ), + target: 'roughnessFactor = %RESULT%;', + inclusionType: 'append' + } ) ); - if ( material.isMeshPhysicalNodeMaterial ) { + } - if ( material.clearcoatNode && material.clearcoatNode.isNode ) { + if ( material.isMeshPhysicalNodeMaterial ) { - this.addSlot( 'fragment', new SlotNode( material.clearcoatNode, 'CLEARCOAT', 'float' ) ); + if ( material.clearcoatNode && material.clearcoatNode.isNode ) { - if ( material.clearcoatRoughnessNode && material.clearcoatRoughnessNode.isNode ) { + this.addSlot( 'fragment', new SlotNode( { + node: material.clearcoatNode, + nodeType: 'float', + source: 'material.clearcoat = clearcoat;', + target: 'material.clearcoat = %RESULT%;' + } ) ); - this.addSlot( 'fragment', new SlotNode( material.clearcoatRoughnessNode, 'CLEARCOAT_ROUGHNESS', 'float' ) ); + if ( material.clearcoatRoughnessNode && material.clearcoatRoughnessNode.isNode ) { - } + this.addSlot( 'fragment', new SlotNode( { + node: material.clearcoatRoughnessNode, + nodeType: 'float', + source: 'material.clearcoatRoughness = clearcoatRoughness;', + target: 'material.clearcoatRoughness = %RESULT%;' + } ) ); - if ( material.clearcoatNormalNode && material.clearcoatNormalNode.isNode ) { + } - this.addSlot( 'fragment', new SlotNode( material.clearcoatNormalNode, 'CLEARCOAT_NORMAL', 'vec3' ) ); + if ( material.clearcoatNormalNode && material.clearcoatNormalNode.isNode ) { + + this.addSlot( 'fragment', new SlotNode( { + node: material.clearcoatNormalNode, + nodeType: 'vec3', + source: 'vec3 clearcoatNormal = geometryNormal;', + target: 'vec3 clearcoatNormal = %RESULT%;' + } ) ); + + } + + material.defines.USE_CLEARCOAT = ''; + + } else { + + delete material.defines.USE_CLEARCOAT; } - material.defines.USE_CLEARCOAT = ''; + if ( material.sheenNode && material.sheenNode.isNode ) { - } else { + this.addSlot( 'fragment', new SlotNode( { + node: material.sheenNode, + nodeType: 'vec3', + source: 'material.sheenColor = sheenColor;', + target: 'material.sheenColor = %RESULT%;' + } ) ); - delete material.defines.USE_CLEARCOAT; + if ( material.sheenRoughnessNode && material.sheenRoughnessNode.isNode ) { - } + this.addSlot( 'fragment', new SlotNode( { + node: material.sheenRoughnessNode, + nodeType: 'float', + source: 'material.sheenRoughness = clamp( sheenRoughness, 0.07, 1.0 );', + target: 'material.sheenRoughness = clamp( %RESULT%, 0.07, 1.0 );' + } ) ); - if ( material.sheenNode && material.sheenNode.isNode ) { + } - this.addSlot( 'fragment', new SlotNode( material.sheenNode, 'SHEEN', 'vec3' ) ); + material.defines.USE_SHEEN = ''; - if ( material.sheenRoughnessNode && material.sheenRoughnessNode.isNode ) { + } else { - this.addSlot( 'fragment', new SlotNode( material.sheenRoughnessNode, 'SHEEN_ROUGHNESS', 'float' ) ); + delete material.defines.USE_SHEEN; } - material.defines.USE_SHEEN = ''; + if ( material.iridescenceNode && material.iridescenceNode.isNode ) { - } else { + this.addSlot( 'fragment', new SlotNode( { + node: material.iridescenceNode, + nodeType: 'float', + source: 'material.iridescence = iridescence;', + target: 'material.iridescence = %RESULT%;' + } ) ); - delete material.defines.USE_SHEEN; + if ( material.iridescenceIORNode && material.iridescenceIORNode.isNode ) { - } + this.addSlot( 'fragment', new SlotNode( { + node: material.iridescenceIORNode, + nodeType: 'float', + source: 'material.iridescenceIOR = iridescenceIOR;', + target: 'material.iridescenceIOR = %RESULT%;' + } ) ); - if ( material.iridescenceNode && material.iridescenceNode.isNode ) { + } - this.addSlot( 'fragment', new SlotNode( material.iridescenceNode, 'IRIDESCENCE', 'float' ) ); + if ( material.iridescenceThicknessNode && material.iridescenceThicknessNode.isNode ) { - if ( material.iridescenceIORNode && material.iridescenceIORNode.isNode ) { + this.addSlot( 'fragment', new SlotNode( { + node: material.iridescenceThicknessNode, + nodeType: 'float', + source: 'material.iridescenceThickness = iridescenceThicknessMaximum;', + target: 'material.iridescenceThickness = %RESULT%;' + } ) ); - this.addSlot( 'fragment', new SlotNode( material.iridescenceIORNode, 'IRIDESCENCE_IOR', 'float' ) ); + } + + material.defines.USE_IRIDESCENCE = ''; + + } else { + + delete material.defines.USE_IRIDESCENCE; } - if ( material.iridescenceThicknessNode && material.iridescenceThicknessNode.isNode ) { + if ( material.iorNode && material.iorNode.isNode ) { - this.addSlot( 'fragment', new SlotNode( material.iridescenceThicknessNode, 'IRIDESCENCE_THICKNESS', 'float' ) ); + this.addSlot( 'fragment', new SlotNode( { + node: material.iorNode, + nodeType: 'float', + source: 'material.ior = ior;', + target: 'material.ior = %RESULT%;' + } ) ); } - material.defines.USE_IRIDESCENCE = ''; + if ( material.specularColorNode && material.specularColorNode.isNode ) { - } else { + this.addSlot( 'fragment', new SlotNode( { + node: material.specularColorNode, + nodeType: 'vec3', + source: 'vec3 specularColorFactor = specularColor;', + target: 'vec3 specularColorFactor = %RESULT%;' + } ) ); - delete material.defines.USE_IRIDESCENCE; + } - } + if ( material.specularIntensityNode && material.specularIntensityNode.isNode ) { - } + this.addSlot( 'fragment', new SlotNode( { + node: material.specularIntensityNode, + nodeType: 'float', + source: 'float specularIntensityFactor = specularIntensity;', + target: 'float specularIntensityFactor = %RESULT%;' + } ) ); + + } + + if ( material.transmissionNode && material.transmissionNode.isNode ) { + + this.addSlot( 'fragment', new SlotNode( { + node: material.transmissionNode, + nodeType: 'float', + source: 'material.transmission = transmission;', + target: 'material.transmission = %RESULT%;' + } ) ); + + if ( material.thicknessNode && material.thicknessNode.isNode ) { + + this.addSlot( 'fragment', new SlotNode( { + node: material.thicknessNode, + nodeType: 'float', + source: 'material.thickness = thickness;', + target: 'material.thickness = %RESULT%;' + } ) ); + + } + + if ( material.thicknessNode && material.thicknessNode.isNode ) { + + this.addSlot( 'fragment', new SlotNode( { + node: material.thicknessNode, + nodeType: 'float', + source: 'material.thickness = thickness;', + target: 'material.thickness = %RESULT%;' + } ) ); + + } + + if ( material.attenuationDistanceNode && material.attenuationDistanceNode.isNode ) { + + this.addSlot( 'fragment', new SlotNode( { + node: material.attenuationDistanceNode, + nodeType: 'float', + source: 'material.attenuationDistance = attenuationDistance;', + target: 'material.attenuationDistance = %RESULT%;' + } ) ); + + } + + if ( material.attenuationColorNode && material.attenuationColorNode.isNode ) { + + this.addSlot( 'fragment', new SlotNode( { + node: material.attenuationColorNode, + nodeType: 'vec3', + source: 'material.attenuationColor = attenuationColor;', + target: 'material.attenuationColor = %RESULT%;' + } ) ); + + } + + material.transmission = 1; + material.defines.USE_TRANSMISSION = ''; + + } else { - if ( material.envNode && material.envNode.isNode ) { + material.transmission = 0; + delete material.defines.USE_TRANSMISSION; - const envRadianceNode = new WebGLPhysicalContextNode( WebGLPhysicalContextNode.RADIANCE, material.envNode ); - const envIrradianceNode = new WebGLPhysicalContextNode( WebGLPhysicalContextNode.IRRADIANCE, material.envNode ); + } - this.addSlot( 'fragment', new SlotNode( envRadianceNode, 'RADIANCE', 'vec3' ) ); - this.addSlot( 'fragment', new SlotNode( envIrradianceNode, 'IRRADIANCE', 'vec3' ) ); + } } + // + if ( material.positionNode && material.positionNode.isNode ) { - this.addSlot( 'vertex', new SlotNode( material.positionNode, 'POSITION', 'vec3' ) ); + this.addSlot( 'vertex', new SlotNode( { + node: material.positionNode, + nodeType: 'vec3', + source: getIncludeSnippet( 'begin_vertex' ), + target: 'transformed = %RESULT%;', + inclusionType: 'append' + } ) ); } if ( material.sizeNode && material.sizeNode.isNode ) { - this.addSlot( 'vertex', new SlotNode( material.sizeNode, 'SIZE', 'float' ) ); + this.addSlot( 'vertex', new SlotNode( { + node: material.sizeNode, + nodeType: 'float', + source: 'gl_PointSize = size;', + target: 'gl_PointSize = %RESULT%;' + } ) ); } @@ -335,7 +518,7 @@ class WebGLNodeBuilder extends NodeBuilder { } - addCodeAfterSnippet( shaderStage, snippet, code ) { + addCodeAfterCode( shaderStage, snippet, code ) { const shaderProperty = getShaderStageProperty( shaderStage ); @@ -356,14 +539,6 @@ class WebGLNodeBuilder extends NodeBuilder { } - addCodeAfterInclude( shaderStage, includeName, code ) { - - const includeSnippet = getIncludeSnippet( includeName ); - - this.addCodeAfterSnippet( shaderStage, includeSnippet, code ); - - } - replaceCode( shaderStage, source, target ) { const shaderProperty = getShaderStageProperty( shaderStage ); @@ -372,19 +547,6 @@ class WebGLNodeBuilder extends NodeBuilder { } - parseInclude( shaderStage, ...includes ) { - - for ( const name of includes ) { - - const includeSnippet = getIncludeSnippet( name ); - const code = ShaderChunk[ name ]; - - this.replaceCode( shaderStage, includeSnippet, code ); - - } - - } - getTextureEncodingFromMap( map ) { const isWebGL2 = this.renderer.capabilities.isWebGL2; @@ -463,208 +625,77 @@ ${this.shader[ getShaderStageProperty( shaderStage ) ]} } - getSlot( shaderStage, name ) { - - const slots = this.slots[ shaderStage ]; + _parseInclude( shaderStage, ...includes ) { - for ( const node of slots ) { + for ( const name of includes ) { - if ( node.name === name ) { + const includeSnippet = getIncludeSnippet( name ); + const code = ShaderChunk[ name ]; - return this.getFlowData( node/*, shaderStage*/ ); + const shaderProperty = getShaderStageProperty( shaderStage ); - } + this.shader[ shaderProperty ] = this.shader[ shaderProperty ].replaceAll( includeSnippet, code ); } } - _addSnippets() { - - this.parseInclude( 'fragment', 'lights_physical_fragment' ); - this.parseInclude( 'fragment', 'clearcoat_normal_fragment_begin' ); - - const colorSlot = this.getSlot( 'fragment', 'COLOR' ); - const opacityNode = this.getSlot( 'fragment', 'OPACITY' ); - const normalSlot = this.getSlot( 'fragment', 'NORMAL' ); - const emissiveNode = this.getSlot( 'fragment', 'EMISSIVE' ); - const roughnessNode = this.getSlot( 'fragment', 'ROUGHNESS' ); - const metalnessNode = this.getSlot( 'fragment', 'METALNESS' ); - const clearcoatNode = this.getSlot( 'fragment', 'CLEARCOAT' ); - const clearcoatRoughnessNode = this.getSlot( 'fragment', 'CLEARCOAT_ROUGHNESS' ); - const clearcoatNormalNode = this.getSlot( 'fragment', 'CLEARCOAT_NORMAL' ); - const sheenNode = this.getSlot( 'fragment', 'SHEEN' ); - const sheenRoughnessNode = this.getSlot( 'fragment', 'SHEEN_ROUGHNESS' ); - const iridescenceNode = this.getSlot( 'fragment', 'IRIDESCENCE' ); - const iridescenceIORNode = this.getSlot( 'fragment', 'IRIDESCENCE_IOR' ); - const iridescenceThicknessNode = this.getSlot( 'fragment', 'IRIDESCENCE_THICKNESS' ); - - const positionNode = this.getSlot( 'vertex', 'POSITION' ); - const sizeNode = this.getSlot( 'vertex', 'SIZE' ); - - if ( colorSlot !== undefined ) { - - this.addCodeAfterInclude( - 'fragment', - 'color_fragment', - `${colorSlot.code}\n\tdiffuseColor = ${colorSlot.result};` - ); - - } - - if ( opacityNode !== undefined ) { - - this.addCodeAfterInclude( - 'fragment', - 'alphatest_fragment', - `${opacityNode.code}\n\tdiffuseColor.a = ${opacityNode.result};` - ); - - } - - if ( normalSlot !== undefined ) { - - this.addCodeAfterInclude( - 'fragment', - 'normal_fragment_begin', - `${normalSlot.code}\n\tnormal = ${normalSlot.result};` - ); - - } + _sortSlotsToFlow() { - if ( emissiveNode !== undefined ) { - - this.addCodeAfterInclude( - 'fragment', - 'emissivemap_fragment', - `${emissiveNode.code}\n\ttotalEmissiveRadiance = ${emissiveNode.result};` - ); - - } - - if ( roughnessNode !== undefined ) { - - this.addCodeAfterInclude( - 'fragment', - 'roughnessmap_fragment', - `${roughnessNode.code}\n\troughnessFactor = ${roughnessNode.result};` - ); - - } - - if ( metalnessNode !== undefined ) { - - this.addCodeAfterInclude( - 'fragment', - 'metalnessmap_fragment', - `${metalnessNode.code}\n\tmetalnessFactor = ${metalnessNode.result};` - ); - - } - - if ( clearcoatNode !== undefined ) { - - this.addCodeAfterSnippet( - 'fragment', - 'material.clearcoat = clearcoat;', - `${clearcoatNode.code}\n\tmaterial.clearcoat = ${clearcoatNode.result};` - ); - - if ( clearcoatRoughnessNode !== undefined ) { - - this.addCodeAfterSnippet( - 'fragment', - 'material.clearcoatRoughness = clearcoatRoughness;', - `${clearcoatRoughnessNode.code}\n\tmaterial.clearcoatRoughness = ${clearcoatRoughnessNode.result};` - ); - - } - - if ( clearcoatNormalNode !== undefined ) { + for ( const shaderStage of defaultShaderStages ) { - this.addCodeAfterSnippet( - 'fragment', - 'vec3 clearcoatNormal = geometryNormal;', - `${clearcoatNormalNode.code}\n\tclearcoatNormal = ${clearcoatNormalNode.result};` - ); + const sourceCode = this.shader[ getShaderStageProperty( shaderStage ) ]; - } + const slots = this.slots[ shaderStage ].sort( ( slotA, slotB ) => { - } + if ( sourceCode.indexOf( slotA.source ) == - 1 ) { + //console.log( slotA, sourceCode.indexOf( slotA.source ), sourceCode.indexOf( slotB.source ) ); + //console.log(sourceCode); + } - if ( sheenNode !== undefined ) { + return sourceCode.indexOf( slotA.source ) > sourceCode.indexOf( slotB.source ) ? 1 : - 1; - this.addCodeAfterSnippet( - 'fragment', - 'material.sheenColor = sheenColor;', - `${sheenNode.code}\n\tmaterial.sheenColor = ${sheenNode.result};` - ); + } ); - if ( sheenRoughnessNode !== undefined ) { + for ( const slotNode of slots ) { - this.replaceCode( - 'fragment', - 'material.sheenRoughness = clamp( sheenRoughness, 0.07, 1.0 );', - `${sheenRoughnessNode.code}\n\tmaterial.sheenRoughness = clamp( ${sheenRoughnessNode.result}, 0.07, 1.0 );` - ); + this.addFlow( shaderStage, slotNode ); } } - if ( iridescenceNode !== undefined ) { - - this.addCodeAfterSnippet( - 'fragment', - 'material.iridescence = iridescence;', - `${iridescenceNode.code}\n\tmaterial.iridescence = ${iridescenceNode.result};` - ); - - } + } - if ( iridescenceIORNode !== undefined ) { + _addSnippets() { - this.addCodeAfterSnippet( - 'fragment', - 'material.iridescenceIOR = iridescenceIOR;', - `${iridescenceIORNode.code}\n\tmaterial.iridescenceIOR = ${iridescenceIORNode.result};` - ); + for ( const shaderStage of defaultShaderStages ) { - } + for ( const slotNode of this.slots[ shaderStage ] ) { - if ( iridescenceThicknessNode !== undefined ) { + const flowData = this.getFlowData( slotNode/*, shaderStage*/ ); - this.addCodeAfterSnippet( - 'fragment', - 'material.iridescenceThickness = iridescenceThicknessMaximum;', - `${iridescenceThicknessNode.code}\n\tmaterial.iridescenceThickness = ${iridescenceThicknessNode.result};` - ); + const inclusionType = slotNode.inclusionType; + const source = slotNode.source; + const target = flowData.code + '\n\t' + slotNode.target.replace( '%RESULT%', flowData.result ); - } + if ( inclusionType === 'append' ) { - if ( positionNode !== undefined ) { + this.addCodeAfterCode( shaderStage, source, target ); - this.addCodeAfterInclude( - 'vertex', - 'begin_vertex', - `${positionNode.code}\n\ttransformed = ${positionNode.result};` - ); + } else if ( inclusionType === 'replace' ) { - } + this.replaceCode( shaderStage, source, target ); - if ( sizeNode !== undefined ) { + } else { - this.addCodeAfterSnippet( - 'vertex', - 'gl_PointSize = size;', - `${sizeNode.code}\n\tgl_PointSize = ${sizeNode.result};` - ); + console.warn( `Inclusion type "${ inclusionType }" not compatible.` ); - } + } - for ( const shaderStage of defaultShaderStages ) { + } - this.addCodeAfterSnippet( + this.addCodeAfterCode( shaderStage, 'main() {', this.flowCode[ shaderStage ] diff --git a/examples/jsm/renderers/webgl/nodes/WebGLNodes.js b/examples/jsm/renderers/webgl/nodes/WebGLNodes.js index 830173b24a4e0a..92b65ae84523ea 100644 --- a/examples/jsm/renderers/webgl/nodes/WebGLNodes.js +++ b/examples/jsm/renderers/webgl/nodes/WebGLNodes.js @@ -8,7 +8,11 @@ export const nodeFrame = new NodeFrame(); Material.prototype.onBuild = function ( object, parameters, renderer ) { - builders.set( this, new WebGLNodeBuilder( object, renderer, parameters ).build() ); + if ( object.material.isNodeMaterial === true ) { + + builders.set( this, new WebGLNodeBuilder( object, renderer, parameters ).build() ); + + } }; diff --git a/examples/jsm/renderers/webgl/nodes/WebGLPhysicalContextNode.js b/examples/jsm/renderers/webgl/nodes/WebGLPhysicalContextNode.js deleted file mode 100644 index 635be8db420f98..00000000000000 --- a/examples/jsm/renderers/webgl/nodes/WebGLPhysicalContextNode.js +++ /dev/null @@ -1,45 +0,0 @@ -import ContextNode from 'three-nodes/core/ContextNode.js'; -import NormalNode from 'three-nodes/accessors/NormalNode.js'; -import ExpressionNode from 'three-nodes/core/ExpressionNode.js'; -import ConstNode from 'three-nodes/core/ConstNode.js'; - -class WebGLPhysicalContextNode extends ContextNode { - - static RADIANCE = 'radiance'; - static IRRADIANCE = 'irradiance'; - - constructor( scope, node ) { - - super( node, 'vec3' ); - - this.scope = scope; - - } - - generate( builder, output ) { - - const scope = this.scope; - - let roughness = null; - - if ( scope === WebGLPhysicalContextNode.RADIANCE ) { - - roughness = new ExpressionNode( 'roughnessFactor', 'float' ); - - } else if ( scope === WebGLPhysicalContextNode.IRRADIANCE ) { - - roughness = new ConstNode( 1 ); - - this.context.uv = new NormalNode( NormalNode.WORLD ); - - } - - this.context.roughness = roughness; - - return super.generate( builder, output ); - - } - -} - -export default WebGLPhysicalContextNode; diff --git a/examples/screenshots/webgl_nodes_loader_gltf_transmission.jpg b/examples/screenshots/webgl_nodes_loader_gltf_transmission.jpg new file mode 100644 index 0000000000000000000000000000000000000000..be97b2955bb8abc643e07aa32aaee70716c03dbc GIT binary patch literal 43837 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%0AG>NER6$jM^T8JH_Xdhx{$ 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 RkCkK~b*C5a8C6Qh|JkNRwFUqH literal 0 HcmV?d00001 diff --git a/examples/webgl_nodes_loader_gltf_transmission.html b/examples/webgl_nodes_loader_gltf_transmission.html new file mode 100644 index 00000000000000..4531ec3011bd57 --- /dev/null +++ b/examples/webgl_nodes_loader_gltf_transmission.html @@ -0,0 +1,161 @@ + + + + three.js webgl - GLTFloader + transmission + nodes + + + + + + +
+ three.js - GLTFLoader + KHR_materials_transmission + Nodes
+ Iridescent Dish With Olives by Eric Chadwick
+ Royal Esplanade by HDRI Haven +
+ + + + + + + + + + + diff --git a/examples/webgl_nodes_materials_instance_uniform.html b/examples/webgl_nodes_materials_instance_uniform.html index 9f9d58438c4fb0..97ff1118302448 100644 --- a/examples/webgl_nodes_materials_instance_uniform.html +++ b/examples/webgl_nodes_materials_instance_uniform.html @@ -27,8 +27,8 @@