diff --git a/examples/jsm/inspector/Inspector.js b/examples/jsm/inspector/Inspector.js index d16288131df069..18d66407d5ddbd 100644 --- a/examples/jsm/inspector/Inspector.js +++ b/examples/jsm/inspector/Inspector.js @@ -4,9 +4,11 @@ import { Profiler } from './ui/Profiler.js'; import { Performance } from './tabs/Performance.js'; import { Console } from './tabs/Console.js'; import { Parameters } from './tabs/Parameters.js'; -import { setText, ease } from './ui/utils.js'; +import { Viewer } from './tabs/Viewer.js'; +import { setText, ease, splitPath, splitCamelCase } from './ui/utils.js'; -import { setConsoleFunction, REVISION } from 'three/webgpu'; +import { QuadMesh, NodeMaterial, CanvasTarget, setConsoleFunction, REVISION, NoToneMapping } from 'three/webgpu'; +import { renderOutput, vec3, vec4 } from 'three/tsl'; const EASE_FACTOR = 0.1; @@ -24,6 +26,9 @@ class Inspector extends RendererInspector { parameters.hide(); profiler.addTab( parameters ); + const viewer = new Viewer(); + profiler.addTab( viewer ); + const performance = new Performance(); profiler.addTab( performance ); @@ -38,10 +43,12 @@ class Inspector extends RendererInspector { this.softDeltaTime = 0; this.statsData = new Map(); + this.canvasNodes = new Map(); this.profiler = profiler; this.performance = performance; this.console = console; this.parameters = parameters; + this.viewer = viewer; this.once = {}; this.displayCycle = { @@ -247,6 +254,63 @@ class Inspector extends RendererInspector { } + getCanvasDataByNode( node ) { + + let canvasData = this.canvasNodes.get( node ); + + if ( canvasData === undefined ) { + + const renderer = this.getRenderer(); + + const canvas = document.createElement( 'canvas' ); + + const canvasTarget = new CanvasTarget( canvas ); + canvasTarget.setPixelRatio( window.devicePixelRatio ); + canvasTarget.setSize( 140, 140 ); + + const id = node.id; + + const { path, name } = splitPath( splitCamelCase( node.getName() || '(unnamed)' ) ); + + let output = vec4( vec3( node ), 1 ); + output = renderOutput( output, NoToneMapping, renderer.outputColorSpace ); + output = output.context( { inspector: true } ); + + const material = new NodeMaterial(); + material.outputNode = output; + + const quad = new QuadMesh( material ); + quad.name = 'Inspector - ' + name; + + canvasData = { + id, + name, + path, + node, + quad, + canvasTarget, + material + }; + + this.canvasNodes.set( node, canvasData ); + + } + + return canvasData; + + } + + resolveViewer() { + + const nodes = this.currentNodes; + + const renderer = this.getRenderer(); + const canvasDataList = nodes.map( node => this.getCanvasDataByNode( node ) ); + + this.viewer.update( renderer, canvasDataList ); + + } + resolveFrame( frame ) { const nextFrame = this.getFrameById( frame.frameId + 1 ); @@ -278,7 +342,7 @@ class Inspector extends RendererInspector { // Frame desync, probably due to async GPU timing. - return; + frame.miscellaneous = 0; } @@ -298,7 +362,7 @@ class Inspector extends RendererInspector { if ( this.displayCycle.text.needsUpdate ) { - setText( 'fps-counter', this.fps.toFixed() ); + setText( 'fps-counter', this.softFPS.toFixed() ); this.performance.updateText( this, frame ); diff --git a/examples/jsm/inspector/RendererInspector.js b/examples/jsm/inspector/RendererInspector.js index 5dc61396cccda5..3bf16528c331ec 100644 --- a/examples/jsm/inspector/RendererInspector.js +++ b/examples/jsm/inspector/RendererInspector.js @@ -73,6 +73,7 @@ export class RendererInspector extends InspectorBase { this.currentFrame = null; this.currentRender = null; + this.currentNodes = null; this.frames = []; this.framesLib = {}; @@ -89,6 +90,7 @@ export class RendererInspector extends InspectorBase { this.currentFrame = this._createFrame(); this.currentRender = this.currentFrame; + this.currentNodes = []; } @@ -104,6 +106,7 @@ export class RendererInspector extends InspectorBase { this.currentFrame = null; this.currentRender = null; + this.currentNodes = null; this._lastFinishTime = now; @@ -138,6 +141,8 @@ export class RendererInspector extends InspectorBase { } + resolveViewer() { } + resolveFrame( /*frame*/ ) { } async resolveTimestamp() { @@ -266,12 +271,19 @@ export class RendererInspector extends InspectorBase { if ( this.isAvailable ) { + this.resolveViewer(); this.resolveTimestamp(); } } + inspect( node ) { + + this.currentNodes.push( node ); + + } + beginCompute( uid, computeNode ) { const frame = this.getFrame(); diff --git a/examples/jsm/inspector/tabs/Performance.js b/examples/jsm/inspector/tabs/Performance.js index 856e7c7346718a..0d5bc9d734b840 100644 --- a/examples/jsm/inspector/tabs/Performance.js +++ b/examples/jsm/inspector/tabs/Performance.js @@ -57,7 +57,7 @@ class Performance extends Tab { const frameStats = new Item( 'Frame Stats', createValueSpan(), createValueSpan(), createValueSpan() ); perfList.add( frameStats ); - const miscellaneous = new Item( 'Miscellaneous / Idle', createValueSpan(), createValueSpan(), createValueSpan() ); + const miscellaneous = new Item( 'Miscellaneous & Idle', createValueSpan(), createValueSpan(), createValueSpan() ); miscellaneous.domElement.firstChild.style.backgroundColor = '#00ff0b1a'; miscellaneous.domElement.firstChild.classList.add( 'no-hover' ); frameStats.add( miscellaneous ); @@ -235,7 +235,7 @@ class Performance extends Tab { // - setText( 'graph-fps-counter', inspector.fps.toFixed() + ' FPS' ); + setText( 'graph-fps-counter', inspector.softFPS.toFixed() + ' FPS' ); // @@ -248,6 +248,7 @@ class Performance extends Tab { setText( this.miscellaneous.data[ 1 ], frame.miscellaneous.toFixed( 2 ) ); setText( this.miscellaneous.data[ 2 ], '-' ); setText( this.miscellaneous.data[ 3 ], frame.miscellaneous.toFixed( 2 ) ); + // this.currentItem = null; diff --git a/examples/jsm/inspector/tabs/Viewer.js b/examples/jsm/inspector/tabs/Viewer.js new file mode 100644 index 00000000000000..5b5f78159eb358 --- /dev/null +++ b/examples/jsm/inspector/tabs/Viewer.js @@ -0,0 +1,166 @@ +import { Tab } from '../ui/Tab.js'; +import { List } from '../ui/List.js'; +import { Item } from '../ui/Item.js'; + +import { RendererUtils, NoToneMapping, LinearSRGBColorSpace } from 'three/webgpu'; + +class Viewer extends Tab { + + constructor() { + + super( 'Viewer' ); + + const nodeList = new List( 'Viewer', 'Name' ); + nodeList.setGridStyle( '150px minmax(200px, 2fr)' ); + nodeList.domElement.style.minWidth = '600px'; + + const scrollWrapper = document.createElement( 'div' ); + scrollWrapper.className = 'list-scroll-wrapper'; + scrollWrapper.appendChild( nodeList.domElement ); + this.content.appendChild( scrollWrapper ); + + const nodes = new Item( 'Nodes' ); + nodeList.add( nodes ); + + // + + this.itemLibrary = new Map(); + this.folderLibrary = new Map(); + this.currentDataList = []; + this.nodeList = nodeList; + this.nodes = nodes; + + } + + getFolder( name ) { + + let folder = this.folderLibrary.get( name ); + + if ( folder === undefined ) { + + folder = new Item( name ); + + this.folderLibrary.set( name, folder ); + this.nodeList.add( folder ); + + } + + return folder; + + } + + addNodeItem( canvasData ) { + + let item = this.itemLibrary.get( canvasData.id ); + + if ( item === undefined ) { + + const name = canvasData.name; + const domElement = canvasData.canvasTarget.domElement; + + item = new Item( domElement, name ); + item.itemRow.children[ 1 ].style[ 'justify-content' ] = 'flex-start'; + this.itemLibrary.set( canvasData.id, item ); + + } + + return item; + + } + + update( renderer, canvasDataList ) { + + if ( ! this.isActive ) return; + + // + + const previousDataList = [ ...this.currentDataList ]; + + // remove old + + for ( const canvasData of previousDataList ) { + + if ( this.itemLibrary.has( canvasData.id ) && canvasDataList.indexOf( canvasData ) === - 1 ) { + + const item = this.itemLibrary.get( canvasData.id ); + const parent = item.parent; + + parent.remove( item ); + + if ( this.folderLibrary.has( parent.data[ 0 ] ) && parent.children.length === 0 ) { + + parent.parent.remove( parent ); + + this.folderLibrary.delete( parent.data[ 0 ] ); + + } + + this.itemLibrary.delete( canvasData.id ); + + } + + } + + // + + const indexes = {}; + + for ( const canvasData of canvasDataList ) { + + const item = this.addNodeItem( canvasData ); + const previousCanvasTarget = renderer.getCanvasTarget(); + + const path = canvasData.path; + + if ( path ) { + + const folder = this.getFolder( path ); + + if ( indexes[ path ] === undefined ) { + + indexes[ path ] = 0; + + } + + if ( folder.parent === null || item.parent !== folder || folder.children.indexOf( item ) !== indexes[ path ] ) { + + folder.add( item ); + + } + + indexes[ path ] ++; + + } else { + + if ( ! item.parent ) { + + this.nodes.add( item ); + + } + + } + + this.currentDataList = canvasDataList; + + // + + const state = RendererUtils.resetRendererState( renderer ); + + renderer.toneMapping = NoToneMapping; + renderer.outputColorSpace = LinearSRGBColorSpace; + + renderer.setCanvasTarget( canvasData.canvasTarget ); + + canvasData.quad.render( renderer ); + + renderer.setCanvasTarget( previousCanvasTarget ); + + RendererUtils.restoreRendererState( renderer, state ); + + } + + } + +} + +export { Viewer }; diff --git a/examples/jsm/inspector/ui/Style.js b/examples/jsm/inspector/ui/Style.js index 6721a0a02f3ec6..9fe9862ff4d3af 100644 --- a/examples/jsm/inspector/ui/Style.js +++ b/examples/jsm/inspector/ui/Style.js @@ -348,7 +348,7 @@ export class Style { .item-toggler { display: inline-block; - width: 1.5em; + margin-right: 0.8em; text-align: left; } diff --git a/examples/jsm/inspector/ui/Tab.js b/examples/jsm/inspector/ui/Tab.js index 25f598bb5fb5df..1321f2d3ee88dd 100644 --- a/examples/jsm/inspector/ui/Tab.js +++ b/examples/jsm/inspector/ui/Tab.js @@ -11,6 +11,7 @@ export class Tab { this.content.id = `${this.id}-content`; this.content.className = 'profiler-content'; + this.isActive = false; this.isVisible = true; } @@ -20,6 +21,8 @@ export class Tab { this.button.classList.toggle( 'active', isActive ); this.content.classList.toggle( 'active', isActive ); + this.isActive = isActive; + } show() { diff --git a/examples/jsm/inspector/ui/utils.js b/examples/jsm/inspector/ui/utils.js index 99a51d493eef98..3b450d8e3f7558 100644 --- a/examples/jsm/inspector/ui/utils.js +++ b/examples/jsm/inspector/ui/utils.js @@ -40,3 +40,29 @@ export function getText( element ) { return el ? el.textContent : null; } + +export function splitPath( fullPath ) { + + const lastSlash = fullPath.lastIndexOf( '/' ); + + if ( lastSlash === - 1 ) { + + return { + path: '', + name: fullPath.trim() + }; + + } + + const path = fullPath.substring( 0, lastSlash ).trim(); + const name = fullPath.substring( lastSlash + 1 ).trim(); + + return { path, name }; + +} + +export function splitCamelCase( str ) { + + return str.replace( /([a-z0-9])([A-Z])/g, '$1 $2' ).trim(); + +} diff --git a/examples/webgpu_backdrop_water.html b/examples/webgpu_backdrop_water.html index d2ea239782129e..1c33d766b5f279 100644 --- a/examples/webgpu_backdrop_water.html +++ b/examples/webgpu_backdrop_water.html @@ -150,10 +150,10 @@ // linearDepth() returns the linear depth of the mesh const depth = linearDepth(); - const depthWater = viewportLinearDepth.sub( depth ); + const depthWater = viewportLinearDepth.sub( depth ).toInspector( 'Water / Depth', ( node ) => node.oneMinus() ); const depthEffect = depthWater.remapClamp( - .002, .04 ); - const refractionUV = screenUV.add( vec2( 0, waterIntensity.mul( .1 ) ) ); + const refractionUV = screenUV.add( vec2( 0, waterIntensity.mul( .1 ) ) ).toInspector( 'Water / Refraction UV' ); // linearDepth( viewportDepthTexture( uv ) ) return the linear depth of the scene const depthTestForRefraction = linearDepth( viewportDepthTexture( refractionUV ) ).sub( depth ); @@ -162,10 +162,10 @@ const finalUV = depthTestForRefraction.lessThan( 0 ).select( screenUV, refractionUV ); - const viewportTexture = viewportSharedTexture( finalUV ); + const viewportTexture = viewportSharedTexture( finalUV ).toInspector( 'Water / Viewport Texture + Refraction UV' ); const waterMaterial = new THREE.MeshBasicNodeMaterial(); - waterMaterial.colorNode = waterColor; + waterMaterial.colorNode = waterColor.toInspector( 'Water / Color' ); waterMaterial.backdropNode = depthEffect.mix( viewportSharedTexture(), viewportTexture.mul( depthRefraction.mix( 1, waterColor ) ) ); waterMaterial.backdropAlphaNode = depthRefraction.oneMinus(); waterMaterial.transparent = true; @@ -224,12 +224,12 @@ const scenePassColor = scenePass.getTextureNode(); const scenePassDepth = scenePass.getLinearDepthNode().remapClamp( .3, .5 ); - const waterMask = objectPosition( camera ).y.greaterThan( screenUV.y.sub( .5 ).mul( camera.near ) ); + const waterMask = objectPosition( camera ).y.greaterThan( screenUV.y.sub( .5 ).mul( camera.near ) ).toInspector( 'Post-Processing / Water Mask' ); const scenePassColorBlurred = gaussianBlur( scenePassColor ); - scenePassColorBlurred.directionNode = waterMask.select( scenePassDepth, scenePass.getLinearDepthNode().mul( 5 ) ); + scenePassColorBlurred.directionNode = waterMask.select( scenePassDepth, scenePass.getLinearDepthNode().mul( 5 ) ).toInspector( 'Post-Processing / Blur Strength [ Depth ]', ( node ) => node.toFloat() ); - const vignette = screenUV.distance( .5 ).mul( 1.35 ).clamp().oneMinus(); + const vignette = screenUV.distance( .5 ).mul( 1.35 ).clamp().oneMinus().toInspector( 'Post-Processing / Vignette' ); postProcessing = new THREE.PostProcessing( renderer ); postProcessing.outputNode = waterMask.select( scenePassColorBlurred, scenePassColorBlurred.mul( color( 0x74ccf4 ) ).mul( vignette ) ); diff --git a/examples/webgpu_postprocessing_ssgi.html b/examples/webgpu_postprocessing_ssgi.html index 92a76c02de5e20..ebebad9e3652da 100644 --- a/examples/webgpu_postprocessing_ssgi.html +++ b/examples/webgpu_postprocessing_ssgi.html @@ -57,10 +57,8 @@ renderer.setSize( window.innerWidth, window.innerHeight ); renderer.setAnimationLoop( animate ); renderer.shadowMap.enabled = true; - document.body.appendChild( renderer.domElement ); - renderer.inspector = new Inspector(); - document.body.appendChild( renderer.inspector.domElement ); + document.body.appendChild( renderer.domElement ); // @@ -84,10 +82,15 @@ } ) ); const scenePassColor = scenePass.getTextureNode( 'output' ); - const scenePassDiffuse = scenePass.getTextureNode( 'diffuseColor' ); - const scenePassDepth = scenePass.getTextureNode( 'depth' ); - const scenePassNormal = scenePass.getTextureNode( 'normal' ); - const scenePassVelocity = scenePass.getTextureNode( 'velocity' ); + const scenePassDiffuse = scenePass.getTextureNode( 'diffuseColor' ).toInspector( 'Diffuse Color' ); + const scenePassDepth = scenePass.getTextureNode( 'depth' ).toInspector( 'Depth', () => { + + return scenePass.getLinearDepthNode(); + + } ); + + const scenePassNormal = scenePass.getTextureNode( 'normal' ).toInspector( 'Normal' ); + const scenePassVelocity = scenePass.getTextureNode( 'velocity' ).toInspector( 'Velocity' ); // bandwidth optimization @@ -111,8 +114,8 @@ // composite - const gi = giPass.rgb; - const ao = giPass.a; + const gi = giPass.rgb.toInspector( 'SSGI' ); + const ao = giPass.a.toInspector( 'AO' ); const compositePass = vec4( add( scenePassColor.rgb.mul( ao ), ( scenePassDiffuse.rgb.mul( gi ) ) ), scenePassColor.a ); compositePass.name = 'Composite'; diff --git a/examples/webgpu_volume_caustics.html b/examples/webgpu_volume_caustics.html index 24cb504543a3a9..ad7f864751ab94 100644 --- a/examples/webgpu_volume_caustics.html +++ b/examples/webgpu_volume_caustics.html @@ -270,8 +270,11 @@ // Scene Pass - const scenePass = pass( scene, camera ); + const scenePass = pass( scene, camera ).toInspector(); + scenePass.name = 'Scene'; + const sceneDepth = scenePass.getTextureNode( 'depth' ); + sceneDepth.name = 'Scene Depth'; // Material - Apply occlusion depth of volumetric lighting based on the scene depth @@ -279,14 +282,15 @@ // Volumetric Lighting Pass - const volumetricPass = pass( scene, camera, { depthBuffer: false } ); + const volumetricPass = pass( scene, camera, { depthBuffer: false, samples: 0 } ).toInspector( 'Volumetric Lighting / Raw' ); volumetricPass.name = 'Volumetric Lighting'; volumetricPass.setLayers( volumetricLayer ); volumetricPass.setResolutionScale( .5 ); // Compose and Denoise - const bloomPass = bloom( volumetricPass, 1, 1, 0 ); + const bloomPass = bloom( volumetricPass, 1, 1, 0 ).toInspector( 'Volumetric Lighting / Mip-Chain Gaussian Blur' ); + bloomPass.name = 'Bloom'; const scenePassColor = scenePass.add( bloomPass.mul( volumetricLightingIntensity ) ); diff --git a/src/nodes/core/InspectorNode.js b/src/nodes/core/InspectorNode.js new file mode 100644 index 00000000000000..80ac36f969eb89 --- /dev/null +++ b/src/nodes/core/InspectorNode.js @@ -0,0 +1,120 @@ +import Node from './Node.js'; +import { addMethodChaining, nodeObject } from '../tsl/TSLCore.js'; +import { NodeUpdateType } from './constants.js'; + +/** + * InspectorNode is a wrapper node that allows inspection of node values during rendering. + * It can be used to debug or analyze node outputs in the rendering pipeline. + * + * @augments Node + */ +class InspectorNode extends Node { + + /** + * Returns the type of the node. + * + * @returns {string} + */ + static get type() { + + return 'InspectorNode'; + + } + + /** + * Creates an InspectorNode. + * + * @param {Node} node - The node to inspect. + * @param {string} [name=''] - Optional name for the inspector node. + * @param {Function|null} [callback=null] - Optional callback to modify the node during setup. + */ + constructor( node, name = '', callback = null ) { + + super(); + + this.node = node; + this.name = name; + this.callback = callback; + + this.updateType = NodeUpdateType.FRAME; + + this.isInspectorNode = true; + + } + + /** + * Returns the name of the inspector node. + * + * @returns {string} + */ + getName() { + + return this.name || this.node.name; + + } + + /** + * Updates the inspector node, allowing inspection of the wrapped node. + * + * @param {NodeFrame} frame - A reference to the current node frame. + */ + update( frame ) { + + frame.renderer.inspector.inspect( this ); + + } + + /** + * Returns the type of the wrapped node. + * + * @param {NodeBuilder} builder - The node builder. + * @returns {string} + */ + getNodeType( builder ) { + + return this.node.getNodeType( builder ); + + } + + /** + * Sets up the inspector node. + * + * @param {NodeBuilder} builder - The node builder. + * @returns {Node} The setup node. + */ + setup( builder ) { + + let node = this.node; + + if ( builder.context.inspector === true && this.callback !== null ) { + + node = this.callback( node ); + + } + + return node; + + } + +} + +export default InspectorNode; + +/** + * Creates an inspector node to wrap around a given node for inspection purposes. + * + * @tsl + * @param {Node} node - The node to inspect. + * @param {string} [name=''] - Optional name for the inspector node. + * @param {Function|null} [callback=null] - Optional callback to modify the node during setup. + * @returns {Node} The inspector node. + */ +export function inspector( node, name = '', callback = null ) { + + node = nodeObject( node ); + + return node.before( new InspectorNode( node, name, callback ) ); + +} + +addMethodChaining( 'toInspector', inspector ); diff --git a/src/nodes/core/Node.js b/src/nodes/core/Node.js index 588723180236a0..a7500368eb27d5 100644 --- a/src/nodes/core/Node.js +++ b/src/nodes/core/Node.js @@ -120,6 +120,8 @@ class Node extends EventDispatcher { // private + this._beforeNodes = null; + /** * The cache key of this node. * @@ -615,6 +617,16 @@ class Node extends EventDispatcher { } + before( node ) { + + if ( this._beforeNodes === null ) this._beforeNodes = []; + + this._beforeNodes.push( node ); + + return this; + + } + /** * This method performs the build of a node. The behavior and return value depend on the current build stage: * - **setup**: Prepares the node and its children for the build process. This process can also create new nodes. Returns the node itself or a variant. @@ -637,6 +649,24 @@ class Node extends EventDispatcher { // + if ( this._beforeNodes !== null ) { + + const currentBeforeNodes = this._beforeNodes; + + this._beforeNodes = null; + + for ( const beforeNode of currentBeforeNodes ) { + + beforeNode.build( builder, output ); + + } + + this._beforeNodes = currentBeforeNodes; + + } + + // + const nodeData = builder.getDataFromNode( this ); nodeData.buildStages = nodeData.buildStages || {}; nodeData.buildStages[ builder.buildStage ] = true; diff --git a/src/nodes/lighting/ShadowNode.js b/src/nodes/lighting/ShadowNode.js index 44da3d88f7ad02..1f690ed5b923db 100644 --- a/src/nodes/lighting/ShadowNode.js +++ b/src/nodes/lighting/ShadowNode.js @@ -1,7 +1,7 @@ import ShadowBaseNode, { shadowPositionWorld } from './ShadowBaseNode.js'; import { float, vec2, vec3, int, Fn, nodeObject } from '../tsl/TSLBase.js'; import { reference } from '../accessors/ReferenceNode.js'; -import { texture } from '../accessors/TextureNode.js'; +import { texture, textureLoad } from '../accessors/TextureNode.js'; import { normalWorld } from '../accessors/Normal.js'; import { mix, sqrt } from '../math/MathNode.js'; import { add } from '../math/OperatorNode.js'; @@ -19,6 +19,8 @@ import { getDataFromObject } from '../core/NodeUtils.js'; import { getShadowMaterial, BasicShadowFilter, PCFShadowFilter, PCFSoftShadowFilter, VSMShadowFilter } from './ShadowFilterNode.js'; import ChainMap from '../../renderers/common/ChainMap.js'; import { warn } from '../../utils.js'; +import { textureSize } from '../accessors/TextureSizeNode.js'; +import { uv } from '../accessors/UV.js'; // @@ -515,7 +517,19 @@ class ShadowNode extends ShadowBaseNode { this.shadowMap = shadowMap; this.shadow.map = shadowMap; - return shadowOutput; + // Shadow Output + Inspector + + const inspectName = `${ this.light.type } Shadow [ ${ this.light.name || 'ID: ' + this.light.id } ]`; + + return shadowOutput.toInspector( `${ inspectName } / Color`, () => { + + return texture( this.shadowMap.texture ); + + } ).toInspector( `${ inspectName } / Depth`, () => { + + return textureLoad( this.shadowMap.depthTexture, uv().mul( textureSize( texture( this.shadowMap.depthTexture ) ) ) ).x.oneMinus(); + + } ); } diff --git a/src/nodes/tsl/TSLBase.js b/src/nodes/tsl/TSLBase.js index 0f5e3ec184dcd7..56e257ae545443 100644 --- a/src/nodes/tsl/TSLBase.js +++ b/src/nodes/tsl/TSLBase.js @@ -27,6 +27,7 @@ export * from '../utils/Discard.js'; // Discard(), Return() export * from '../display/RenderOutputNode.js'; // .renderOutput() export * from '../utils/DebugNode.js'; // debug() export * from '../core/SubBuildNode.js'; // subBuild() +export * from '../core/InspectorNode.js'; // inspector(), .toInspector() export function addNodeElement( name/*, nodeElement*/ ) { diff --git a/src/renderers/common/CanvasTarget.js b/src/renderers/common/CanvasTarget.js index 6e6c1281b723b0..20e2e9165034cd 100644 --- a/src/renderers/common/CanvasTarget.js +++ b/src/renderers/common/CanvasTarget.js @@ -10,30 +10,15 @@ import { DepthTexture } from '../../textures/DepthTexture.js'; */ class CanvasTarget extends EventDispatcher { - /** - * CanvasTarget options. - * - * @typedef {Object} CanvasTarget~Options - * @property {boolean} [antialias=false] - Whether MSAA as the default anti-aliasing should be enabled or not. - * @property {number} [samples=0] - When `antialias` is `true`, `4` samples are used by default. This parameter can set to any other integer value than 0 - * to overwrite the default. - */ - /** * Constructs a new CanvasTarget. * * @param {HTMLCanvasElement|OffscreenCanvas} domElement - The canvas element to render to. - * @param {Object} [parameters={}] - The parameters. */ - constructor( domElement, parameters = {} ) { + constructor( domElement ) { super(); - const { - antialias = false, - samples = 0 - } = parameters; - /** * A reference to the canvas element the renderer is drawing to. * This value of this property will automatically be created by @@ -92,15 +77,6 @@ class CanvasTarget extends EventDispatcher { */ this._scissorTest = false; - /** - * The number of MSAA samples. - * - * @private - * @type {number} - * @default 0 - */ - this._samples = samples || ( antialias === true ) ? 4 : 0; - /** * The color texture of the default framebuffer. * @@ -117,18 +93,6 @@ class CanvasTarget extends EventDispatcher { } - /** - * The number of samples used for multi-sample anti-aliasing (MSAA). - * - * @type {number} - * @default 0 - */ - get samples() { - - return this._samples; - - } - /** * Returns the pixel ratio. * diff --git a/src/renderers/common/InspectorBase.js b/src/renderers/common/InspectorBase.js index 2b37fc9e42e694..ad755f7eafa372 100644 --- a/src/renderers/common/InspectorBase.js +++ b/src/renderers/common/InspectorBase.js @@ -78,6 +78,13 @@ class InspectorBase { */ finish() { } + /** + * Inspects a node. + * + * @param {Node} node - The node to inspect. + */ + inspect( /*node*/ ) { } + /** * When a compute operation is performed. * diff --git a/src/renderers/common/Renderer.js b/src/renderers/common/Renderer.js index 8b56b5e7db46f9..54a7506103a2f6 100644 --- a/src/renderers/common/Renderer.js +++ b/src/renderers/common/Renderer.js @@ -254,6 +254,15 @@ class Renderer { // internals + /** + * The number of MSAA samples. + * + * @private + * @type {number} + * @default 0 + */ + this._samples = samples || ( antialias === true ) ? 4 : 0; + /** * OnCanvasTargetResize callback function. * @@ -268,7 +277,7 @@ class Renderer { * @private * @type {CanvasTarget} */ - this._canvasTarget = new CanvasTarget( backend.getDomElement(), { antialias, samples } ); + this._canvasTarget = new CanvasTarget( backend.getDomElement() ); this._canvasTarget.addEventListener( 'resize', this._onCanvasTargetResize ); this._canvasTarget.isDefaultCanvasTarget = true; @@ -2172,7 +2181,7 @@ class Renderer { */ get samples() { - return this._canvasTarget.samples; + return this._samples; } @@ -2187,7 +2196,7 @@ class Renderer { */ get currentSamples() { - let samples = this.samples; + let samples = this._samples; if ( this._renderTarget !== null ) {