11import { mat3 , mat4 } from 'gl-matrix' ;
22
33import * as macro from 'vtk.js/Sources/macros' ;
4+ import vtkDataSet from 'vtk.js/Sources/Common/DataModel/DataSet' ;
5+ import CoincidentTopologyHelper from 'vtk.js/Sources/Rendering/Core/Mapper/CoincidentTopologyHelper' ;
46import vtkMapper from 'vtk.js/Sources/Rendering/Core/Mapper' ;
57import vtkProp from 'vtk.js/Sources/Rendering/Core/Prop' ;
68import vtkProperty from 'vtk.js/Sources/Rendering/Core/Property' ;
@@ -12,6 +14,8 @@ import vtkWebGPUUniformBuffer from 'vtk.js/Sources/Rendering/WebGPU/UniformBuffe
1214import vtkWebGPUSimpleMapper from 'vtk.js/Sources/Rendering/WebGPU/SimpleMapper' ;
1315import vtkWebGPUTypes from 'vtk.js/Sources/Rendering/WebGPU/Types' ;
1416
17+ const { Resolve } = CoincidentTopologyHelper ;
18+ const { FieldAssociations } = vtkDataSet ;
1519const { BufferUsage, PrimitiveTypes } = vtkWebGPUBufferManager ;
1620const { Representation } = vtkProperty ;
1721const { ScalarMode } = vtkMapper ;
@@ -541,6 +545,9 @@ function vtkWebGPUCellArrayMapper(publicAPI, model) {
541545 model . UBO . setValue ( 'LineWidth' , ppty . getLineWidth ( ) ) ;
542546 model . UBO . setValue ( 'Opacity' , ppty . getOpacity ( ) ) ;
543547 model . UBO . setValue ( 'PropID' , model . WebGPUActor . getPropID ( ) ) ;
548+ const cp = publicAPI . getCoincidentParameters ( ) ;
549+ model . UBO . setValue ( 'CoincidentFactor' , cp . factor ) ;
550+ model . UBO . setValue ( 'CoincidentOffset' , cp . offset ) ;
544551
545552 // Only send if needed
546553 model . UBO . sendIfNeeded ( model . WebGPURenderWindow . getDevice ( ) ) ;
@@ -582,6 +589,67 @@ function vtkWebGPUCellArrayMapper(publicAPI, model) {
582589 } ,
583590 } ) ;
584591
592+ publicAPI . getCoincidentParameters = ( ) => {
593+ let cp = {
594+ factor : 0.0 ,
595+ offset : 0.0 ,
596+ } ;
597+
598+ const actor = model . WebGPUActor ?. getRenderable ( ) ;
599+ const prop = actor ?. getProperty ?. ( ) ;
600+ if ( ! prop ) {
601+ return cp ;
602+ }
603+
604+ if (
605+ // backwards compat with code that (errorneously) set this to boolean
606+ // eslint-disable-next-line eqeqeq
607+ model . renderable . getResolveCoincidentTopology ( ) ==
608+ Resolve . PolygonOffset ||
609+ ( prop . getEdgeVisibility ( ) &&
610+ prop . getRepresentation ( ) === Representation . SURFACE )
611+ ) {
612+ const primType = model . primitiveType ;
613+ if (
614+ primType === PrimitiveTypes . Verts ||
615+ prop . getRepresentation ( ) === Representation . POINTS
616+ ) {
617+ cp = model . renderable . getCoincidentTopologyPointOffsetParameter ( ) ;
618+ } else if (
619+ primType === PrimitiveTypes . Lines ||
620+ prop . getRepresentation ( ) === Representation . WIREFRAME
621+ ) {
622+ cp = model . renderable . getCoincidentTopologyLineOffsetParameters ( ) ;
623+ } else if (
624+ primType === PrimitiveTypes . Triangles ||
625+ primType === PrimitiveTypes . TriangleStrips
626+ ) {
627+ cp = model . renderable . getCoincidentTopologyPolygonOffsetParameters ( ) ;
628+ }
629+
630+ if (
631+ primType === PrimitiveTypes . TriangleEdges ||
632+ primType === PrimitiveTypes . TriangleStripEdges
633+ ) {
634+ cp = model . renderable . getCoincidentTopologyPolygonOffsetParameters ( ) ;
635+ cp . factor /= 2.0 ;
636+ cp . offset /= 2.0 ;
637+ }
638+ }
639+
640+ // Hardware point picking always offsets due to the saved depth buffer.
641+ const selector = model . WebGPURenderer ?. getSelector ?. ( ) ;
642+ if (
643+ selector &&
644+ selector . getFieldAssociation ( ) ===
645+ FieldAssociations . FIELD_ASSOCIATION_POINTS
646+ ) {
647+ cp . offset -= 2.0 ;
648+ }
649+
650+ return cp ;
651+ } ;
652+
585653 publicAPI . replaceShaderPosition = ( hash , pipeline , vertexInput ) => {
586654 const vDesc = pipeline . getShaderDescription ( 'vertex' ) ;
587655 vDesc . addBuiltinOutput ( 'vec4<f32>' , '@builtin(position) Position' ) ;
@@ -631,16 +699,42 @@ function vtkWebGPUCellArrayMapper(publicAPI, model) {
631699 ] ) . result ;
632700 }
633701 code = vtkWebGPUShaderCache . substitute ( code , '//VTK::Position::Impl' , [
702+ // Match the OpenGL coincident-topology constant offset scale (~1 / 2^16 = 0.000016)
703+ ' pCoord.z = clamp(pCoord.z - 0.000016 * mapperUBO.CoincidentOffset * pCoord.w, 0.0, pCoord.w);' ,
634704 ' output.Position = pCoord;' ,
635705 ] ) . result ;
636-
637706 vDesc . setCode ( code ) ;
638707 } ;
639708 model . shaderReplacements . set (
640709 'replaceShaderPosition' ,
641710 publicAPI . replaceShaderPosition
642711 ) ;
643712
713+ publicAPI . replaceShaderCoincidentOffset = ( hash , pipeline , vertexInput ) => {
714+ const fDesc = pipeline . getShaderDescription ( 'fragment' ) ;
715+ if ( ! fDesc ) {
716+ return ;
717+ }
718+
719+ fDesc . addBuiltinInput ( 'vec4<f32>' , '@builtin(position) fragPos' ) ;
720+ fDesc . addBuiltinOutput ( 'f32' , '@builtin(frag_depth) fragDepth' ) ;
721+
722+ let code = fDesc . getCode ( ) ;
723+ code = vtkWebGPUShaderCache . substitute ( code , '//VTK::Position::Impl' , [
724+ ' var coincidentDepth: f32 = input.fragPos.z;' ,
725+ ' if (mapperUBO.CoincidentFactor != 0.0) {' ,
726+ ' let cscale = length(vec2<f32>(dpdx(input.fragPos.z), dpdy(input.fragPos.z)));' ,
727+ ' coincidentDepth = coincidentDepth - mapperUBO.CoincidentFactor * cscale;' ,
728+ ' }' ,
729+ ' output.fragDepth = clamp(coincidentDepth, 0.0, 1.0);' ,
730+ ] ) . result ;
731+ fDesc . setCode ( code ) ;
732+ } ;
733+ model . shaderReplacements . set (
734+ 'replaceShaderCoincidentOffset' ,
735+ publicAPI . replaceShaderCoincidentOffset
736+ ) ;
737+
644738 publicAPI . replaceShaderNormal = ( hash , pipeline , vertexInput ) => {
645739 const normalBuffer = vertexInput . getBuffer ( 'normalMC' ) ;
646740 const actor = model . WebGPUActor . getRenderable ( ) ;
@@ -1487,6 +1581,8 @@ export function extend(publicAPI, model, initiaLalues = {}) {
14871581 model . UBO . addEntry ( 'Opacity' , 'f32' ) ;
14881582 model . UBO . addEntry ( 'OpacityBF' , 'f32' ) ;
14891583 model . UBO . addEntry ( 'ZValue' , 'f32' ) ;
1584+ model . UBO . addEntry ( 'CoincidentFactor' , 'f32' ) ;
1585+ model . UBO . addEntry ( 'CoincidentOffset' , 'f32' ) ;
14901586 model . UBO . addEntry ( 'PropID' , 'u32' ) ;
14911587 model . UBO . addEntry ( 'ClipNear' , 'f32' ) ;
14921588 model . UBO . addEntry ( 'ClipFar' , 'f32' ) ;
0 commit comments