Skip to content

Commit 871a84c

Browse files
dakerfinetjul
authored andcommitted
feat(WebGPU): add coincident topology offsets to CellArrayMapper
1 parent 6bfb4c7 commit 871a84c

1 file changed

Lines changed: 97 additions & 1 deletion

File tree

  • Sources/Rendering/WebGPU/CellArrayMapper

Sources/Rendering/WebGPU/CellArrayMapper/index.js

Lines changed: 97 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import { mat3, mat4 } from 'gl-matrix';
22

33
import * 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';
46
import vtkMapper from 'vtk.js/Sources/Rendering/Core/Mapper';
57
import vtkProp from 'vtk.js/Sources/Rendering/Core/Prop';
68
import vtkProperty from 'vtk.js/Sources/Rendering/Core/Property';
@@ -12,6 +14,8 @@ import vtkWebGPUUniformBuffer from 'vtk.js/Sources/Rendering/WebGPU/UniformBuffe
1214
import vtkWebGPUSimpleMapper from 'vtk.js/Sources/Rendering/WebGPU/SimpleMapper';
1315
import vtkWebGPUTypes from 'vtk.js/Sources/Rendering/WebGPU/Types';
1416

17+
const { Resolve } = CoincidentTopologyHelper;
18+
const { FieldAssociations } = vtkDataSet;
1519
const { BufferUsage, PrimitiveTypes } = vtkWebGPUBufferManager;
1620
const { Representation } = vtkProperty;
1721
const { 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

Comments
 (0)