Kaynağa Gözat

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]>
aardgoose 1 yıl önce
ebeveyn
işleme
2ac424c3ea

+ 5 - 1
examples/jsm/nodes/core/OutputStructNode.js

@@ -33,15 +33,19 @@ class OutputStructNode extends Node {
 	generate( builder, output ) {
 
 		const nodeVar = builder.getVarFromNode( this, this.nodeType );
+		nodeVar.isOutputStructVar = true;
+
 		const propertyName = builder.getPropertyName( nodeVar );
 
 		const members = this.members;
 
+		const structPrefix = propertyName !== '' ? propertyName + '.' : '';
+
 		for ( let i = 0; i < members.length; i++ ) {
 
 			const snippet = members[ i ].build( builder, output );
 
-			builder.addLineFlowCode( `${propertyName}.m${i} = ${snippet}` );
+			builder.addLineFlowCode( `${structPrefix}m${i} = ${snippet}` );
 
 		}
 

+ 28 - 2
examples/jsm/renderers/webgl/WebGLBackend.js

@@ -64,8 +64,26 @@ class WebGLBackend extends Backend {
 
 		const clearColor = renderContext.clearColorValue;
 
-		gl.clearColor( clearColor.r, clearColor.g, clearColor.b, clearColor.a );
-		gl.clear( clear );
+		if ( clear !== 0 ) {
+
+			if ( renderContext.textures === null ) {
+
+				gl.clearColor( clearColor.r, clearColor.g, clearColor.b, clearColor.a );
+				gl.clear( clear );
+
+			} else {
+
+				for ( let i = 0; i < renderContext.textures.length; i ++ ) {
+
+					gl.clearBufferfv( gl.COLOR, i, [ clearColor.r, clearColor.g, clearColor.b, clearColor.a ] );
+
+				}
+
+				gl.clearBufferfi( gl.DEPTH_STENCIL, 0, 1, 1 );
+
+			}
+
+		}
 
 		//
 
@@ -638,15 +656,23 @@ class WebGLBackend extends Backend {
 
 				const textures = renderContext.textures;
 
+				const drawBuffers = [];
+
 				for ( let i = 0; i < textures.length; i++ ) {
 
 					const texture = textures[ i ];
 					const { textureGPU } = this.get( texture );
 
+					const attachment = gl.COLOR_ATTACHMENT0 + i;
+
 					gl.framebufferTexture2D( gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0 + i, gl.TEXTURE_2D, textureGPU, 0 );
 
+					drawBuffers.push( attachment );
+
 				}
 
+				gl.drawBuffers( drawBuffers );
+
 				if ( renderContext.depthTexture !== null ) {
 
 					const { textureGPU } = this.get( renderContext.depthTexture );

+ 62 - 4
examples/jsm/renderers/webgl/nodes/GLSLNodeBuilder.js

@@ -30,6 +30,14 @@ class GLSLNodeBuilder extends NodeBuilder {
 
 	}
 
+	getPropertyName( node, shaderStage ) {
+
+		if ( node.isOutputStructVar ) return '';
+
+		return super.getPropertyName( node, shaderStage );
+
+	}
+
 	getTexture( texture, textureProperty, uvSnippet ) {
 
 		if ( texture.isTextureCube ) {
@@ -62,6 +70,8 @@ class GLSLNodeBuilder extends NodeBuilder {
 
 		for ( const variable of vars ) {
 
+			if ( variable.isOutputStructVar ) continue;
+
 			snippets.push( `${ this.getVar( variable.type, variable.name ) };` );
 
 		}
@@ -160,6 +170,49 @@ class GLSLNodeBuilder extends NodeBuilder {
 
 	}
 
+	getStructMembers( struct ) {
+
+		const snippets = [];
+		const members = struct.getMemberTypes();
+
+		for ( let i = 0; i < members.length; i ++ ) {
+
+			const member = members[ i ];
+			snippets.push( `layout( location = ${i} ) out ${ member} m${i};` );
+
+		}
+
+		return snippets.join( '\n' );
+
+	}
+
+	getStructs( shaderStage ) {
+
+		const snippets = [];
+		const structs = this.structs[ shaderStage ];
+
+		if ( structs.length === 0 ) {
+
+			return "layout( location = 0 ) out vec4 fragColor;\n";
+
+		}
+
+		for ( let index = 0, length = structs.length; index < length; index ++ ) {
+
+			const struct = structs[ index ];
+
+			let snippet = `\n`;
+			snippet += this.getStructMembers( struct );
+			snippet += '\n';
+
+			snippets.push( snippet );
+
+		}
+
+		return snippets.join( '\n\n' );
+
+	}
+
 	getVaryings( shaderStage ) {
 
 		let snippet = '';
@@ -281,7 +334,7 @@ ${shaderData.varyings}
 // codes
 ${shaderData.codes}
 
-layout( location = 0 ) out vec4 fragColor;
+${shaderData.structs}
 
 void main() {
 
@@ -330,14 +383,18 @@ void main() {
 					if ( shaderStage === 'vertex' ) {
 
 						flow += 'gl_Position = ';
+						flow += `${ flowSlotData.result };`;
 
 					} else if ( shaderStage === 'fragment' ) {
 
-						flow += 'fragColor = ';
+						if ( ! node.outputNode.isOutputStructNode ) {
 
-					}
+							flow += 'fragColor = ';
+							flow += `${ flowSlotData.result };`;
 
-					flow += `${ flowSlotData.result };`;
+						}
+
+					}
 
 				}
 
@@ -349,6 +406,7 @@ void main() {
 			stageData.attributes = this.getAttributes( shaderStage );
 			stageData.varyings = this.getVaryings( shaderStage );
 			stageData.vars = this.getVars( shaderStage );
+			stageData.structs = this.getStructs( shaderStage );
 			stageData.codes = this.getCodes( shaderStage );
 			stageData.flow = flow;
 

BIN
examples/screenshots/webgpu_multiple_rendertargets.jpg


+ 4 - 2
examples/webgpu_multiple_rendertargets.html

@@ -34,6 +34,8 @@
 
 			import { NodeMaterial, MeshBasicNodeMaterial, mix, modelNormalMatrix, normalGeometry, normalize, outputStruct, step, texture, uniform, uv, varying, vec2, vec4 } from 'three/nodes';
 			import WebGPU from 'three/addons/capabilities/WebGPU.js';
+			import WebGL from 'three/addons/capabilities/WebGL.js';
+
 			import WebGPURenderer from 'three/addons/renderers/webgpu/WebGPURenderer.js';
 
 			let camera, scene, renderer, torus;
@@ -101,11 +103,11 @@
 
 			function init() {
 
-				if ( WebGPU.isAvailable() === false ) {
+				if ( WebGPU.isAvailable() === false && WebGL.isWebGL2Available() === false ) {
 
 					document.body.appendChild( WebGPU.getErrorMessage() );
 
-					throw new Error( 'No WebGPU support' );
+					throw new Error( 'No WebGPU or WebGL2 support' );
 
 				}
 

+ 0 - 1
test/e2e/puppeteer.js

@@ -125,7 +125,6 @@ const exceptionList = [
 	'webgpu_materials',
 	'webgpu_materials_video',
 	'webgpu_morphtargets',
-	"webgpu_multiple_rendertargets",
 	'webgpu_occlusion',
 	'webgpu_particles',
 	'webgpu_sandbox',