@@ -414,24 +414,22 @@ class RendererWebGPU extends Renderer3D {
414414 multisample : { count : sampleCount } ,
415415 depthStencil : {
416416 format : depthFormat ,
417- depthWriteEnabled : true ,
417+ depthWriteEnabled : ! clipping ,
418418 depthCompare : 'less-equal' ,
419419 stencilFront : {
420- compare : clipping ? 'always' : ( clipApplied ? 'equal' : 'always' ) ,
420+ compare : clipping ? 'always' : ( clipApplied ? 'not- equal' : 'always' ) ,
421421 failOp : 'keep' ,
422422 depthFailOp : 'keep' ,
423423 passOp : clipping ? 'replace' : 'keep' ,
424424 } ,
425425 stencilBack : {
426- compare : clipping ? 'always' : ( clipApplied ? 'equal' : 'always' ) ,
426+ compare : clipping ? 'always' : ( clipApplied ? 'not- equal' : 'always' ) ,
427427 failOp : 'keep' ,
428428 depthFailOp : 'keep' ,
429429 passOp : clipping ? 'replace' : 'keep' ,
430430 } ,
431- stencilReadMask : clipApplied ? 0xFFFFFFFF : 0x00000000 ,
432- stencilWriteMask : clipping ? 0xFFFFFFFF : 0x00000000 ,
433- stencilLoadOp : "load" ,
434- stencilStoreOp : "store" ,
431+ stencilReadMask : 0xFF ,
432+ stencilWriteMask : clipping ? 0xFF : 0x00 ,
435433 } ,
436434 } ) ;
437435 shader . _pipelineCache . set ( key , pipeline ) ;
@@ -1070,6 +1068,18 @@ class RendererWebGPU extends Renderer3D {
10701068 const passEncoder = commandEncoder . beginRenderPass ( renderPassDescriptor ) ;
10711069 const currentShader = this . _curShader ;
10721070 passEncoder . setPipeline ( currentShader . getPipeline ( this . _shaderOptions ( { mode } ) ) ) ;
1071+
1072+ // Set stencil reference value for clipping
1073+ const drawTarget = this . drawTarget ( ) ;
1074+ if ( drawTarget . _isClipApplied && ! this . _clipping ) {
1075+ // When using the clip mask, test against reference value 0 (background)
1076+ // WebGL uses NOTEQUAL with ref 0, so fragments pass where stencil != 0
1077+ // In WebGPU with 'not-equal', we need ref 0 to pass where stencil != 0
1078+ passEncoder . setStencilReference ( 0 ) ;
1079+ } else if ( this . _clipping ) {
1080+ // When writing to the clip mask, write reference value 1
1081+ passEncoder . setStencilReference ( 1 ) ;
1082+ }
10731083 // Bind vertex buffers
10741084 for ( const buffer of this . _getVertexBuffers ( currentShader ) ) {
10751085 const location = currentShader . attributes [ buffer . attr ] . location ;
@@ -1569,6 +1579,78 @@ class RendererWebGPU extends Renderer3D {
15691579 return { adjustedWidth : width , adjustedHeight : height } ;
15701580 }
15711581
1582+ _applyClip ( ) {
1583+ const commandEncoder = this . device . createCommandEncoder ( ) ;
1584+
1585+ const activeFramebuffer = this . activeFramebuffer ( ) ;
1586+ const depthTexture = activeFramebuffer ?
1587+ ( activeFramebuffer . aaDepthTexture || activeFramebuffer . depthTexture ) :
1588+ this . depthTexture ;
1589+
1590+ if ( ! depthTexture ) {
1591+ return ;
1592+ }
1593+
1594+ const depthStencilAttachment = {
1595+ view : depthTexture . createView ( ) ,
1596+ stencilLoadOp : 'clear' ,
1597+ stencilStoreOp : 'store' ,
1598+ stencilClearValue : 0 ,
1599+ depthReadOnly : true ,
1600+ stencilReadOnly : false ,
1601+ } ;
1602+
1603+ const renderPassDescriptor = {
1604+ colorAttachments : [ ] ,
1605+ depthStencilAttachment : depthStencilAttachment ,
1606+ } ;
1607+
1608+ const passEncoder = commandEncoder . beginRenderPass ( renderPassDescriptor ) ;
1609+ passEncoder . end ( ) ;
1610+
1611+ this . _pendingCommandEncoders . push ( commandEncoder . finish ( ) ) ;
1612+ this . _hasPendingDraws = true ;
1613+ }
1614+
1615+ _unapplyClip ( ) {
1616+ // In WebGPU, clip unapplication is handled through pipeline state rather than direct commands
1617+ // The stencil test configuration is set in the render pipeline based on _clipping and _clipInvert flags
1618+ // This is already handled in the _shaderOptions() method and pipeline creation
1619+ }
1620+
1621+ _clearClipBuffer ( ) {
1622+ const commandEncoder = this . device . createCommandEncoder ( ) ;
1623+
1624+ const activeFramebuffer = this . activeFramebuffer ( ) ;
1625+ const depthTexture = activeFramebuffer ?
1626+ ( activeFramebuffer . aaDepthTexture || activeFramebuffer . depthTexture ) :
1627+ this . depthTexture ;
1628+
1629+ if ( ! depthTexture ) {
1630+ return ;
1631+ }
1632+
1633+ const depthStencilAttachment = {
1634+ view : depthTexture . createView ( ) ,
1635+ stencilLoadOp : 'clear' ,
1636+ stencilStoreOp : 'store' ,
1637+ stencilClearValue : 1 ,
1638+ depthReadOnly : true ,
1639+ stencilReadOnly : false ,
1640+ } ;
1641+
1642+ const renderPassDescriptor = {
1643+ colorAttachments : [ ] ,
1644+ depthStencilAttachment : depthStencilAttachment ,
1645+ } ;
1646+
1647+ const passEncoder = commandEncoder . beginRenderPass ( renderPassDescriptor ) ;
1648+ passEncoder . end ( ) ;
1649+
1650+ this . _pendingCommandEncoders . push ( commandEncoder . finish ( ) ) ;
1651+ this . _hasPendingDraws = true ;
1652+ }
1653+
15721654 _applyStencilTestIfClipping ( ) {
15731655 // TODO
15741656 }
0 commit comments