From 3300ffde2d53fa66e4b6a9156023c2fa6cf3d025 Mon Sep 17 00:00:00 2001 From: aardgoose Date: Wed, 31 Jan 2024 14:27:18 +0000 Subject: [PATCH 01/14] clipping --- examples/files.json | 1 + examples/jsm/nodes/accessors/ClippingNode.js | 210 +++++++++++++ examples/jsm/nodes/core/NodeBuilder.js | 2 + examples/jsm/nodes/materials/NodeMaterial.js | 29 ++ .../jsm/renderers/common/ClippingContext.js | 97 ++++++ examples/jsm/renderers/common/RenderObject.js | 46 ++- .../jsm/renderers/common/RenderObjects.js | 14 +- examples/jsm/renderers/common/Renderer.js | 49 ++- examples/jsm/renderers/common/Uniform.js | 7 +- .../jsm/renderers/common/UniformsGroup.js | 24 +- examples/jsm/renderers/common/nodes/Nodes.js | 1 + .../renderers/webgl/nodes/GLSLNodeBuilder.js | 12 +- .../jsm/renderers/webgpu/WebGPUBackend.js | 7 +- .../jsm/renderers/webgpu/WebGPURenderer.js | 2 +- .../renderers/webgpu/nodes/WGSLNodeBuilder.js | 12 +- examples/screenshots/webgpu_clipping.jpg | Bin 0 -> 22470 bytes examples/webgpu_clipping.html | 292 ++++++++++++++++++ 17 files changed, 781 insertions(+), 24 deletions(-) create mode 100644 examples/jsm/nodes/accessors/ClippingNode.js create mode 100644 examples/jsm/renderers/common/ClippingContext.js create mode 100644 examples/screenshots/webgpu_clipping.jpg create mode 100644 examples/webgpu_clipping.html diff --git a/examples/files.json b/examples/files.json index a912ac96fe03e4..12152d8fd7b153 100644 --- a/examples/files.json +++ b/examples/files.json @@ -321,6 +321,7 @@ "webgpu_backdrop_water", "webgpu_camera_logarithmicdepthbuffer", "webgpu_clearcoat", + "webgpu_clipping", "webgpu_compute_audio", "webgpu_compute_particles", "webgpu_compute_particles_rain", diff --git a/examples/jsm/nodes/accessors/ClippingNode.js b/examples/jsm/nodes/accessors/ClippingNode.js new file mode 100644 index 00000000000000..eda576434bb0fd --- /dev/null +++ b/examples/jsm/nodes/accessors/ClippingNode.js @@ -0,0 +1,210 @@ + +import Node from '../core/Node.js'; +import { nodeObject } from '../shadernode/ShaderNode.js'; +import { positionView } from './PositionNode.js'; +import { diffuseColor, property } from '../core/PropertyNode.js'; +import { tslFn } from '../shadernode/ShaderNode.js'; +import { loop } from '../utils/LoopNode.js'; +import { smoothstep } from '../math/MathNode.js'; +import { NodeUpdateType } from '../core/constants.js'; +import { Matrix3, Plane, Vector4 } from 'three'; +import { uniform } from '../core/UniformNode.js'; + +const _plane = new Plane(); +const _viewNormalMatrix = new Matrix3(); + +class ClippingNode extends Node { + + constructor( scope = ClippingNode.DEFAULT ) { + + super(); + + this.scope = scope; + this.updateType = NodeUpdateType.FRAME; + this.planes = []; + + } + + projectPlanes( source, offset, viewMatrix ) { + + const l = source.length; + const planes = this.planes; + + for ( let i = 0; i < l; i ++ ) { + + _plane.copy( source[ i ] ).applyMatrix4( viewMatrix, _viewNormalMatrix ); + + const v = planes[ offset + i ]; + const normal = _plane.normal; + + v.x = - normal.x; + v.y = - normal.y; + v.z = - normal.z; + v.w = _plane.constant; + + } + + } + + update( frame ) { + + const viewMatrix = frame.camera.matrixWorldInverse; + + _viewNormalMatrix.getNormalMatrix( viewMatrix ); + + const globalClippingPlanes = this._globalClippingPlanes; + const localClippingPlanes = this._localClippingPlanes; + + const lg = globalClippingPlanes.length; + const ll = localClippingPlanes.length; + + if ( lg > 0 ) this.projectPlanes( globalClippingPlanes, 0, viewMatrix ); + + if ( ll > 0 ) this.projectPlanes( localClippingPlanes, lg, viewMatrix ); + + } + + setup( builder ) { + + super.setup( builder ); + + const { localClippingEnabled, localClipIntersection } = builder.clippingContext; + const { localClippingCount, globalClippingCount } = builder.clippingContext; + const { globalClippingPlanes, localClippingPlanes } = builder.clippingContext; + + this._globalClippingPlanes = globalClippingPlanes; + this._localClippingPlanes = localClippingEnabled ? localClippingPlanes : []; + + const l = globalClippingCount + localClippingCount; + + this._numClippingPlanes = l; + this._numUnionClippingPlanes = localClipIntersection ? l - localClippingCount : l; + + for ( let i = 0; i < l; i ++ ) { + + this.planes.push( new Vector4() ); + + } + + if ( this.scope === ClippingNode.ALPHA_TO_COVERAGE ) { + + this.setupAlphaToCoverage(); + + } else { + + this.setupDefault(); + + } + + return this.clippingNode; + + } + + setupAlphaToCoverage() { + + const numClippingPlanes = this._numClippingPlanes; + const numUnionClippingPlanes = this._numUnionClippingPlanes; + + this.clippingNode = tslFn( () => { + + const clippingPlanes = uniform( this.planes, 'vec4' ); + + const distanceToPlane = property( 'float', 'distanceToPlane' ); + const distanceGradient = property( 'float', 'distanceToGradient' ); + + const clipOpacity = property( 'float', 'clipOpacity' ); + + clipOpacity.assign( 1 ); + + let plane; + + loop( numUnionClippingPlanes, ( { i } ) => { + + plane = clippingPlanes.element( i ); + + distanceToPlane.assign( positionView.dot( plane.xyz ).negate().add( plane.w ) ); + distanceGradient.assign( distanceToPlane.fwidth().div( 2.0 ) ); + + clipOpacity.mulAssign( smoothstep( distanceGradient.negate(), distanceGradient, distanceToPlane ) ); + + clipOpacity.equal( 0.0 ).discard(); + + } ); + + if ( numUnionClippingPlanes < numClippingPlanes ) { + + const unionClipOpacity = property( 'float', 'unionclipOpacity' ); + + unionClipOpacity.assign( 1 ); + + loop( { start: numUnionClippingPlanes, end: numClippingPlanes }, ( { i } ) => { + + plane = clippingPlanes.element( i ); + + distanceToPlane.assign( positionView.dot( plane.xyz ).negate().add( plane.w ) ); + distanceGradient.assign( distanceToPlane.fwidth().div( 2.0 ) ); + + unionClipOpacity.mulAssign( smoothstep( distanceGradient.negate(), distanceGradient, distanceToPlane ).oneMinus() ); + + } ); + + clipOpacity.mulAssign( unionClipOpacity.oneMinus() ); + + } + + diffuseColor.a.mulAssign( clipOpacity ); + + diffuseColor.a.equal( 0.0 ).discard(); + + } )(); + + } + + setupDefault() { + + const numClippingPlanes = this._numClippingPlanes; + const numUnionClippingPlanes = this._numUnionClippingPlanes; + + this.clippingNode = tslFn( () => { + + const clippingPlanes = uniform( this.planes, 'vec4' ); + + let plane; + + loop( numUnionClippingPlanes, ( { i } ) => { + + plane = clippingPlanes.element( i ); + positionView.dot( plane.xyz ).greaterThan( plane.w ).discard(); + + } ); + + if ( numUnionClippingPlanes < numClippingPlanes ) { + + const clipped = property( 'bool', 'clipped' ); + + clipped.assign( true ); + + loop( { start: numUnionClippingPlanes, end: numClippingPlanes }, ( { i } ) => { + + plane = clippingPlanes.element( i ); + clipped.assign( positionView.dot( plane.xyz ).greaterThan( plane.w ).and( clipped ) ); + + } ); + + clipped.discard(); + } + + } )(); + + } + +} + +ClippingNode.ALPHA_TO_COVERAGE = 'alphaToCoverage'; +ClippingNode.DEFAULT = 'default'; + +export default ClippingNode; + +export const clipping = () => nodeObject( new ClippingNode() ); + +export const clippingAlpha = () => nodeObject( new ClippingNode( ClippingNode.ALPHA_TO_COVERAGE ) ); diff --git a/examples/jsm/nodes/core/NodeBuilder.js b/examples/jsm/nodes/core/NodeBuilder.js index 4d0e90e37dfae4..6dd15892b96afc 100644 --- a/examples/jsm/nodes/core/NodeBuilder.js +++ b/examples/jsm/nodes/core/NodeBuilder.js @@ -72,6 +72,8 @@ class NodeBuilder { this.fogNode = null; this.toneMappingNode = null; + this.clippingContext = null; + this.vertexShader = null; this.fragmentShader = null; this.computeShader = null; diff --git a/examples/jsm/nodes/materials/NodeMaterial.js b/examples/jsm/nodes/materials/NodeMaterial.js index 325a08285e93b9..2c493fc3363744 100644 --- a/examples/jsm/nodes/materials/NodeMaterial.js +++ b/examples/jsm/nodes/materials/NodeMaterial.js @@ -19,6 +19,7 @@ import { lightingContext } from '../lighting/LightingContextNode.js'; import EnvironmentNode from '../lighting/EnvironmentNode.js'; import { depthPixel } from '../display/ViewportDepthNode.js'; import { cameraLogDepth } from '../accessors/CameraNode.js'; +import { clipping, clippingAlpha } from '../accessors/ClippingNode.js'; const NodeMaterials = new Map(); @@ -54,6 +55,7 @@ class NodeMaterial extends ShaderMaterial { this.depthNode = null; this.shadowNode = null; + this.clippingNode = null; this.outputNode = null; @@ -90,6 +92,8 @@ class NodeMaterial extends ShaderMaterial { let resultNode; + this.setupClipping( builder ); + if ( this.fragmentNode === null ) { if ( this.depthWrite === true ) this.setupDepth( builder ); @@ -101,6 +105,8 @@ class NodeMaterial extends ShaderMaterial { const outgoingLightNode = this.setupLighting( builder ); + if ( this.clippingNode ) builder.stack.add( this.clippingNode ); + resultNode = this.setupOutput( builder, vec4( outgoingLightNode, diffuseColor.a ) ); // OUTPUT NODE @@ -123,6 +129,29 @@ class NodeMaterial extends ShaderMaterial { } + setupClipping( builder ) { + + const { globalClippingCount, localClippingCount, localClippingEnabled } = builder.clippingContext; + + this.clippingNode = null; + + if ( globalClippingCount || ( localClippingEnabled && localClippingCount > 0 ) ) { + + if ( this.alphaToCoverage ) { + + // to be added to flow when the color/alpha value has been determined + this.clippingNode = clippingAlpha(); + + } else { + + builder.stack.add( clipping() ); + + } + + } + + } + setupDepth( builder ) { const { renderer } = builder; diff --git a/examples/jsm/renderers/common/ClippingContext.js b/examples/jsm/renderers/common/ClippingContext.js new file mode 100644 index 00000000000000..afc96ba4f0ef20 --- /dev/null +++ b/examples/jsm/renderers/common/ClippingContext.js @@ -0,0 +1,97 @@ +let _clippingContextVersion = 0; + +class ClippingContext { + + constructor() { + + this.version = ++ _clippingContextVersion; + + this.globalClippingPlanes = []; + this.globalClippingCount = 0; + + this.localClippingEnabled = false; + this.localClippingPlanes = []; + this.localClippingCount = 0; + + this.localClipIntersection = false; + + this.parentVersion = 0; + + } + + inherit( parent ) { + + if ( this === parent || parent.version === this.parentVersion ) return; + + this.globalClippingPlanes = parent.globalClippingPlanes; + this.globalClippingCount = parent.globalClippingCount; + this.localClippingEnabled = parent.localClippingEnabled; + this.parentVersion = parent.version; + + this.version = _clippingContextVersion ++; + + } + + updateGlobal( renderer ) { + + let update = false; + + if ( renderer.localClippingEnabled !== this.localClippingEnabled ) { + + this.localClippingEnabled = renderer.localClippingEnabled; + update = true; + + } + + if ( renderer.clippingPlanes !== this.globalClippingPlanes && Array.isArray( renderer.clippingPlanes )) { + + this.globalClippingPlanes = renderer.clippingPlanes; + this.globalClippingCount = this.globalClippingPlanes.length; + update = true; + + } else if ( this.globalClippingPlanes.length !== this.globalClippingCount ) { + + this.globalClippingCount = this.globalClippingPlanes.length; + update = true; + + } + + if ( update ) this.version = _clippingContextVersion ++; + + } + + updateMaterial( material ) { + + let update = false; + + if ( this.localClippingEnabled ) { + + if ( material.clippingPlanes != this.localClippingPlanes && Array.isArray( material.clippingPlanes ) ) { + + this.localClippingPlanes = material.clippingPlanes; + this.localClippingCount = this.localClippingPlanes.length; + update = true; + + } else if ( this.localClippingCount !== this.localClippingPlanes.length ) { + + this.localClippingCount = this.localClippingPlanes.length; + update = true; + + } + + if ( this.localClipIntersection !== material.clipIntersection ) { + + this.localClipIntersection = material.clipIntersection; + update = true; + + } + + if ( update ) this.version = _clippingContextVersion ++; + + } + + } + +} + +export default ClippingContext; diff --git a/examples/jsm/renderers/common/RenderObject.js b/examples/jsm/renderers/common/RenderObject.js index 5372250b8bcadd..8bca34cf803c50 100644 --- a/examples/jsm/renderers/common/RenderObject.js +++ b/examples/jsm/renderers/common/RenderObject.js @@ -1,8 +1,10 @@ +import ClippingContext from "./ClippingContext.js"; + let id = 0; export default class RenderObject { - constructor( nodes, geometries, renderer, object, material, scene, camera, lightsNode, renderContext ) { + constructor( nodes, geometries, renderer, object, material, scene, camera, lightsNode, renderContext, clippingContext ) { this._nodes = nodes; this._geometries = geometries; @@ -24,6 +26,10 @@ export default class RenderObject { this.pipeline = null; this.vertexBuffers = null; + this.updateClipping( clippingContext ); + + this.clippingContextVersion = this.clippingContext.version; + this.initialNodesCacheKey = this.getNodesCacheKey(); this.initialCacheKey = this.getCacheKey(); @@ -44,6 +50,42 @@ export default class RenderObject { } + updateClipping( parent ) { + + const material = this.material; + + let clippingContext = this.clippingContext; + + if ( Array.isArray( material.clippingPlanes ) ) { + + if ( clippingContext === parent || ! clippingContext ) { + + clippingContext = new ClippingContext(); + this.clippingContext = clippingContext; + + } + + clippingContext.inherit( parent ); + clippingContext.updateMaterial( material ); + + } else if ( this.clippingContext !== parent ) { + + this.clippingContext = parent; + + } + + } + + clippingNeedsUpdate () { + + if ( this.clippingContext.version === this.clippingContextVersion ) return false; + + this.clippingContextVersion = this.clippingContext.version; + + return true; + + } + getNodeBuilderState() { return this._nodeBuilderState || ( this._nodeBuilderState = this._nodes.getForRender( this ) ); @@ -131,6 +173,8 @@ export default class RenderObject { } + cacheKey += this.clippingContextVersion + ','; + if ( object.skeleton ) { cacheKey += object.skeleton.uuid + ','; diff --git a/examples/jsm/renderers/common/RenderObjects.js b/examples/jsm/renderers/common/RenderObjects.js index f223c38a917af2..309cea3e0f3d98 100644 --- a/examples/jsm/renderers/common/RenderObjects.js +++ b/examples/jsm/renderers/common/RenderObjects.js @@ -16,7 +16,7 @@ class RenderObjects { } - get( object, material, scene, camera, lightsNode, renderContext, passId ) { + get( object, material, scene, camera, lightsNode, renderContext, clippingContext, passId ) { const chainMap = this.getChainMap( passId ); const chainArray = [ object, material, renderContext, lightsNode ]; @@ -25,19 +25,21 @@ class RenderObjects { if ( renderObject === undefined ) { - renderObject = this.createRenderObject( this.nodes, this.geometries, this.renderer, object, material, scene, camera, lightsNode, renderContext, passId ); + renderObject = this.createRenderObject( this.nodes, this.geometries, this.renderer, object, material, scene, camera, lightsNode, renderContext, clippingContext, passId ); chainMap.set( chainArray, renderObject ); } else { - if ( renderObject.version !== material.version || renderObject.needsUpdate ) { + renderObject.updateClipping( clippingContext ); + + if ( renderObject.version !== material.version || renderObject.needsUpdate || renderObject.clippingNeedsUpdate() ) { if ( renderObject.initialCacheKey !== renderObject.getCacheKey() ) { renderObject.dispose(); - renderObject = this.get( object, material, scene, camera, lightsNode, renderContext, passId ); + renderObject = this.get( object, material, scene, camera, lightsNode, renderContext, clippingContext, passId ); } else { @@ -65,11 +67,11 @@ class RenderObjects { } - createRenderObject( nodes, geometries, renderer, object, material, scene, camera, lightsNode, renderContext, passId ) { + createRenderObject( nodes, geometries, renderer, object, material, scene, camera, lightsNode, renderContext, clippingContext, passId ) { const chainMap = this.getChainMap( passId ); - const renderObject = new RenderObject( nodes, geometries, renderer, object, material, scene, camera, lightsNode, renderContext ); + const renderObject = new RenderObject( nodes, geometries, renderer, object, material, scene, camera, lightsNode, renderContext, clippingContext ); renderObject.onDispose = () => { diff --git a/examples/jsm/renderers/common/Renderer.js b/examples/jsm/renderers/common/Renderer.js index 41a05a361664c6..a1509e59f30bd7 100644 --- a/examples/jsm/renderers/common/Renderer.js +++ b/examples/jsm/renderers/common/Renderer.js @@ -11,6 +11,7 @@ import Textures from './Textures.js'; import Background from './Background.js'; import Nodes from './nodes/Nodes.js'; import Color4 from './Color4.js'; +import ClippingContext from './ClippingContext.js'; import { Scene, Frustum, Matrix4, Vector2, Vector3, Vector4, DoubleSide, BackSide, FrontSide, SRGBColorSpace, NoToneMapping } from 'three'; const _scene = new Scene(); @@ -58,6 +59,8 @@ class Renderer { this.depth = true; this.stencil = true; + this.clippingPlanes = []; + this.info = new Info(); // internals @@ -161,6 +164,7 @@ class Renderer { this._objects = new RenderObjects( this, this._nodes, this._geometries, this._pipelines, this._bindings, this.info ); this._renderLists = new RenderLists(); this._renderContexts = new RenderContexts(); + this._clippingContext = new ClippingContext(); // @@ -386,6 +390,8 @@ class Renderer { renderContext.scissorValue.width >>= activeMipmapLevel; renderContext.scissorValue.height >>= activeMipmapLevel; + this._clippingContext.updateGlobal( this ); + // sceneRef.onBeforeRender( this, scene, camera, renderTarget ); @@ -440,6 +446,7 @@ class Renderer { renderContext.activeCubeFace = activeCubeFace; renderContext.activeMipmapLevel = activeMipmapLevel; renderContext.occlusionQueryCount = renderList.occlusionQueryCount; + renderContext.globalClippingCount = this.clippingPlanes !== null ? this.clippingPlanes.length: 0; // @@ -1107,10 +1114,42 @@ class Renderer { } - if ( overrideMaterial.isShadowNodeMaterial && ( material.shadowNode && material.shadowNode.isNode ) ) { + if ( overrideMaterial.isShadowNodeMaterial ) { + + overrideMaterial.side = material.shadowSide === null ? material.side : material.shadowSide; + + if ( material.shadowNode && material.shadowNode.isNode ) { + + overrideFragmentNode = overrideMaterial.fragmentNode; + overrideMaterial.fragmentNode = material.shadowNode; + + } + + if ( this.localClippingEnabled ) { + + if ( material.clipShadows ) { + + if ( overrideMaterial.clippingPlanes !== material.clippingPlanes ) { + + overrideMaterial.clippingPlanes = material.clippingPlanes; + overrideMaterial.needsUpdate = true; - overrideFragmentNode = overrideMaterial.fragmentNode; - overrideMaterial.fragmentNode = material.shadowNode; + } + + if ( overrideMaterial.clipIntersection !== material.clipIntersection ) { + + overrideMaterial.clipIntersection = material.clipIntersection; + + } + + } else if ( Array.isArray( overrideMaterial.clippingPlanes ) ) { + + overrideMaterial.clippingPlanes = null; + overrideMaterial.needsUpdate = true; + + } + + } } @@ -1158,7 +1197,7 @@ class Renderer { _renderObjectDirect( object, material, scene, camera, lightsNode, passId ) { - const renderObject = this._objects.get( object, material, scene, camera, lightsNode, this._currentRenderContext, passId ); + const renderObject = this._objects.get( object, material, scene, camera, lightsNode, this._currentRenderContext, this._clippingContext, passId ); // @@ -1184,7 +1223,7 @@ class Renderer { _createObjectPipeline( object, material, scene, camera, lightsNode, passId ) { - const renderObject = this._objects.get( object, material, scene, camera, lightsNode, this._currentRenderContext, passId ); + const renderObject = this._objects.get( object, material, scene, camera, lightsNode, this._currentRenderContext, this._clippingContext, passId ); // diff --git a/examples/jsm/renderers/common/Uniform.js b/examples/jsm/renderers/common/Uniform.js index 4386d3e755e025..b90d375f864a5a 100644 --- a/examples/jsm/renderers/common/Uniform.js +++ b/examples/jsm/renderers/common/Uniform.js @@ -7,6 +7,8 @@ class Uniform { this.name = name; this.value = value; + this.isArray = value && Array.isArray( value ); + this.itemCount = this.isArray ? this.value.length : 1; this.boundary = 0; // used to build the uniform buffer according to the STD140 layout this.itemSize = 0; @@ -80,9 +82,8 @@ class Vector4Uniform extends Uniform { super( name, value ); this.isVector4Uniform = true; - - this.boundary = 16; - this.itemSize = 4; + this.boundary = this.itemCount * 16; + this.itemSize = this.itemCount * 4; } diff --git a/examples/jsm/renderers/common/UniformsGroup.js b/examples/jsm/renderers/common/UniformsGroup.js index 21bb2cd33010f4..24ea9a021f6735 100644 --- a/examples/jsm/renderers/common/UniformsGroup.js +++ b/examples/jsm/renderers/common/UniformsGroup.js @@ -116,10 +116,11 @@ class UniformsGroup extends UniformBuffer { updateByType( uniform ) { + if ( uniform.isArray ) return this.updateArray( uniform ); if ( uniform.isFloatUniform ) return this.updateNumber( uniform ); if ( uniform.isVector2Uniform ) return this.updateVector2( uniform ); if ( uniform.isVector3Uniform ) return this.updateVector3( uniform ); - if ( uniform.isVector4Uniform ) return this.updateVector4( uniform ); + if ( uniform.isVector4Uniform ) return this.updateVector4( uniform.getValue(), uniform.offset ); if ( uniform.isColorUniform ) return this.updateColor( uniform ); if ( uniform.isMatrix3Uniform ) return this.updateMatrix3( uniform ); if ( uniform.isMatrix4Uniform ) return this.updateMatrix4( uniform ); @@ -128,6 +129,23 @@ class UniformsGroup extends UniformBuffer { } + updateArray( uniform ) { + + const values = uniform.getValue(); + const l = values.length; + + let updated = false; + + for ( let i = 0; i < l; i ++ ) { + + if ( uniform.isVector4Uniform ) updated = this.updateVector4( values[ i ], uniform.offset + i * 4 ) || updated; + + } + + return updated; + + } + updateNumber( uniform ) { let updated = false; @@ -190,13 +208,11 @@ class UniformsGroup extends UniformBuffer { } - updateVector4( uniform ) { + updateVector4( v, offset ) { let updated = false; const a = this.buffer; - const v = uniform.getValue(); - const offset = uniform.offset; if ( a[ offset + 0 ] !== v.x || a[ offset + 1 ] !== v.y || a[ offset + 2 ] !== v.z || a[ offset + 4 ] !== v.w ) { diff --git a/examples/jsm/renderers/common/nodes/Nodes.js b/examples/jsm/renderers/common/nodes/Nodes.js index 2364ee5d9ceb59..5e217a3c705bdb 100644 --- a/examples/jsm/renderers/common/nodes/Nodes.js +++ b/examples/jsm/renderers/common/nodes/Nodes.js @@ -114,6 +114,7 @@ class Nodes extends DataMap { nodeBuilder.environmentNode = this.getEnvironmentNode( renderObject.scene ); nodeBuilder.fogNode = this.getFogNode( renderObject.scene ); nodeBuilder.toneMappingNode = this.getToneMappingNode(); + nodeBuilder.clippingContext = renderObject.clippingContext; nodeBuilder.build(); nodeBuilderState = this._createNodeBuilderState( nodeBuilder ); diff --git a/examples/jsm/renderers/webgl/nodes/GLSLNodeBuilder.js b/examples/jsm/renderers/webgl/nodes/GLSLNodeBuilder.js index 53088cdcca6cd2..ba7565c32bee22 100644 --- a/examples/jsm/renderers/webgl/nodes/GLSLNodeBuilder.js +++ b/examples/jsm/renderers/webgl/nodes/GLSLNodeBuilder.js @@ -328,7 +328,17 @@ ${ flowData.code } const vectorType = this.getVectorType( uniform.type ); - snippet = `${vectorType} ${uniform.name};`; + if ( Array.isArray( uniform.value ) === true ) { + + const length = uniform.value.length; + + snippet = `${vectorType} ${uniform.name}[${length}];`; + + } else { + + snippet = `${vectorType} ${uniform.name};`; + + } group = true; diff --git a/examples/jsm/renderers/webgpu/WebGPUBackend.js b/examples/jsm/renderers/webgpu/WebGPUBackend.js index 8a4686c2b9d535..ed56f7fa0bad21 100644 --- a/examples/jsm/renderers/webgpu/WebGPUBackend.js +++ b/examples/jsm/renderers/webgpu/WebGPUBackend.js @@ -929,7 +929,8 @@ class WebGPUBackend extends Backend { data.side !== material.side || data.alphaToCoverage !== material.alphaToCoverage || data.sampleCount !== sampleCount || data.colorSpace !== colorSpace || data.colorFormat !== colorFormat || data.depthStencilFormat !== depthStencilFormat || - data.primitiveTopology !== primitiveTopology + data.primitiveTopology !== primitiveTopology || + data.clippingContextVersion !== renderObject.clippingContextVersion ) { data.material = material; data.materialVersion = material.version; @@ -947,6 +948,7 @@ class WebGPUBackend extends Backend { data.colorFormat = colorFormat; data.depthStencilFormat = depthStencilFormat; data.primitiveTopology = primitiveTopology; + data.clippingContextVersion = renderObject.clippingContextVersion needsUpdate = true; @@ -975,7 +977,8 @@ class WebGPUBackend extends Backend { material.side, utils.getSampleCount( renderContext ), utils.getCurrentColorSpace( renderContext ), utils.getCurrentColorFormat( renderContext ), utils.getCurrentDepthStencilFormat( renderContext ), - utils.getPrimitiveTopology( object, material ) + utils.getPrimitiveTopology( object, material ), + renderObject.clippingContextVersion ].join(); } diff --git a/examples/jsm/renderers/webgpu/WebGPURenderer.js b/examples/jsm/renderers/webgpu/WebGPURenderer.js index c4360d78a88103..b33e26755416f4 100644 --- a/examples/jsm/renderers/webgpu/WebGPURenderer.js +++ b/examples/jsm/renderers/webgpu/WebGPURenderer.js @@ -23,7 +23,7 @@ class WebGPURenderer extends Renderer { let BackendClass; - if ( parameters.forceWebGL ) { + if ( ! parameters.forceWebGL ) { BackendClass = WebGLBackend; diff --git a/examples/jsm/renderers/webgpu/nodes/WGSLNodeBuilder.js b/examples/jsm/renderers/webgpu/nodes/WGSLNodeBuilder.js index a86e35580374dc..d102d2ce486133 100644 --- a/examples/jsm/renderers/webgpu/nodes/WGSLNodeBuilder.js +++ b/examples/jsm/renderers/webgpu/nodes/WGSLNodeBuilder.js @@ -783,7 +783,17 @@ ${ flowData.code } snippets: [] } ); - group.snippets.push( `\t${ uniform.name } : ${ vectorType }` ); + if ( Array.isArray( uniform.value ) === true ) { + + const length = uniform.value.length; + + group.snippets.push( `\t${uniform.name} : array<${vectorType}, ${length}>` ); + + } else { + + group.snippets.push( `\t${uniform.name} : ${ vectorType}` ); + + } } diff --git a/examples/screenshots/webgpu_clipping.jpg b/examples/screenshots/webgpu_clipping.jpg new file mode 100644 index 0000000000000000000000000000000000000000..c02bb5bae6e92110c3a4c42157dc2b5c53fd0832 GIT binary patch literal 22470 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

4Q#*66J)m~x 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 oqm<=k^^ + + + three.js webgpu - clipping planes + + + + + +

+ three.js webgpu - clipping +
+ + + + + + From 8036ee7031ed9cdbaacde01b3e408dc240c7d659 Mon Sep 17 00:00:00 2001 From: aardgoose Date: Tue, 6 Feb 2024 09:33:29 +0000 Subject: [PATCH 02/14] add ; --- examples/jsm/renderers/webgpu/WebGPUBackend.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/jsm/renderers/webgpu/WebGPUBackend.js b/examples/jsm/renderers/webgpu/WebGPUBackend.js index ed56f7fa0bad21..56c8548a6a6632 100644 --- a/examples/jsm/renderers/webgpu/WebGPUBackend.js +++ b/examples/jsm/renderers/webgpu/WebGPUBackend.js @@ -948,7 +948,7 @@ class WebGPUBackend extends Backend { data.colorFormat = colorFormat; data.depthStencilFormat = depthStencilFormat; data.primitiveTopology = primitiveTopology; - data.clippingContextVersion = renderObject.clippingContextVersion + data.clippingContextVersion = renderObject.clippingContextVersion; needsUpdate = true; From b0f76fdcc97366b2f3706e4fe4f9ec2c260b0c66 Mon Sep 17 00:00:00 2001 From: aardgoose Date: Tue, 6 Feb 2024 10:57:04 +0000 Subject: [PATCH 03/14] remove testing code --- examples/jsm/renderers/webgpu/WebGPURenderer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/jsm/renderers/webgpu/WebGPURenderer.js b/examples/jsm/renderers/webgpu/WebGPURenderer.js index b33e26755416f4..c4360d78a88103 100644 --- a/examples/jsm/renderers/webgpu/WebGPURenderer.js +++ b/examples/jsm/renderers/webgpu/WebGPURenderer.js @@ -23,7 +23,7 @@ class WebGPURenderer extends Renderer { let BackendClass; - if ( ! parameters.forceWebGL ) { + if ( parameters.forceWebGL ) { BackendClass = WebGLBackend; From 6f1752d80bb314adb11ead97568c1f508607f8fb Mon Sep 17 00:00:00 2001 From: aardgoose Date: Tue, 6 Feb 2024 11:20:50 +0000 Subject: [PATCH 04/14] cleanup and adjust default settiing in example --- examples/jsm/nodes/materials/NodeMaterial.js | 11 ++++++----- examples/webgpu_clipping.html | 2 +- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/examples/jsm/nodes/materials/NodeMaterial.js b/examples/jsm/nodes/materials/NodeMaterial.js index 2c493fc3363744..59cae53cdd4bb4 100644 --- a/examples/jsm/nodes/materials/NodeMaterial.js +++ b/examples/jsm/nodes/materials/NodeMaterial.js @@ -55,7 +55,6 @@ class NodeMaterial extends ShaderMaterial { this.depthNode = null; this.shadowNode = null; - this.clippingNode = null; this.outputNode = null; @@ -92,7 +91,7 @@ class NodeMaterial extends ShaderMaterial { let resultNode; - this.setupClipping( builder ); + const clippingNode = this.setupClipping( builder ); if ( this.fragmentNode === null ) { @@ -105,7 +104,7 @@ class NodeMaterial extends ShaderMaterial { const outgoingLightNode = this.setupLighting( builder ); - if ( this.clippingNode ) builder.stack.add( this.clippingNode ); + if ( clippingNode !== null ) builder.stack.add( clippingNode ); resultNode = this.setupOutput( builder, vec4( outgoingLightNode, diffuseColor.a ) ); @@ -133,14 +132,14 @@ class NodeMaterial extends ShaderMaterial { const { globalClippingCount, localClippingCount, localClippingEnabled } = builder.clippingContext; - this.clippingNode = null; + let result = null; if ( globalClippingCount || ( localClippingEnabled && localClippingCount > 0 ) ) { if ( this.alphaToCoverage ) { // to be added to flow when the color/alpha value has been determined - this.clippingNode = clippingAlpha(); + result = clippingAlpha(); } else { @@ -150,6 +149,8 @@ class NodeMaterial extends ShaderMaterial { } + return result; + } setupDepth( builder ) { diff --git a/examples/webgpu_clipping.html b/examples/webgpu_clipping.html index 768b5e401f3829..0d71c4244d39a6 100644 --- a/examples/webgpu_clipping.html +++ b/examples/webgpu_clipping.html @@ -157,7 +157,7 @@ const gui = new GUI(), props = { - alphaToCoverage: false, + alphaToCoverage: true, }, folderLocal = gui.addFolder( 'Local Clipping' ), propsLocal = { From db465a72c701a103068cf28c018791a68c5e3253 Mon Sep 17 00:00:00 2001 From: aardgoose Date: Tue, 6 Feb 2024 11:25:08 +0000 Subject: [PATCH 05/14] remove unused import --- examples/webgpu_clipping.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/webgpu_clipping.html b/examples/webgpu_clipping.html index 0d71c4244d39a6..06b8c6eb94afaa 100644 --- a/examples/webgpu_clipping.html +++ b/examples/webgpu_clipping.html @@ -23,7 +23,7 @@