diff --git a/examples/jsm/nodes/core/OutputStructNode.js b/examples/jsm/nodes/core/OutputStructNode.js index df8991a3ab6c30..68dff8dee7c958 100644 --- a/examples/jsm/nodes/core/OutputStructNode.js +++ b/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}` ); } diff --git a/examples/jsm/renderers/webgl/WebGLBackend.js b/examples/jsm/renderers/webgl/WebGLBackend.js index dcab743032b1a2..71a995fc08c440 100644 --- a/examples/jsm/renderers/webgl/WebGLBackend.js +++ b/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 ); diff --git a/examples/jsm/renderers/webgl/nodes/GLSLNodeBuilder.js b/examples/jsm/renderers/webgl/nodes/GLSLNodeBuilder.js index 311aae9ae95407..0de36c2ad24a4a 100644 --- a/examples/jsm/renderers/webgl/nodes/GLSLNodeBuilder.js +++ b/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; diff --git a/examples/screenshots/webgpu_multiple_rendertargets.jpg b/examples/screenshots/webgpu_multiple_rendertargets.jpg index 001fe203e0b94e..e1cd5894893de3 100644 Binary files a/examples/screenshots/webgpu_multiple_rendertargets.jpg and b/examples/screenshots/webgpu_multiple_rendertargets.jpg differ diff --git a/examples/webgpu_multiple_rendertargets.html b/examples/webgpu_multiple_rendertargets.html index a78c86d5009f4c..f4cacde8828dbb 100644 --- a/examples/webgpu_multiple_rendertargets.html +++ b/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' ); } diff --git a/test/e2e/puppeteer.js b/test/e2e/puppeteer.js index 2a5aa6402eb949..4c972cdf41ebe8 100644 --- a/test/e2e/puppeteer.js +++ b/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',