diff --git a/examples/jsm/renderers/common/Animation.js b/examples/jsm/renderers/common/Animation.js index 50da8c0591db22..d3a5f2043b767b 100644 --- a/examples/jsm/renderers/common/Animation.js +++ b/examples/jsm/renderers/common/Animation.js @@ -1,23 +1,18 @@ class Animation { - constructor() { + constructor( nodes, info ) { - this.nodes = null; + this.nodes = nodes; + this.info = info; this.animationLoop = null; this.requestId = null; - this.isAnimating = false; - - this.context = self; + this._init(); } - start() { - - if ( this.isAnimating === true || this.animationLoop === null || this.nodes === null ) return; - - this.isAnimating = true; + _init() { const update = ( time, frame ) => { @@ -25,20 +20,20 @@ class Animation { this.nodes.nodeFrame.update(); - this.animationLoop( time, frame ); + this.info.frame = this.nodes.nodeFrame.frameId; + + if ( this.animationLoop !== null ) this.animationLoop( time, frame ); }; - this.requestId = self.requestAnimationFrame( update ); + update(); } - stop() { + dispose() { self.cancelAnimationFrame( this.requestId ); - this.isAnimating = false; - } setAnimationLoop( callback ) { @@ -47,12 +42,6 @@ class Animation { } - setNodes( nodes ) { - - this.nodes = nodes; - - } - } export default Animation; diff --git a/examples/jsm/renderers/common/Bindings.js b/examples/jsm/renderers/common/Bindings.js index b78d110181d23a..53dc86e070b493 100644 --- a/examples/jsm/renderers/common/Bindings.js +++ b/examples/jsm/renderers/common/Bindings.js @@ -101,7 +101,7 @@ class Bindings extends DataMap { const { backend } = this; const updateMap = this.updateMap; - const frame = this.info.render.frame; + const callId = this.info.calls; let needsBindingsUpdate = false; @@ -109,7 +109,7 @@ class Bindings extends DataMap { for ( const binding of bindings ) { - const isUpdated = updateMap.get( binding ) === frame; + const isUpdated = updateMap.get( binding ) === callId; if ( isUpdated ) continue; @@ -137,7 +137,7 @@ class Bindings extends DataMap { } - updateMap.set( binding, frame ); + updateMap.set( binding, callId ); } diff --git a/examples/jsm/renderers/common/Geometries.js b/examples/jsm/renderers/common/Geometries.js index 0de0b7e37d6366..90f6798fe9cd6a 100644 --- a/examples/jsm/renderers/common/Geometries.js +++ b/examples/jsm/renderers/common/Geometries.js @@ -76,7 +76,7 @@ class Geometries extends DataMap { this.info = info; this.wireframes = new WeakMap(); - this.attributeFrame = new WeakMap(); + this.attributeCall = new WeakMap(); } @@ -162,13 +162,13 @@ class Geometries extends DataMap { updateAttribute( attribute, type ) { - const frame = this.info.render.frame; + const callId = this.info.render.calls; - if ( this.attributeFrame.get( attribute ) !== frame ) { + if ( this.attributeCall.get( attribute ) !== callId ) { this.attributes.update( attribute, type ); - this.attributeFrame.set( attribute, frame ); + this.attributeCall.set( attribute, callId ); } diff --git a/examples/jsm/renderers/common/Info.js b/examples/jsm/renderers/common/Info.js index 77d773e7a03ab4..62b0b6c4120a47 100644 --- a/examples/jsm/renderers/common/Info.js +++ b/examples/jsm/renderers/common/Info.js @@ -4,14 +4,21 @@ class Info { this.autoReset = true; + this.frame = 0; + this.calls = 0; + this.render = { - frame: 0, + calls: 0, drawCalls: 0, triangles: 0, points: 0, lines: 0 }; + this.compute = { + calls: 0 + }; + this.memory = { geometries: 0, textures: 0 @@ -60,7 +67,10 @@ class Info { this.reset(); - this.render.frame = 0; + this.calls = 0; + + this.render.calls = 0; + this.compute.calls = 0; this.memory.geometries = 0; this.memory.textures = 0; diff --git a/examples/jsm/renderers/common/Renderer.js b/examples/jsm/renderers/common/Renderer.js index ab4d9ddac81855..c2479046b49eb2 100644 --- a/examples/jsm/renderers/common/Renderer.js +++ b/examples/jsm/renderers/common/Renderer.js @@ -62,6 +62,7 @@ class Renderer { this._attributes = null; this._geometries = null; this._nodes = null; + this._animation = null; this._bindings = null; this._objects = null; this._pipelines = null; @@ -70,8 +71,6 @@ class Renderer { this._textures = null; this._background = null; - this._animation = new Animation(); - this._currentRenderContext = null; this._lastRenderContext = null; @@ -136,6 +135,7 @@ class Renderer { } this._nodes = new Nodes( this, backend ); + this._animation = new Animation( this._nodes, this.info ); this._attributes = new Attributes( backend ); this._background = new Background( this, this._nodes ); this._geometries = new Geometries( this._attributes, this.info ); @@ -148,9 +148,6 @@ class Renderer { // - this._animation.setNodes( this._nodes ); - this._animation.start(); - this._initialized = true; resolve(); @@ -197,8 +194,13 @@ class Renderer { this._currentRenderContext = renderContext; this._currentRenderObjectFunction = this._renderObjectFunction || this.renderObject; + // + nodeFrame.renderId ++; + this.info.calls ++; + this.info.render.calls ++; + // const coordinateSystem = this.coordinateSystem; @@ -213,16 +215,12 @@ class Renderer { // - if ( this._animation.isAnimating === false ) nodeFrame.update(); - if ( scene.matrixWorldAutoUpdate === true ) scene.updateMatrixWorld(); if ( camera.parent === null && camera.matrixWorldAutoUpdate === true ) camera.updateMatrixWorld(); if ( this.info.autoReset === true ) this.info.reset(); - this.info.render.frame ++; - // let viewport = this._viewport; @@ -361,15 +359,11 @@ class Renderer { } - setAnimationLoop( callback ) { - - if ( this._initialized === false ) this.init(); + async setAnimationLoop( callback ) { - const animation = this._animation; - - animation.setAnimationLoop( callback ); + if ( this._initialized === false ) await this.init(); - ( callback === null ) ? animation.stop() : animation.start(); + this._animation.setAnimationLoop( callback ); } @@ -621,6 +615,7 @@ class Renderer { this.info.dispose(); + this._animation.dispose(); this._objects.dispose(); this._properties.dispose(); this._pipelines.dispose(); @@ -665,12 +660,25 @@ class Renderer { if ( this._initialized === false ) await this.init(); + // + + this.info.calls ++; + this.info.compute.calls ++; + + // + const backend = this.backend; const pipelines = this._pipelines; const bindings = this._bindings; const nodes = this._nodes; const computeList = Array.isArray( computeNodes ) ? computeNodes : [ computeNodes ]; + if ( computeList[ 0 ] === undefined || computeList[ 0 ].isComputeNode !== true ) { + + throw new Error( 'THREE.Renderer: .compute() expects a ComputeNode.' ); + + } + backend.beginCompute( computeNodes ); for ( const computeNode of computeList ) { diff --git a/examples/jsm/renderers/common/nodes/Nodes.js b/examples/jsm/renderers/common/nodes/Nodes.js index 13543fd66d97c8..d3cbb50b03227b 100644 --- a/examples/jsm/renderers/common/nodes/Nodes.js +++ b/examples/jsm/renderers/common/nodes/Nodes.js @@ -14,7 +14,7 @@ class Nodes extends DataMap { this.backend = backend; this.nodeFrame = new NodeFrame(); this.nodeBuilderCache = new Map(); - this.frameHashCache = new ChainMap(); + this.callHashCache = new ChainMap(); } @@ -148,11 +148,11 @@ class Nodes extends DataMap { getCacheKey( scene, lightsNode ) { const chain = [ scene, lightsNode ]; - const frameId = this.nodeFrame.frameId; + const callId = this.renderer.info.calls; - let cacheKeyData = this.frameHashCache.get( chain ); + let cacheKeyData = this.callHashCache.get( chain ); - if ( cacheKeyData === undefined || cacheKeyData.frameId !== frameId ) { + if ( cacheKeyData === undefined || cacheKeyData.callId !== callId ) { const environmentNode = this.getEnvironmentNode( scene ); const fogNode = this.getFogNode( scene ); @@ -166,11 +166,11 @@ class Nodes extends DataMap { if ( toneMappingNode ) cacheKey.push( toneMappingNode.getCacheKey() ); cacheKeyData = { - frameId, + callId, cacheKey: cacheKey.join( ',' ) }; - this.frameHashCache.set( chain, cacheKeyData ); + this.callHashCache.set( chain, cacheKeyData ); } diff --git a/examples/screenshots/webgpu_instance_points.jpg b/examples/screenshots/webgpu_instance_points.jpg index c0ad77b069951d..720b1e15ba73f3 100644 Binary files a/examples/screenshots/webgpu_instance_points.jpg and b/examples/screenshots/webgpu_instance_points.jpg differ diff --git a/examples/screenshots/webgpu_lines_fat.jpg b/examples/screenshots/webgpu_lines_fat.jpg index d8df6c93aa25b3..0a7b43c05ac854 100644 Binary files a/examples/screenshots/webgpu_lines_fat.jpg and b/examples/screenshots/webgpu_lines_fat.jpg differ diff --git a/examples/screenshots/webgpu_particles.jpg b/examples/screenshots/webgpu_particles.jpg index e4b0ebeb93f47b..bfe99e946c389f 100644 Binary files a/examples/screenshots/webgpu_particles.jpg and b/examples/screenshots/webgpu_particles.jpg differ diff --git a/examples/webgpu_clearcoat.html b/examples/webgpu_clearcoat.html index 7e805d8c8b3427..0f8c37c5589944 100644 --- a/examples/webgpu_clearcoat.html +++ b/examples/webgpu_clearcoat.html @@ -42,7 +42,6 @@ let group; init(); - animate(); function init() { @@ -187,6 +186,7 @@ renderer = new WebGPURenderer( { antialias: true } ); renderer.setPixelRatio( window.devicePixelRatio ); renderer.setSize( window.innerWidth, window.innerHeight ); + renderer.setAnimationLoop( animate ); container.appendChild( renderer.domElement ); // @@ -227,8 +227,6 @@ function animate() { - requestAnimationFrame( animate ); - render(); stats.update(); diff --git a/examples/webgpu_compute_texture_pingpong.html b/examples/webgpu_compute_texture_pingpong.html index 3ee63c23527f15..92c42657e2b188 100644 --- a/examples/webgpu_compute_texture_pingpong.html +++ b/examples/webgpu_compute_texture_pingpong.html @@ -35,6 +35,8 @@ let pingTexture, pongTexture; let material; let phase = true; + let lastUpdate = - 1; + const seed = uniform( new THREE.Vector2() ); init(); @@ -184,14 +186,19 @@ function render() { - // reset every 200 frames + const time = performance.now(); + const seconds = Math.floor( time / 1000 ); + + // reset every second - if ( renderer.info.render.frame % 200 === 0 ) { + if ( phase && seconds !== lastUpdate ) { seed.value.set( Math.random(), Math.random() ); renderer.compute( computeInitNode ); + lastUpdate = seconds; + } // compute step diff --git a/examples/webgpu_instance_points.html b/examples/webgpu_instance_points.html index 44f263f8735e41..e5370261848fcb 100644 --- a/examples/webgpu_instance_points.html +++ b/examples/webgpu_instance_points.html @@ -54,7 +54,6 @@ let insetHeight; init(); - animate(); function init() { @@ -69,6 +68,7 @@ renderer = new WebGPURenderer( { antialias: true } ); renderer.setPixelRatio( window.devicePixelRatio ); renderer.setSize( window.innerWidth, window.innerHeight ); + renderer.setAnimationLoop( animate ); document.body.appendChild( renderer.domElement ); scene = new THREE.Scene(); @@ -161,8 +161,6 @@ function animate() { - requestAnimationFrame( animate ); - stats.update(); // main scene diff --git a/examples/webgpu_lines_fat.html b/examples/webgpu_lines_fat.html index dd12a97f5031d4..f306dd6d986712 100644 --- a/examples/webgpu_lines_fat.html +++ b/examples/webgpu_lines_fat.html @@ -52,7 +52,6 @@ let insetHeight; init(); - animate(); function init() { @@ -68,6 +67,7 @@ renderer.setPixelRatio( window.devicePixelRatio ); renderer.setClearColor( 0x000000, 0.0 ); renderer.setSize( window.innerWidth, window.innerHeight ); + renderer.setAnimationLoop( animate ); document.body.appendChild( renderer.domElement ); scene = new THREE.Scene(); @@ -173,8 +173,6 @@ function animate() { - requestAnimationFrame( animate ); - stats.update(); // main scene diff --git a/examples/webgpu_loader_gltf_sheen.html b/examples/webgpu_loader_gltf_sheen.html index fd16c319d21c6e..fcafbff7c99c62 100644 --- a/examples/webgpu_loader_gltf_sheen.html +++ b/examples/webgpu_loader_gltf_sheen.html @@ -43,7 +43,6 @@ let camera, scene, renderer, controls; init(); - animate(); function init() { @@ -84,6 +83,7 @@ renderer = new WebGPURenderer( { antialias: true } ); renderer.setPixelRatio( window.devicePixelRatio ); renderer.setSize( window.innerWidth, window.innerHeight ); + renderer.setAnimationLoop( animate ); renderer.toneMapping = THREE.ACESFilmicToneMapping; renderer.toneMappingExposure = 1; container.appendChild( renderer.domElement ); @@ -126,8 +126,6 @@ function animate() { - requestAnimationFrame( animate ); - controls.update(); // required if damping enabled render(); diff --git a/examples/webgpu_particles.html b/examples/webgpu_particles.html index b8a3df65f76101..53ac92bbecefa6 100644 --- a/examples/webgpu_particles.html +++ b/examples/webgpu_particles.html @@ -122,7 +122,6 @@ // const helper = new THREE.GridHelper( 3000, 40, 0x303030, 0x303030 ); - helper.material.colorNode = attribute( 'color' ); helper.position.y = - 75; scene.add( helper ); diff --git a/examples/webgpu_video_panorama.html b/examples/webgpu_video_panorama.html index c534ce64ca14ea..1557882dc34d01 100644 --- a/examples/webgpu_video_panorama.html +++ b/examples/webgpu_video_panorama.html @@ -52,7 +52,6 @@ const distance = .5; init(); - animate(); function init() { @@ -87,6 +86,7 @@ renderer = new WebGPURenderer( { antialias: true } ); renderer.setPixelRatio( window.devicePixelRatio ); renderer.setSize( window.innerWidth, window.innerHeight ); + renderer.setAnimationLoop( animate ); container.appendChild( renderer.domElement ); document.addEventListener( 'pointerdown', onPointerDown ); @@ -139,7 +139,6 @@ function animate() { - requestAnimationFrame( animate ); update(); } diff --git a/test/e2e/puppeteer.js b/test/e2e/puppeteer.js index 7e9d302c2d47b8..84640d9c9e3605 100644 --- a/test/e2e/puppeteer.js +++ b/test/e2e/puppeteer.js @@ -126,6 +126,7 @@ const exceptionList = [ 'webgpu_video_panorama', // WebGPURenderer: Unknown problem + 'webgpu_particles', 'webgpu_shadertoy', 'webgpu_tsl_editor', 'webgpu_tsl_transpiler'