Skip to content

Commit 2ac424c

Browse files
aardgooseycwaardgoosesunag
authored
WebGPURenderer: Support multiple render targets (#26808)
* less var access (#26817) actually use the framebuffer we have cached update examples update screenshots MRT allow example to run fix WGSL code address comments update screenshot * remove unused var * cleanup --------- Co-authored-by: ycw <[email protected]> Co-authored-by: aardgoose <[email protected]> Co-authored-by: sunag <[email protected]>
1 parent 309e5f6 commit 2ac424c

File tree

6 files changed

+99
-10
lines changed

6 files changed

+99
-10
lines changed

examples/jsm/nodes/core/OutputStructNode.js

+5-1
Original file line numberDiff line numberDiff line change
@@ -33,15 +33,19 @@ class OutputStructNode extends Node {
3333
generate( builder, output ) {
3434

3535
const nodeVar = builder.getVarFromNode( this, this.nodeType );
36+
nodeVar.isOutputStructVar = true;
37+
3638
const propertyName = builder.getPropertyName( nodeVar );
3739

3840
const members = this.members;
3941

42+
const structPrefix = propertyName !== '' ? propertyName + '.' : '';
43+
4044
for ( let i = 0; i < members.length; i++ ) {
4145

4246
const snippet = members[ i ].build( builder, output );
4347

44-
builder.addLineFlowCode( `${propertyName}.m${i} = ${snippet}` );
48+
builder.addLineFlowCode( `${structPrefix}m${i} = ${snippet}` );
4549

4650
}
4751

examples/jsm/renderers/webgl/WebGLBackend.js

+28-2
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,26 @@ class WebGLBackend extends Backend {
6464

6565
const clearColor = renderContext.clearColorValue;
6666

67-
gl.clearColor( clearColor.r, clearColor.g, clearColor.b, clearColor.a );
68-
gl.clear( clear );
67+
if ( clear !== 0 ) {
68+
69+
if ( renderContext.textures === null ) {
70+
71+
gl.clearColor( clearColor.r, clearColor.g, clearColor.b, clearColor.a );
72+
gl.clear( clear );
73+
74+
} else {
75+
76+
for ( let i = 0; i < renderContext.textures.length; i ++ ) {
77+
78+
gl.clearBufferfv( gl.COLOR, i, [ clearColor.r, clearColor.g, clearColor.b, clearColor.a ] );
79+
80+
}
81+
82+
gl.clearBufferfi( gl.DEPTH_STENCIL, 0, 1, 1 );
83+
84+
}
85+
86+
}
6987

7088
//
7189

@@ -638,15 +656,23 @@ class WebGLBackend extends Backend {
638656

639657
const textures = renderContext.textures;
640658

659+
const drawBuffers = [];
660+
641661
for ( let i = 0; i < textures.length; i++ ) {
642662

643663
const texture = textures[ i ];
644664
const { textureGPU } = this.get( texture );
645665

666+
const attachment = gl.COLOR_ATTACHMENT0 + i;
667+
646668
gl.framebufferTexture2D( gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0 + i, gl.TEXTURE_2D, textureGPU, 0 );
647669

670+
drawBuffers.push( attachment );
671+
648672
}
649673

674+
gl.drawBuffers( drawBuffers );
675+
650676
if ( renderContext.depthTexture !== null ) {
651677

652678
const { textureGPU } = this.get( renderContext.depthTexture );

examples/jsm/renderers/webgl/nodes/GLSLNodeBuilder.js

+62-4
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,14 @@ class GLSLNodeBuilder extends NodeBuilder {
3030

3131
}
3232

33+
getPropertyName( node, shaderStage ) {
34+
35+
if ( node.isOutputStructVar ) return '';
36+
37+
return super.getPropertyName( node, shaderStage );
38+
39+
}
40+
3341
getTexture( texture, textureProperty, uvSnippet ) {
3442

3543
if ( texture.isTextureCube ) {
@@ -62,6 +70,8 @@ class GLSLNodeBuilder extends NodeBuilder {
6270

6371
for ( const variable of vars ) {
6472

73+
if ( variable.isOutputStructVar ) continue;
74+
6575
snippets.push( `${ this.getVar( variable.type, variable.name ) };` );
6676

6777
}
@@ -160,6 +170,49 @@ class GLSLNodeBuilder extends NodeBuilder {
160170

161171
}
162172

173+
getStructMembers( struct ) {
174+
175+
const snippets = [];
176+
const members = struct.getMemberTypes();
177+
178+
for ( let i = 0; i < members.length; i ++ ) {
179+
180+
const member = members[ i ];
181+
snippets.push( `layout( location = ${i} ) out ${ member} m${i};` );
182+
183+
}
184+
185+
return snippets.join( '\n' );
186+
187+
}
188+
189+
getStructs( shaderStage ) {
190+
191+
const snippets = [];
192+
const structs = this.structs[ shaderStage ];
193+
194+
if ( structs.length === 0 ) {
195+
196+
return "layout( location = 0 ) out vec4 fragColor;\n";
197+
198+
}
199+
200+
for ( let index = 0, length = structs.length; index < length; index ++ ) {
201+
202+
const struct = structs[ index ];
203+
204+
let snippet = `\n`;
205+
snippet += this.getStructMembers( struct );
206+
snippet += '\n';
207+
208+
snippets.push( snippet );
209+
210+
}
211+
212+
return snippets.join( '\n\n' );
213+
214+
}
215+
163216
getVaryings( shaderStage ) {
164217

165218
let snippet = '';
@@ -281,7 +334,7 @@ ${shaderData.varyings}
281334
// codes
282335
${shaderData.codes}
283336
284-
layout( location = 0 ) out vec4 fragColor;
337+
${shaderData.structs}
285338
286339
void main() {
287340
@@ -330,14 +383,18 @@ void main() {
330383
if ( shaderStage === 'vertex' ) {
331384

332385
flow += 'gl_Position = ';
386+
flow += `${ flowSlotData.result };`;
333387

334388
} else if ( shaderStage === 'fragment' ) {
335389

336-
flow += 'fragColor = ';
390+
if ( ! node.outputNode.isOutputStructNode ) {
337391

338-
}
392+
flow += 'fragColor = ';
393+
flow += `${ flowSlotData.result };`;
339394

340-
flow += `${ flowSlotData.result };`;
395+
}
396+
397+
}
341398

342399
}
343400

@@ -349,6 +406,7 @@ void main() {
349406
stageData.attributes = this.getAttributes( shaderStage );
350407
stageData.varyings = this.getVaryings( shaderStage );
351408
stageData.vars = this.getVars( shaderStage );
409+
stageData.structs = this.getStructs( shaderStage );
352410
stageData.codes = this.getCodes( shaderStage );
353411
stageData.flow = flow;
354412

Loading

examples/webgpu_multiple_rendertargets.html

+4-2
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@
3434

3535
import { NodeMaterial, MeshBasicNodeMaterial, mix, modelNormalMatrix, normalGeometry, normalize, outputStruct, step, texture, uniform, uv, varying, vec2, vec4 } from 'three/nodes';
3636
import WebGPU from 'three/addons/capabilities/WebGPU.js';
37+
import WebGL from 'three/addons/capabilities/WebGL.js';
38+
3739
import WebGPURenderer from 'three/addons/renderers/webgpu/WebGPURenderer.js';
3840

3941
let camera, scene, renderer, torus;
@@ -101,11 +103,11 @@
101103

102104
function init() {
103105

104-
if ( WebGPU.isAvailable() === false ) {
106+
if ( WebGPU.isAvailable() === false && WebGL.isWebGL2Available() === false ) {
105107

106108
document.body.appendChild( WebGPU.getErrorMessage() );
107109

108-
throw new Error( 'No WebGPU support' );
110+
throw new Error( 'No WebGPU or WebGL2 support' );
109111

110112
}
111113

test/e2e/puppeteer.js

-1
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,6 @@ const exceptionList = [
125125
'webgpu_materials',
126126
'webgpu_materials_video',
127127
'webgpu_morphtargets',
128-
"webgpu_multiple_rendertargets",
129128
'webgpu_occlusion',
130129
'webgpu_particles',
131130
'webgpu_sandbox',

0 commit comments

Comments
 (0)