-
-
Notifications
You must be signed in to change notification settings - Fork 36.3k
Description
Description
This is related to issues previously discussed in #32642
ViewportTextureNode and ViewportDepthTextureNode have buffer caching mechanism that is supposed to reuse texture buffers per reference. However, when rendering to multiple targets of different size, the cached buffers are brute-force destroyed and re-created per each target and frame.
jsfiddle example shows that rendering two CanvasTargets of different size cause 6 texture destructions and creations per frame. This shows that caching mechanism is not actually working or is designed incorrectly.
-
ViewportDepthTextureNode: Uses a singleton _sharedDepthbuffer that is shared across all RenderTargets/CanvasTargets. This causes brute-force destruction and re-creation of depth buffer per reference on every rendered frame if references are not exactly the same size. This affects both CanvasTarget and RenderTarget -
ViewporTextureNodeDoes not consider CanvasTarget as a reference. It simply does not do caching for CanvasTargets -
Renderer: Uses a single _frameBufferTarget that resizes for each canvas (if not exactly the same size), triggering
depthTexture.needsUpdate = true and causing texture recreation
cc @Mugen87
Reproduction steps
- Open js fiddle and examine js code
- Notice that each frame 6 buffer textures are destroyed and created.
Code
import * as THREE from 'three/webgpu';
import { linearDepth, viewportLinearDepth, vec3 } from 'three/tsl';
import WebGPU from 'three/addons/capabilities/WebGPU.js';
if ( WebGPU.isAvailable() === false ) {
document.body.appendChild( WebGPU.getErrorMessage() );
throw new Error( 'No WebGPU support' );
}
let renderer;
const views = [];
let createTextureCount = 0;
let createTexturePerFrameCount = 0;
function createView( canvasId, rotationSpeed, width, height ) {
const canvas = document.getElementById( canvasId );
const canvasTarget = new THREE.CanvasTarget( canvas );
canvasTarget.setPixelRatio( window.devicePixelRatio );
canvasTarget.setSize( width, height );
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera( 50, 1, 0.1, 10 );
camera.position.set( 0, 4, 0 );
camera.lookAt( 0, 0, 0 );
const depthDistance = viewportLinearDepth.distance( linearDepth() );
const sphere = new THREE.Mesh(
new THREE.SphereGeometry( 0.75, 32, 32 ),
new THREE.MeshBasicNodeMaterial( {
colorNode: vec3( depthDistance ),
side: THREE.DoubleSide
} )
);
sphere.renderOrder = 1;
scene.add( sphere );
const bgKnot = new THREE.Mesh(
new THREE.TorusKnotGeometry( 1, 0.4, 50, 20 ),
new THREE.MeshBasicNodeMaterial()
);
bgKnot.rotation.x = - Math.PI / 2;
bgKnot.position.y = - 2.8;
scene.add( bgKnot );
return {
canvasTarget,
scene,
camera,
sphere,
rotationSpeed,
bgKnot,
};
}
function init() {
renderer = new THREE.WebGPURenderer( { antialias: true } );
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setAnimationLoop( animate );
renderer.init().then( () => {
const backend = renderer.backend;
const originalCreateTexture = backend.createTexture.bind( backend );
backend.createTexture = function( texture, options ) {
createTextureCount++;
document.getElementById('createTexture').textContent = createTextureCount;
createTexturePerFrameCount++;
return originalCreateTexture( texture, options );
};
} );
views.push( createView( 'canvas1', 0.2, 360, 360 ) );
views.push( createView( 'canvas2', 1.8, 240, 240 ) );
}
function animate() {
const time = performance.now() * 0.001;
for ( const view of views ) {
view.bgKnot.rotation.x = time * view.rotationSpeed;
view.bgKnot.rotation.y = time * view.rotationSpeed * 0.7;
renderer.setCanvasTarget( view.canvasTarget );
renderer.render( view.scene, view.camera );
}
document.getElementById('createTexturePerFrame').textContent = createTexturePerFrameCount;
createTexturePerFrameCount = 0;
}
init();Live example
Screenshots
Version
dev
Device
No response
Browser
No response
OS
No response