Skip to content

Commit

Permalink
WebGPURenderer: Support for multiple render targets (#26409)
Browse files Browse the repository at this point in the history
* experimental multi attachment shader

add support for webglmultiplerendertargets wip

* fix logic

* rework to use common path

* cleanup

* added antialias

---------

Co-authored-by: aardgoose <angus.sawyer@email.com>
  • Loading branch information
aardgoose and aardgoose committed Aug 30, 2023
1 parent bf7996b commit 1f43ebe
Show file tree
Hide file tree
Showing 16 changed files with 576 additions and 47 deletions.
1 change: 1 addition & 0 deletions examples/files.json
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,7 @@
"webgpu_loader_gltf_sheen",
"webgpu_materials",
"webgpu_materials_video",
"webgpu_multiple_rendertargets",
"webgpu_morphtargets",
"webgpu_occlusion",
"webgpu_particles",
Expand Down
1 change: 1 addition & 0 deletions examples/jsm/nodes/Nodes.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export { default as TempNode } from './core/TempNode.js';
export { default as UniformNode, uniform } from './core/UniformNode.js';
export { default as VarNode, temp } from './core/VarNode.js';
export { default as VaryingNode, varying } from './core/VaryingNode.js';
export { default as OutputStructNode, outputStruct } from './core/OutputStructNode.js';

import * as NodeUtils from './core/NodeUtils.js';
export { NodeUtils };
Expand Down
22 changes: 22 additions & 0 deletions examples/jsm/nodes/core/NodeBuilder.js
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ class NodeBuilder {
this.flowNodes = { vertex: [], fragment: [], compute: [] };
this.flowCode = { vertex: '', fragment: '', compute: [] };
this.uniforms = { vertex: [], fragment: [], compute: [], index: 0 };
this.structs = { vertex: [], fragment: [], compute: [], index: 0 };
this.codes = { vertex: [], fragment: [], compute: [] };
this.bindings = { vertex: [], fragment: [], compute: [] };
this.bindingsOffset = { vertex: 0, fragment: 0, compute: 0 };
Expand Down Expand Up @@ -646,6 +647,27 @@ class NodeBuilder {

}

getStructTypeFromNode( node, shaderStage = this.shaderStage, name = null ) {

const nodeData = this.getDataFromNode( node, shaderStage );

let nodeStruct = nodeData.structType;

if ( nodeStruct === undefined ) {

const index = this.structs.index ++;

node.name = `StructType${index}`;
this.structs[ shaderStage ].push( node );

nodeData.structType = node;

}

return node;

}

getUniformFromNode( node, type, shaderStage = this.shaderStage, name = null ) {

const nodeData = this.getDataFromNode( node, shaderStage );
Expand Down
58 changes: 58 additions & 0 deletions examples/jsm/nodes/core/OutputStructNode.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import Node, { addNodeClass } from './Node.js';
import StructTypeNode from './StructTypeNode.js';
import { nodeProxy } from '../shadernode/ShaderNode.js';

class OutputStructNode extends Node {

constructor( ...members ) {

super();

this.isOutputStructNode = true;
this.members = members;

}

construct( builder ) {

super.construct( builder );

const members = this.members;
const types = [];

for ( let i = 0; i < members.length; i++ ) {

types.push( members[ i ].getNodeType( builder ) );

}

this.nodeType = builder.getStructTypeFromNode( new StructTypeNode( types ) ).name;

}

generate( builder, output ) {

const nodeVar = builder.getVarFromNode( this, this.nodeType );
const propertyName = builder.getPropertyName( nodeVar );

const members = this.members;

for ( let i = 0; i < members.length; i++ ) {

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

builder.addLineFlowCode( `${propertyName}.m${i} = ${snippet}` );

}

return propertyName;

}

}

export default OutputStructNode;

export const outputStruct = nodeProxy( OutputStructNode );

addNodeClass( OutputStructNode );
24 changes: 24 additions & 0 deletions examples/jsm/nodes/core/StructTypeNode.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import Node, { addNodeClass } from './Node.js';

class StructTypeNode extends Node {

constructor( types ) {

super();

this.types = types;
this.isStructTypeNode = true;

}

getMemberTypes() {

return this.types;

}

}

export default StructTypeNode;

addNodeClass( StructTypeNode );
10 changes: 9 additions & 1 deletion examples/jsm/nodes/materials/NodeMaterial.js
Original file line number Diff line number Diff line change
Expand Up @@ -345,7 +345,15 @@ class NodeMaterial extends ShaderMaterial {

if ( renderTarget !== null ) {

outputColorSpace = renderTarget.texture.colorSpace;
if ( Array.isArray( renderTarget.texture ) ) {

outputColorSpace = renderTarget.texture[ 0 ].colorSpace;

} else {

outputColorSpace = renderTarget.texture.colorSpace;

}

} else {

Expand Down
27 changes: 26 additions & 1 deletion examples/jsm/renderers/common/RenderContexts.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,32 @@ class RenderContexts {
get( scene, camera, renderTarget = null ) {

const chainKey = [ scene, camera ];
const attachmentState = renderTarget === null ? 'default' : `${renderTarget.texture.format}:${renderTarget.samples}:${renderTarget.depthBuffer}:${renderTarget.stencilBuffer}`;

let attachmentState;

if ( renderTarget === null ) {

attachmentState = 'default';

} else {

let format, count;

if ( renderTarget.isWebGLMultipleRenderTargets ) {

format = renderTarget.texture[ 0 ].format;
count = renderTarget.texture.length;

} else {

format = renderTarget.texture.format;
count = 1;

}

attachmentState = `${count}:${format}:${renderTarget.samples}:${renderTarget.depthBuffer}:${renderTarget.stencilBuffer}`;

}

const chainMap = this.getChainMap( attachmentState );

Expand Down
4 changes: 2 additions & 2 deletions examples/jsm/renderers/common/Renderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -278,12 +278,12 @@ class Renderer {

const renderTargetData = this._textures.get( renderTarget );

renderContext.texture = renderTargetData.texture;
renderContext.textures = renderTargetData.textures;
renderContext.depthTexture = renderTargetData.depthTexture;

} else {

renderContext.texture = null;
renderContext.textures = null;
renderContext.depthTexture = null;

}
Expand Down
49 changes: 43 additions & 6 deletions examples/jsm/renderers/common/Textures.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,24 @@ class Textures extends DataMap {
const renderTargetData = this.get( renderTarget );
const sampleCount = renderTarget.samples === 0 ? 1 : renderTarget.samples;

const texture = renderTarget.texture;
let texture, textures;

if ( renderTarget.isWebGLMultipleRenderTargets ) {

textures = renderTarget.texture;
texture = renderTarget.texture[ 0 ];

} else {

textures = [ renderTarget.texture ];
texture = renderTarget.texture;

}

const size = this.getSize( texture );

let depthTexture = renderTarget.depthTexture || renderTargetData.depthTexture;
let textureNeedsUpdate = false;

if ( depthTexture === undefined ) {

Expand All @@ -37,7 +51,7 @@ class Textures extends DataMap {

if ( renderTargetData.width !== size.width || size.height !== renderTargetData.height ) {

texture.needsUpdate = true;
textureNeedsUpdate = true;
depthTexture.needsUpdate = true;

depthTexture.image.width = size.width;
Expand All @@ -47,12 +61,12 @@ class Textures extends DataMap {

renderTargetData.width = size.width;
renderTargetData.height = size.height;
renderTargetData.texture = texture;
renderTargetData.textures = textures;
renderTargetData.depthTexture = depthTexture;

if ( renderTargetData.sampleCount !== sampleCount ) {

texture.needsUpdate = true;
textureNeedsUpdate = true;
depthTexture.needsUpdate = true;

renderTargetData.sampleCount = sampleCount;
Expand All @@ -61,7 +75,17 @@ class Textures extends DataMap {

const options = { sampleCount };

this.updateTexture( texture, options );

for ( let i = 0; i < textures.length; i ++ ) {

const texture = textures[ i ];

if ( textureNeedsUpdate ) texture.needsUpdate = true;

this.updateTexture( texture, options );

}

this.updateTexture( depthTexture, options );

// dispose handler
Expand All @@ -76,7 +100,20 @@ class Textures extends DataMap {

renderTarget.removeEventListener( 'dispose', onDispose );

this._destroyTexture( texture );
if ( textures !== undefined ) {

for ( let i = 0; i < textures.length; i ++ ) {

this._destroyTexture( textures[ i ] );

}

} else {

this._destroyTexture( texture );

}

this._destroyTexture( depthTexture );

};
Expand Down
Loading

0 comments on commit 1f43ebe

Please sign in to comment.