-
-
Notifications
You must be signed in to change notification settings - Fork 413
feat(WebGPU): Add Multiscale AntiAliasing to renderWindow #3417
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -36,14 +36,15 @@ fn main( | |||||
| } | ||||||
| `; | ||||||
|
|
||||||
| // ---------------------------------------------------------------------------- | ||||||
|
|
||||||
| function vtkWebGPUOrderIndependentTranslucentPass(publicAPI, model) { | ||||||
| // Set our className | ||||||
| model.classHierarchy.push('vtkWebGPUOrderIndependentTranslucentPass'); | ||||||
|
|
||||||
| // this pass implements a forward rendering pipeline | ||||||
| // if both volumes and opaque geometry are present | ||||||
| // it will mix the two together by capturing a zbuffer | ||||||
| // first | ||||||
| // This pass implements a forward rendering pipeline for translucent geometry. | ||||||
| // It uses order-independent transparency (OIT) with weighted blended | ||||||
| // compositing, reading the opaque depth buffer for depth testing. | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @sankhesh is the OIT pass really alpha blending in VTK.js ? According to Lucas Gandel, it is not just an alpha blending pass in VTK (hence there would be more to do here).
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good question — in vtk.js this pass isn’t “just alpha blending” in the usual draw-order-dependent sense. The WebGPU OITPass implements a weighted blended oit approach: it renders translucent geometry into accumulation + mrt buffers, then performs a full-screen composite over the opaque color using those resolved textures. |
||||||
| publicAPI.traverse = (renNode, viewNode) => { | ||||||
| if (model.deleted) { | ||||||
| return; | ||||||
|
|
@@ -53,46 +54,112 @@ function vtkWebGPUOrderIndependentTranslucentPass(publicAPI, model) { | |||||
| model._currentParent = viewNode; | ||||||
|
|
||||||
| const device = viewNode.getDevice(); | ||||||
| const sampleCount = viewNode.getMultiSample ? viewNode.getMultiSample() : 1; | ||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
|
|
||||||
| // If sampleCount changed, tear down | ||||||
| if ( | ||||||
| model.translucentRenderEncoder && | ||||||
| model._currentSampleCount !== sampleCount | ||||||
| ) { | ||||||
| model.translucentRenderEncoder = null; | ||||||
| model.translucentColorTexture = null; | ||||||
| model.translucentAccumulateTexture = null; | ||||||
| model.translucentResolveColorTexture = null; | ||||||
| model.translucentResolveAccumulateTexture = null; | ||||||
| model._resolveColorView = null; | ||||||
| model._resolveAccumulateView = null; | ||||||
| } | ||||||
|
|
||||||
| if (!model.translucentRenderEncoder) { | ||||||
| publicAPI.createRenderEncoder(); | ||||||
| publicAPI.createRenderEncoder(sampleCount); | ||||||
| publicAPI.createFinalEncoder(); | ||||||
| model._currentSampleCount = sampleCount; | ||||||
| model.translucentColorTexture = vtkWebGPUTexture.newInstance({ | ||||||
| label: 'translucentPassColor', | ||||||
| }); | ||||||
| model.translucentColorTexture.create(device, { | ||||||
| width: viewNode.getCanvas().width, | ||||||
| height: viewNode.getCanvas().height, | ||||||
| format: 'rgba16float', | ||||||
| sampleCount, | ||||||
| /* eslint-disable no-undef */ | ||||||
| /* eslint-disable no-bitwise */ | ||||||
| usage: | ||||||
| GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TEXTURE_BINDING, | ||||||
| GPUTextureUsage.RENDER_ATTACHMENT | | ||||||
| (sampleCount === 1 ? GPUTextureUsage.TEXTURE_BINDING : 0), | ||||||
| }); | ||||||
| const v1 = model.translucentColorTexture.createView('oitpColorTexture'); | ||||||
| model.translucentRenderEncoder.setColorTextureView(0, v1); | ||||||
|
|
||||||
| // Resolve color texture for MSAA | ||||||
| if (sampleCount > 1) { | ||||||
| model.translucentResolveColorTexture = vtkWebGPUTexture.newInstance({ | ||||||
| label: 'translucentPassResolveColor', | ||||||
| }); | ||||||
| model.translucentResolveColorTexture.create(device, { | ||||||
| width: viewNode.getCanvas().width, | ||||||
| height: viewNode.getCanvas().height, | ||||||
| format: 'rgba16float', | ||||||
| usage: | ||||||
| GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TEXTURE_BINDING, | ||||||
| }); | ||||||
| model._resolveColorView = | ||||||
| model.translucentResolveColorTexture.createView('oitpColorTexture'); | ||||||
| model.translucentRenderEncoder.setResolveTextureView( | ||||||
| 0, | ||||||
| model._resolveColorView | ||||||
| ); | ||||||
| } | ||||||
|
|
||||||
| model.translucentAccumulateTexture = vtkWebGPUTexture.newInstance({ | ||||||
| label: 'translucentPassAccumulate', | ||||||
| }); | ||||||
| model.translucentAccumulateTexture.create(device, { | ||||||
| width: viewNode.getCanvas().width, | ||||||
| height: viewNode.getCanvas().height, | ||||||
| format: 'r16float', | ||||||
| sampleCount, | ||||||
| /* eslint-disable no-undef */ | ||||||
| /* eslint-disable no-bitwise */ | ||||||
| usage: | ||||||
| GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TEXTURE_BINDING, | ||||||
| GPUTextureUsage.RENDER_ATTACHMENT | | ||||||
| (sampleCount === 1 ? GPUTextureUsage.TEXTURE_BINDING : 0), | ||||||
| }); | ||||||
| const v2 = | ||||||
| model.translucentAccumulateTexture.createView('oitpAccumTexture'); | ||||||
| model.translucentRenderEncoder.setColorTextureView(1, v2); | ||||||
|
|
||||||
| // Resolve accumulate texture for MSAA | ||||||
| if (sampleCount > 1) { | ||||||
| model.translucentResolveAccumulateTexture = | ||||||
| vtkWebGPUTexture.newInstance({ | ||||||
| label: 'translucentPassResolveAccumulate', | ||||||
| }); | ||||||
| model.translucentResolveAccumulateTexture.create(device, { | ||||||
| width: viewNode.getCanvas().width, | ||||||
| height: viewNode.getCanvas().height, | ||||||
| format: 'r16float', | ||||||
| usage: | ||||||
| GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TEXTURE_BINDING, | ||||||
| }); | ||||||
| model._resolveAccumulateView = | ||||||
| model.translucentResolveAccumulateTexture.createView( | ||||||
| 'oitpAccumTexture' | ||||||
| ); | ||||||
| model.translucentRenderEncoder.setResolveTextureView( | ||||||
| 1, | ||||||
| model._resolveAccumulateView | ||||||
| ); | ||||||
| } | ||||||
| model.fullScreenQuad = vtkWebGPUFullScreenQuad.newInstance(); | ||||||
| model.fullScreenQuad.setDevice(viewNode.getDevice()); | ||||||
| model.fullScreenQuad.setPipelineHash('oitpfsq'); | ||||||
| model.fullScreenQuad.setTextureViews( | ||||||
| model.translucentRenderEncoder.getColorTextureViews() | ||||||
| ); | ||||||
| // Use resolved textures for the full screen quad if MSAA is on | ||||||
| const views = | ||||||
| sampleCount > 1 | ||||||
| ? [model._resolveColorView, model._resolveAccumulateView] | ||||||
| : model.translucentRenderEncoder.getColorTextureViews(); | ||||||
| model.fullScreenQuad.setTextureViews(views); | ||||||
| model.fullScreenQuad.setFragmentShaderTemplate(oitpFragTemplate); | ||||||
| } else { | ||||||
| model.translucentColorTexture.resizeToMatch( | ||||||
|
|
@@ -101,6 +168,14 @@ function vtkWebGPUOrderIndependentTranslucentPass(publicAPI, model) { | |||||
| model.translucentAccumulateTexture.resizeToMatch( | ||||||
| model.colorTextureView.getTexture() | ||||||
| ); | ||||||
| if (model.translucentResolveColorTexture) { | ||||||
| model.translucentResolveColorTexture.resizeToMatch( | ||||||
| model.colorTextureView.getTexture() | ||||||
| ); | ||||||
| model.translucentResolveAccumulateTexture.resizeToMatch( | ||||||
| model.colorTextureView.getTexture() | ||||||
| ); | ||||||
| } | ||||||
| } | ||||||
|
|
||||||
| model.translucentRenderEncoder.setDepthTextureView(model.depthTextureView); | ||||||
|
|
@@ -129,10 +204,16 @@ function vtkWebGPUOrderIndependentTranslucentPass(publicAPI, model) { | |||||
| model.translucentAccumulateTexture, | ||||||
| ]; | ||||||
|
|
||||||
| publicAPI.createRenderEncoder = () => { | ||||||
| publicAPI.createRenderEncoder = (sampleCount = 1) => { | ||||||
| model.translucentRenderEncoder = vtkWebGPURenderEncoder.newInstance({ | ||||||
| label: 'translucentRender', | ||||||
| }); | ||||||
| // Set multisample state if needed | ||||||
| if (sampleCount > 1) { | ||||||
| const settings = model.translucentRenderEncoder.getPipelineSettings(); | ||||||
| settings.multisample = { count: sampleCount }; | ||||||
| model.translucentRenderEncoder.setPipelineSettings(settings); | ||||||
| } | ||||||
| const rDesc = model.translucentRenderEncoder.getDescription(); | ||||||
| rDesc.colorAttachments = [ | ||||||
| { | ||||||
|
|
@@ -261,6 +342,8 @@ function vtkWebGPUOrderIndependentTranslucentPass(publicAPI, model) { | |||||
| const DEFAULT_VALUES = { | ||||||
| colorTextureView: null, | ||||||
| depthTextureView: null, | ||||||
| translucentResolveColorTexture: null, | ||||||
| translucentResolveAccumulateTexture: null, | ||||||
| }; | ||||||
|
|
||||||
| // ---------------------------------------------------------------------------- | ||||||
|
|
||||||
This file was deleted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.