From 7d01e1472619ccd9c15cfc783c0208ef2b0f8a66 Mon Sep 17 00:00:00 2001 From: aardgoose Date: Wed, 5 Jun 2024 14:50:41 +0100 Subject: [PATCH] hardware clippoing --- examples/jsm/nodes/accessors/BuiltinNode.js | 28 ++++++++++++++ examples/jsm/nodes/accessors/ClippingNode.js | 37 ++++++++++++++++++- examples/jsm/nodes/materials/NodeMaterial.js | 25 ++++++++++++- .../renderers/webgl/nodes/GLSLNodeBuilder.js | 30 ++++++++++++++- .../renderers/webgpu/nodes/WGSLNodeBuilder.js | 20 ++++++++++ examples/webgpu_clipping.html | 2 +- 6 files changed, 137 insertions(+), 5 deletions(-) create mode 100644 examples/jsm/nodes/accessors/BuiltinNode.js diff --git a/examples/jsm/nodes/accessors/BuiltinNode.js b/examples/jsm/nodes/accessors/BuiltinNode.js new file mode 100644 index 00000000000000..84d0b37513fc62 --- /dev/null +++ b/examples/jsm/nodes/accessors/BuiltinNode.js @@ -0,0 +1,28 @@ +import Node, { addNodeClass } from '../core/Node.js'; +import { nodeProxy } from '../shadernode/ShaderNode.js'; + +class BuiltinNode extends Node { + + constructor( name ) { + + super( 'float' ); + + this.name = name; + + this.isBuiltNode = true; + + } + + generate( /* builder */ ) { + + return this.name; + + } + +} + +export default BuiltinNode; + +export const builtin = nodeProxy( BuiltinNode ); + +addNodeClass( 'BuiltinhNode', BuiltinNode ); diff --git a/examples/jsm/nodes/accessors/ClippingNode.js b/examples/jsm/nodes/accessors/ClippingNode.js index b77ce29fc084d7..e4b79ff76388d9 100644 --- a/examples/jsm/nodes/accessors/ClippingNode.js +++ b/examples/jsm/nodes/accessors/ClippingNode.js @@ -1,12 +1,14 @@ import Node from '../core/Node.js'; import { nodeObject } from '../shadernode/ShaderNode.js'; -import { positionView } from './PositionNode.js'; +import { positionLocal, 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 { uniforms } from './UniformsNode.js'; +import { modelWorldMatrix } from '../accessors/ModelNode.js'; +import { builtin } from './BuiltinNode.js'; class ClippingNode extends Node { @@ -32,6 +34,10 @@ class ClippingNode extends Node { return this.setupAlphaToCoverage( clippingContext.planes, numClippingPlanes, numUnionClippingPlanes ); + } else if ( this.scope === ClippingNode.HARDWARE ) { + + return this.setupHardwareClipping( clippingContext.planes, numUnionClippingPlanes, builder ); + } else { return this.setupDefault( clippingContext.planes, numClippingPlanes, numUnionClippingPlanes ); @@ -133,13 +139,42 @@ class ClippingNode extends Node { } + setupHardwareClipping( planes, numUnionClippingPlanes, builder ) { + + return tslFn( () => { + + const clippingPlanes = uniforms( planes ); + let plane; + + console.log( 'hwclipping'); + + const hw_clip_distances = builtin( builder.getClipDistance() ); + + const worldPosition = modelWorldMatrix.mul( positionLocal ).xyz.toVar(); + + for ( let i = 0; i < numUnionClippingPlanes; i ++ ) { + + plane = clippingPlanes.element( i ); + + const distance = worldPosition.dot( plane.xyz ).add( plane.w ); + hw_clip_distances.element( i ).assign( distance ); + + } + + } )(); + + } + } ClippingNode.ALPHA_TO_COVERAGE = 'alphaToCoverage'; ClippingNode.DEFAULT = 'default'; +ClippingNode.HARDWARE = 'hardware'; export default ClippingNode; export const clipping = () => nodeObject( new ClippingNode() ); export const clippingAlpha = () => nodeObject( new ClippingNode( ClippingNode.ALPHA_TO_COVERAGE ) ); + +export const hardwareClipping = () => nodeObject( new ClippingNode( ClippingNode.HARDWARE ) ); diff --git a/examples/jsm/nodes/materials/NodeMaterial.js b/examples/jsm/nodes/materials/NodeMaterial.js index 72ded5b3062437..12b752779fd908 100644 --- a/examples/jsm/nodes/materials/NodeMaterial.js +++ b/examples/jsm/nodes/materials/NodeMaterial.js @@ -22,7 +22,7 @@ import EnvironmentNode from '../lighting/EnvironmentNode.js'; import IrradianceNode from '../lighting/IrradianceNode.js'; import { depthPixel } from '../display/ViewportDepthNode.js'; import { cameraLogDepth } from '../accessors/CameraNode.js'; -import { clipping, clippingAlpha } from '../accessors/ClippingNode.js'; +import { clipping, clippingAlpha, hardwareClipping } from '../accessors/ClippingNode.js'; import { faceDirection } from '../display/FrontFacingNode.js'; const NodeMaterials = new Map(); @@ -42,6 +42,7 @@ class NodeMaterial extends Material { this.fog = true; this.lights = true; this.normals = true; + this.hardwareClipping = true; this.lightsNode = null; this.envNode = null; @@ -146,7 +147,7 @@ class NodeMaterial extends Material { setupClipping( builder ) { - if ( builder.clippingContext === null ) return null; + if ( builder.clippingContext === null || this.hardwareClipping === true ) return null; const { globalClippingCount, localClippingCount } = builder.clippingContext; @@ -171,6 +172,24 @@ class NodeMaterial extends Material { } + setupHardwareClipping( builder ) { + + if ( builder.clippingContext === null ) return null; + + const { localClipIntersection, globalClippingCount } = builder.clippingContext; + + if ( globalClippingCount && localClipIntersection && ! this.alphaToCoverage ) { + + builder.enableHardwareClipping( globalClippingCount ); + builder.stack.add( hardwareClipping() ); + + this.hardwareClipping = true; + } + + return; + + } + setupDepth( builder ) { const { renderer } = builder; @@ -244,6 +263,8 @@ class NodeMaterial extends Material { } + this.setupHardwareClipping( builder ); + const mvp = modelViewProjection(); builder.context.vertex = builder.removeStack(); diff --git a/examples/jsm/renderers/webgl/nodes/GLSLNodeBuilder.js b/examples/jsm/renderers/webgl/nodes/GLSLNodeBuilder.js index aa60d4b484c852..47556964501e0b 100644 --- a/examples/jsm/renderers/webgl/nodes/GLSLNodeBuilder.js +++ b/examples/jsm/renderers/webgl/nodes/GLSLNodeBuilder.js @@ -549,6 +549,12 @@ ${ flowData.code } } + getClipDistance() { + + return 'gl_ClipDistance'; + + } + isAvailable( name ) { return supports[ name ] === true; @@ -561,6 +567,26 @@ ${ flowData.code } } + enableHardwareClipping( planeCount ) { + + const renderer = this.renderer; + + const gl = renderer.getContext(); + const ext = gl.getExtension( 'WEBGL_clip_cull_distance' ); + + if ( ext && planeCount <= gl.getParameter( ext.MAX_CLIP_DISTANCES_WEBGL ) ) { + + gl.enable( ext.CLIP_DISTANCE0_WEBGL + planeCount - 1 ); + console.log( 'requested hardware clipping', planeCount, gl.getParameter( ext.MAX_CLIP_DISTANCES_WEBGL ) ); + + return true; + + } + + return false; + + } + registerTransform( varyingName, attributeNode ) { this.transforms.push( { varyingName, attributeNode } ); @@ -602,6 +628,8 @@ ${vars} ${ this.getSignature() } +${ true ? '#extension GL_ANGLE_clip_cull_distance : enable' : '' } + // precision ${ defaultPrecisions } @@ -736,7 +764,7 @@ void main() { this.vertexShader = this._getGLSLVertexCode( shadersData.vertex ); this.fragmentShader = this._getGLSLFragmentCode( shadersData.fragment ); - +//console.log( this.vertexShader ); } else { this.computeShader = this._getGLSLVertexCode( shadersData.compute ); diff --git a/examples/jsm/renderers/webgpu/nodes/WGSLNodeBuilder.js b/examples/jsm/renderers/webgpu/nodes/WGSLNodeBuilder.js index 37d3cefe97b104..b2548af27cd725 100644 --- a/examples/jsm/renderers/webgpu/nodes/WGSLNodeBuilder.js +++ b/examples/jsm/renderers/webgpu/nodes/WGSLNodeBuilder.js @@ -594,12 +594,31 @@ ${ flowData.code } } + getClipDistance() { + + return 'hw_clip_distances'; + + } + isFlipY() { return false; } + enableHardwareClipping( planeCount ) { + + if ( planeCount <= 8 && this.renderer.backend.hasFeature( 'clip-distances' ) ) { + + this.getBuiltin( 'clip_distances', 'hw_clip_distances', `array`, 'vertex' ); + return true; + + } + + return false; + + } + getBuiltins( shaderStage ) { const snippets = []; @@ -975,6 +994,7 @@ ${ flowData.code } this.vertexShader = this._getWGSLVertexCode( shadersData.vertex ); this.fragmentShader = this._getWGSLFragmentCode( shadersData.fragment ); + console.log( this.vertexShader ); } else { this.computeShader = this._getWGSLComputeCode( shadersData.compute, ( this.object.workgroupSize || [ 64 ] ).join( ', ' ) ); diff --git a/examples/webgpu_clipping.html b/examples/webgpu_clipping.html index 4e5b37612a5175..5be5136783357d 100644 --- a/examples/webgpu_clipping.html +++ b/examples/webgpu_clipping.html @@ -131,7 +131,7 @@ // Renderer - renderer = new WebGPURenderer( { antialias: true } ); + renderer = new WebGPURenderer( { antialias: true, forceWebGL: true } ); renderer.shadowMap.enabled = true; renderer.setPixelRatio( window.devicePixelRatio ); renderer.setSize( window.innerWidth, window.innerHeight );