Skip to content

Commit 8cc9f32

Browse files
authored
WebGPURenderer: New Cache System (#25750)
* FogNode: Update from construct API. * webgpu_rtt: update example API * WebGPURenderer: New Cache System * WebGPURenderer: Update cacheKey after needsUpdate. * final revision (1) * RenderObject pipeline based ( 1/2 ) * RenderObject pipeline based ( 2/2 ) * cleanup * fix possible overrideMaterial material with .wireframe and cleanup * Revert "fix possible overrideMaterial material with .wireframe and cleanup" This reverts commit 7dcd85e. * Revert "Revert "fix possible overrideMaterial material with .wireframe and cleanup"" This reverts commit 5370b40. * preserve nodes if pipeline is removed * WebGPURenderObjects: Move get*Node() to WebGPUNodes.
1 parent 6622dbf commit 8cc9f32

21 files changed

+709
-363
lines changed

examples/jsm/nodes/core/NodeBuilder.js

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,18 +32,19 @@ class NodeBuilder {
3232
constructor( object, renderer, parser ) {
3333

3434
this.object = object;
35-
this.material = object.material || null;
36-
this.geometry = object.geometry || null;
35+
this.material = object && ( object.material || null );
36+
this.geometry = object && ( object.geometry || null );
3737
this.renderer = renderer;
3838
this.parser = parser;
3939

4040
this.nodes = [];
4141
this.updateNodes = [];
4242
this.hashNodes = {};
4343

44-
this.scene = null;
4544
this.lightsNode = null;
45+
this.environmentNode = null;
4646
this.fogNode = null;
47+
this.toneMappingNode = null;
4748

4849
this.vertexShader = null;
4950
this.fragmentShader = null;
@@ -63,7 +64,7 @@ class NodeBuilder {
6364

6465
this.context = {
6566
keywords: new NodeKeywords(),
66-
material: object.material,
67+
material: this.material,
6768
getMIPLevelAlgorithmNode: ( textureNode, levelNode ) => levelNode.mul( maxMipLevel( textureNode ) )
6869
};
6970

examples/jsm/nodes/fog/FogExp2Node.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ class FogExp2Node extends FogNode {
2020
const depthNode = positionView.z.negate();
2121
const densityNode = this.densityNode;
2222

23-
this.factorNode = densityNode.mul( densityNode, depthNode, depthNode ).negate().exp().oneMinus();
23+
return densityNode.mul( densityNode, depthNode, depthNode ).negate().exp().oneMinus();
2424

2525
}
2626

examples/jsm/nodes/fog/FogNode.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,9 @@ class FogNode extends Node {
2020

2121
}
2222

23-
generate( builder ) {
23+
construct() {
2424

25-
return this.factorNode.build( builder, 'float' );
25+
return this.factorNode;
2626

2727
}
2828

examples/jsm/nodes/fog/FogRangeNode.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ class FogRangeNode extends FogNode {
1919

2020
construct() {
2121

22-
this.factorNode = smoothstep( this.nearNode, this.farNode, positionView.z.negate() );
22+
return smoothstep( this.nearNode, this.farNode, positionView.z.negate() );
2323

2424
}
2525

examples/jsm/nodes/materials/NodeMaterial.js

Lines changed: 7 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Material, ShaderMaterial, NoToneMapping } from 'three';
1+
import { Material, ShaderMaterial } from 'three';
22
import { getNodeChildren, getCacheKey } from '../core/NodeUtils.js';
33
import { attribute } from '../core/AttributeNode.js';
44
import { diffuseColor } from '../core/PropertyNode.js';
@@ -8,13 +8,8 @@ import { modelViewProjection } from '../accessors/ModelViewProjectionNode.js';
88
import { transformedNormalView } from '../accessors/NormalNode.js';
99
import { instance } from '../accessors/InstanceNode.js';
1010
import { positionLocal } from '../accessors/PositionNode.js';
11-
import { reference } from '../accessors/ReferenceNode.js';
1211
import { skinning } from '../accessors/SkinningNode.js';
1312
import { texture } from '../accessors/TextureNode.js';
14-
import { cubeTexture } from '../accessors/CubeTextureNode.js';
15-
import { toneMapping } from '../display/ToneMappingNode.js';
16-
import { rangeFog } from '../fog/FogRangeNode.js';
17-
import { densityFog } from '../fog/FogExp2Node.js';
1813
import { lightsWithoutWrap } from '../lighting/LightsNode.js';
1914
import AONode from '../lighting/AONode.js';
2015
import EnvironmentNode from '../lighting/EnvironmentNode.js';
@@ -161,28 +156,7 @@ class NodeMaterial extends ShaderMaterial {
161156

162157
constructLights( builder ) {
163158

164-
let lightsNode = this.lightsNode || builder.lightsNode;
165-
let envNode = this.envNode || builder.scene.environmentNode;
166-
167-
if ( envNode === undefined && builder.scene.environment ) {
168-
169-
const environment = builder.scene.environment;
170-
171-
if ( environment.isCubeTexture === true ) {
172-
173-
envNode = cubeTexture( environment );
174-
175-
} else if ( environment.isTexture === true ) {
176-
177-
envNode = texture( environment );
178-
179-
} else {
180-
181-
console.error( 'NodeMaterial: Unsupported environment configuration.', environment );
182-
183-
}
184-
185-
}
159+
const envNode = this.envNode || builder.environmentNode;
186160

187161
const materialLightsNode = [];
188162

@@ -198,6 +172,8 @@ class NodeMaterial extends ShaderMaterial {
198172

199173
}
200174

175+
let lightsNode = this.lightsNode || builder.lightsNode;
176+
201177
if ( materialLightsNode.length > 0 ) {
202178

203179
lightsNode = lightsWithoutWrap( [ ...lightsNode.lightNodes, ...materialLightsNode ] );
@@ -251,15 +227,9 @@ class NodeMaterial extends ShaderMaterial {
251227

252228
// TONE MAPPING
253229

254-
let toneMappingNode = renderer.toneMappingNode;
255-
256-
if ( ! toneMappingNode && renderer.toneMapping !== NoToneMapping ) {
230+
const toneMappingNode = builder.toneMappingNode;
257231

258-
toneMappingNode = toneMapping( renderer.toneMapping, reference( 'toneMappingExposure', 'float', renderer ), outgoingLight );
259-
260-
}
261-
262-
if ( toneMappingNode && toneMappingNode.isNode === true ) {
232+
if ( toneMappingNode ) {
263233

264234
outgoingLight = toneMappingNode.context( { color: outgoingLight } );
265235

@@ -275,27 +245,7 @@ class NodeMaterial extends ShaderMaterial {
275245

276246
// FOG
277247

278-
let fogNode = builder.fogNode;
279-
280-
if ( ( fogNode && fogNode.isNode !== true ) && builder.scene.fog ) {
281-
282-
const fog = builder.scene.fog;
283-
284-
if ( fog.isFogExp2 ) {
285-
286-
fogNode = densityFog( reference( 'color', 'color', fog ), reference( 'density', 'float', fog ) );
287-
288-
} else if ( fog.isFog ) {
289-
290-
fogNode = rangeFog( reference( 'color', 'color', fog ), reference( 'near', 'float', fog ), reference( 'far', 'float', fog ) );
291-
292-
} else {
293-
294-
console.error( 'NodeMaterial: Unsupported fog configuration.', fog );
295-
296-
}
297-
298-
}
248+
const fogNode = builder.fogNode;
299249

300250
if ( fogNode ) outputNode = vec4( fogNode.mixAssign( outputNode.rgb ), outputNode.a );
301251

examples/jsm/renderers/webgpu/WebGPUBackground.js

Lines changed: 27 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,19 @@
11
import { GPULoadOp, GPUStoreOp } from './constants.js';
2-
import { Color, Mesh, BoxGeometry, BackSide, EquirectangularReflectionMapping, EquirectangularRefractionMapping } from 'three';
3-
import { context, vec2, oneMinus, texture, cubeTexture, transformDirection, positionWorld, modelWorldMatrix, viewportBottomLeft, equirectUV, MeshBasicNodeMaterial } from 'three/nodes';
2+
import { Color, Mesh, BoxGeometry, BackSide } from 'three';
3+
import { context, transformDirection, positionWorld, modelWorldMatrix, MeshBasicNodeMaterial } from 'three/nodes';
44

55
let _clearAlpha;
66
const _clearColor = new Color();
77

88
class WebGPUBackground {
99

10-
constructor( renderer ) {
10+
constructor( renderer, properties ) {
1111

1212
this.renderer = renderer;
13+
this.properties = properties;
1314

1415
this.boxMesh = null;
16+
this.boxMeshNode = null;
1517

1618
this.forceClear = false;
1719

@@ -26,7 +28,7 @@ class WebGPUBackground {
2628
update( renderList, scene ) {
2729

2830
const renderer = this.renderer;
29-
const background = ( scene.isScene === true ) ? scene.backgroundNode || scene.background : null;
31+
const background = ( scene.isScene === true ) ? scene.backgroundNode || this.properties.get( scene ).backgroundNode || scene.background : null;
3032

3133
let forceClear = this.forceClear;
3234

@@ -45,7 +47,10 @@ class WebGPUBackground {
4547
_clearAlpha = 1;
4648
forceClear = true;
4749

48-
} else if ( background.isNode === true || background.isTexture === true ) {
50+
} else if ( background.isNode === true ) {
51+
52+
const sceneProperties = this.properties.get( scene );
53+
const backgroundNode = background;
4954

5055
_clearColor.copy( renderer._clearColor );
5156
_clearAlpha = renderer._clearAlpha;
@@ -54,42 +59,13 @@ class WebGPUBackground {
5459

5560
if ( boxMesh === null ) {
5661

57-
let node = null;
58-
59-
if ( background.isCubeTexture === true ) {
60-
61-
node = cubeTexture( background, transformDirection( positionWorld, modelWorldMatrix ) );
62-
63-
} else if ( background.isTexture === true ) {
64-
65-
let nodeUV = null;
66-
67-
if ( background.mapping === EquirectangularReflectionMapping || background.mapping === EquirectangularRefractionMapping ) {
68-
69-
const dirNode = transformDirection( positionWorld, modelWorldMatrix );
70-
71-
nodeUV = equirectUV( dirNode );
72-
nodeUV = vec2( nodeUV.x, oneMinus( nodeUV.y ) );
73-
74-
} else {
75-
76-
nodeUV = viewportBottomLeft;
77-
78-
}
79-
80-
node = texture( background, nodeUV );
81-
82-
} else /*if ( background.isNode === true )*/ {
83-
84-
node = context( background, {
85-
// @TODO: Add Texture2D support using node context
86-
getUVNode: () => transformDirection( positionWorld, modelWorldMatrix )
87-
} );
88-
89-
}
62+
this.boxMeshNode = context( backgroundNode, {
63+
// @TODO: Add Texture2D support using node context
64+
getUVNode: () => transformDirection( positionWorld, modelWorldMatrix )
65+
} );
9066

9167
const nodeMaterial = new MeshBasicNodeMaterial();
92-
nodeMaterial.colorNode = node;
68+
nodeMaterial.colorNode = this.boxMeshNode;
9369
nodeMaterial.side = BackSide;
9470
nodeMaterial.depthTest = false;
9571
nodeMaterial.depthWrite = false;
@@ -105,6 +81,18 @@ class WebGPUBackground {
10581

10682
}
10783

84+
const backgroundCacheKey = backgroundNode.getCacheKey();
85+
86+
if ( sceneProperties.backgroundMeshCacheKey !== backgroundCacheKey ) {
87+
88+
this.boxMeshNode.node = backgroundNode;
89+
90+
boxMesh.material.needsUpdate = true;
91+
92+
sceneProperties.backgroundMeshCacheKey = backgroundCacheKey;
93+
94+
}
95+
10896
renderList.unshift( boxMesh, boxMesh.geometry, boxMesh.material, 0, 0, null );
10997

11098
} else {

examples/jsm/renderers/webgpu/WebGPUBindings.js

Lines changed: 21 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -17,20 +17,20 @@ class WebGPUBindings {
1717

1818
}
1919

20-
get( object ) {
20+
get( renderObject ) {
2121

22-
let data = this.uniformsData.get( object );
22+
let data = this.uniformsData.get( renderObject );
2323

2424
if ( data === undefined ) {
2525

2626
// each object defines an array of bindings (ubos, textures, samplers etc.)
2727

28-
const nodeBuilder = this.nodes.get( object );
28+
const nodeBuilder = this.nodes.get( renderObject );
2929
const bindings = nodeBuilder.getBindings();
3030

3131
// setup (static) binding layout and (dynamic) binding group
3232

33-
const pipeline = object.isNode ? this.computePipelines.get( object ) : this.renderPipelines.get( object ).pipeline;
33+
const pipeline = this.renderPipelines.get( renderObject ).pipeline;
3434

3535
const bindLayout = pipeline.getBindGroupLayout( 0 );
3636
const bindGroup = this._createBindGroup( bindings, bindLayout );
@@ -41,33 +41,30 @@ class WebGPUBindings {
4141
bindings: bindings
4242
};
4343

44-
this.uniformsData.set( object, data );
44+
this.uniformsData.set( renderObject, data );
4545

4646
}
4747

4848
return data;
4949

5050
}
5151

52-
remove( object ) {
53-
54-
this.uniformsData.delete( object );
55-
56-
}
52+
getForCompute( computeNode ) {
5753

58-
getForCompute( param ) {
59-
60-
let data = this.uniformsData.get( param );
54+
let data = this.uniformsData.get( computeNode );
6155

6256
if ( data === undefined ) {
6357

64-
// bindings are not yet retrieved via node material
58+
// each object defines an array of bindings (ubos, textures, samplers etc.)
6559

66-
const bindings = param.bindings !== undefined ? param.bindings.slice() : [];
60+
const nodeBuilder = this.nodes.getForCompute( computeNode );
61+
const bindings = nodeBuilder.getBindings();
6762

68-
const computePipeline = this.computePipelines.get( param );
63+
// setup (static) binding layout and (dynamic) binding group
6964

70-
const bindLayout = computePipeline.getBindGroupLayout( 0 );
65+
const pipeline = this.computePipelines.get( computeNode );
66+
67+
const bindLayout = pipeline.getBindGroupLayout( 0 );
7168
const bindGroup = this._createBindGroup( bindings, bindLayout );
7269

7370
data = {
@@ -76,14 +73,20 @@ class WebGPUBindings {
7673
bindings: bindings
7774
};
7875

79-
this.uniformsData.set( param, data );
76+
this.uniformsData.set( computeNode, data );
8077

8178
}
8279

8380
return data;
8481

8582
}
8683

84+
remove( object ) {
85+
86+
this.uniformsData.delete( object );
87+
88+
}
89+
8790
update( object ) {
8891

8992
const textures = this.textures;

examples/jsm/renderers/webgpu/WebGPUComputePipelines.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ class WebGPUComputePipelines {
3232

3333
// get shader
3434

35-
const nodeBuilder = this.nodes.get( computeNode );
35+
const nodeBuilder = this.nodes.getForCompute( computeNode );
3636
const computeShader = nodeBuilder.computeShader;
3737

3838
const shader = {

0 commit comments

Comments
 (0)