@@ -36,14 +36,15 @@ fn main(
3636}
3737` ;
3838
39+ // ----------------------------------------------------------------------------
40+
3941function vtkWebGPUOrderIndependentTranslucentPass ( publicAPI , model ) {
4042 // Set our className
4143 model . classHierarchy . push ( 'vtkWebGPUOrderIndependentTranslucentPass' ) ;
4244
43- // this pass implements a forward rendering pipeline
44- // if both volumes and opaque geometry are present
45- // it will mix the two together by capturing a zbuffer
46- // first
45+ // This pass implements a forward rendering pipeline for translucent geometry.
46+ // It uses order-independent transparency (OIT) with weighted blended
47+ // compositing, reading the opaque depth buffer for depth testing.
4748 publicAPI . traverse = ( renNode , viewNode ) => {
4849 if ( model . deleted ) {
4950 return ;
@@ -53,46 +54,112 @@ function vtkWebGPUOrderIndependentTranslucentPass(publicAPI, model) {
5354 model . _currentParent = viewNode ;
5455
5556 const device = viewNode . getDevice ( ) ;
57+ const sampleCount = viewNode . getSampleCount ? viewNode . getSampleCount ( ) : 1 ;
58+
59+ // If sampleCount changed, tear down
60+ if (
61+ model . translucentRenderEncoder &&
62+ model . _currentSampleCount !== sampleCount
63+ ) {
64+ model . translucentRenderEncoder = null ;
65+ model . translucentColorTexture = null ;
66+ model . translucentAccumulateTexture = null ;
67+ model . translucentResolveColorTexture = null ;
68+ model . translucentResolveAccumulateTexture = null ;
69+ model . _resolveColorView = null ;
70+ model . _resolveAccumulateView = null ;
71+ }
5672
5773 if ( ! model . translucentRenderEncoder ) {
58- publicAPI . createRenderEncoder ( ) ;
74+ publicAPI . createRenderEncoder ( sampleCount ) ;
5975 publicAPI . createFinalEncoder ( ) ;
76+ model . _currentSampleCount = sampleCount ;
6077 model . translucentColorTexture = vtkWebGPUTexture . newInstance ( {
6178 label : 'translucentPassColor' ,
6279 } ) ;
6380 model . translucentColorTexture . create ( device , {
6481 width : viewNode . getCanvas ( ) . width ,
6582 height : viewNode . getCanvas ( ) . height ,
6683 format : 'rgba16float' ,
84+ sampleCount,
6785 /* eslint-disable no-undef */
6886 /* eslint-disable no-bitwise */
6987 usage :
70- GPUTextureUsage . RENDER_ATTACHMENT | GPUTextureUsage . TEXTURE_BINDING ,
88+ GPUTextureUsage . RENDER_ATTACHMENT |
89+ ( sampleCount === 1 ? GPUTextureUsage . TEXTURE_BINDING : 0 ) ,
7190 } ) ;
7291 const v1 = model . translucentColorTexture . createView ( 'oitpColorTexture' ) ;
7392 model . translucentRenderEncoder . setColorTextureView ( 0 , v1 ) ;
7493
94+ // Resolve color texture for MSAA
95+ if ( sampleCount > 1 ) {
96+ model . translucentResolveColorTexture = vtkWebGPUTexture . newInstance ( {
97+ label : 'translucentPassResolveColor' ,
98+ } ) ;
99+ model . translucentResolveColorTexture . create ( device , {
100+ width : viewNode . getCanvas ( ) . width ,
101+ height : viewNode . getCanvas ( ) . height ,
102+ format : 'rgba16float' ,
103+ usage :
104+ GPUTextureUsage . RENDER_ATTACHMENT | GPUTextureUsage . TEXTURE_BINDING ,
105+ } ) ;
106+ model . _resolveColorView =
107+ model . translucentResolveColorTexture . createView ( 'oitpColorTexture' ) ;
108+ model . translucentRenderEncoder . setResolveTextureView (
109+ 0 ,
110+ model . _resolveColorView
111+ ) ;
112+ }
113+
75114 model . translucentAccumulateTexture = vtkWebGPUTexture . newInstance ( {
76115 label : 'translucentPassAccumulate' ,
77116 } ) ;
78117 model . translucentAccumulateTexture . create ( device , {
79118 width : viewNode . getCanvas ( ) . width ,
80119 height : viewNode . getCanvas ( ) . height ,
81120 format : 'r16float' ,
121+ sampleCount,
82122 /* eslint-disable no-undef */
83123 /* eslint-disable no-bitwise */
84124 usage :
85- GPUTextureUsage . RENDER_ATTACHMENT | GPUTextureUsage . TEXTURE_BINDING ,
125+ GPUTextureUsage . RENDER_ATTACHMENT |
126+ ( sampleCount === 1 ? GPUTextureUsage . TEXTURE_BINDING : 0 ) ,
86127 } ) ;
87128 const v2 =
88129 model . translucentAccumulateTexture . createView ( 'oitpAccumTexture' ) ;
89130 model . translucentRenderEncoder . setColorTextureView ( 1 , v2 ) ;
131+
132+ // Resolve accumulate texture for MSAA
133+ if ( sampleCount > 1 ) {
134+ model . translucentResolveAccumulateTexture =
135+ vtkWebGPUTexture . newInstance ( {
136+ label : 'translucentPassResolveAccumulate' ,
137+ } ) ;
138+ model . translucentResolveAccumulateTexture . create ( device , {
139+ width : viewNode . getCanvas ( ) . width ,
140+ height : viewNode . getCanvas ( ) . height ,
141+ format : 'r16float' ,
142+ usage :
143+ GPUTextureUsage . RENDER_ATTACHMENT | GPUTextureUsage . TEXTURE_BINDING ,
144+ } ) ;
145+ model . _resolveAccumulateView =
146+ model . translucentResolveAccumulateTexture . createView (
147+ 'oitpAccumTexture'
148+ ) ;
149+ model . translucentRenderEncoder . setResolveTextureView (
150+ 1 ,
151+ model . _resolveAccumulateView
152+ ) ;
153+ }
90154 model . fullScreenQuad = vtkWebGPUFullScreenQuad . newInstance ( ) ;
91155 model . fullScreenQuad . setDevice ( viewNode . getDevice ( ) ) ;
92156 model . fullScreenQuad . setPipelineHash ( 'oitpfsq' ) ;
93- model . fullScreenQuad . setTextureViews (
94- model . translucentRenderEncoder . getColorTextureViews ( )
95- ) ;
157+ // Use resolved textures for the full screen quad if MSAA is on
158+ const views =
159+ sampleCount > 1
160+ ? [ model . _resolveColorView , model . _resolveAccumulateView ]
161+ : model . translucentRenderEncoder . getColorTextureViews ( ) ;
162+ model . fullScreenQuad . setTextureViews ( views ) ;
96163 model . fullScreenQuad . setFragmentShaderTemplate ( oitpFragTemplate ) ;
97164 } else {
98165 model . translucentColorTexture . resizeToMatch (
@@ -101,6 +168,14 @@ function vtkWebGPUOrderIndependentTranslucentPass(publicAPI, model) {
101168 model . translucentAccumulateTexture . resizeToMatch (
102169 model . colorTextureView . getTexture ( )
103170 ) ;
171+ if ( model . translucentResolveColorTexture ) {
172+ model . translucentResolveColorTexture . resizeToMatch (
173+ model . colorTextureView . getTexture ( )
174+ ) ;
175+ model . translucentResolveAccumulateTexture . resizeToMatch (
176+ model . colorTextureView . getTexture ( )
177+ ) ;
178+ }
104179 }
105180
106181 model . translucentRenderEncoder . setDepthTextureView ( model . depthTextureView ) ;
@@ -129,10 +204,16 @@ function vtkWebGPUOrderIndependentTranslucentPass(publicAPI, model) {
129204 model . translucentAccumulateTexture ,
130205 ] ;
131206
132- publicAPI . createRenderEncoder = ( ) => {
207+ publicAPI . createRenderEncoder = ( sampleCount = 1 ) => {
133208 model . translucentRenderEncoder = vtkWebGPURenderEncoder . newInstance ( {
134209 label : 'translucentRender' ,
135210 } ) ;
211+ // Set multisample state if needed
212+ if ( sampleCount > 1 ) {
213+ const settings = model . translucentRenderEncoder . getPipelineSettings ( ) ;
214+ settings . multisample = { count : sampleCount } ;
215+ model . translucentRenderEncoder . setPipelineSettings ( settings ) ;
216+ }
136217 const rDesc = model . translucentRenderEncoder . getDescription ( ) ;
137218 rDesc . colorAttachments = [
138219 {
@@ -261,6 +342,8 @@ function vtkWebGPUOrderIndependentTranslucentPass(publicAPI, model) {
261342const DEFAULT_VALUES = {
262343 colorTextureView : null ,
263344 depthTextureView : null ,
345+ translucentResolveColorTexture : null ,
346+ translucentResolveAccumulateTexture : null ,
264347} ;
265348
266349// ----------------------------------------------------------------------------
0 commit comments