Trying to use copyFramebufferToTexture

I’m trying to use FramebufferTexture to map to a plane mesh basic material. Below is the simplified version of my code. Any help would be appreciated!

// For simplicity sake, defined these const:

// renderBuffer = THREE.WebGLRenderTarget
// mainScene = THREE.Scene
// bufferScene = THREE.Scene
// renderer = THREE.WebGLRenderer
// camera = THREE.OrthographicCamera
// bufferTex = THREE.FramebufferTexture

renderer.setAnimationLoop(animLoop);

function animLoop() {
  renderer.setRenderTarget(renderBuffer);
  renderer.render(bufferScene, camera);

  // this gives me error
  renderer.copyFramebufferToTexture(bufferTex, new THREE.vector2());

  renderer.setRenderTarget(null);
  renderer.render(mainScene, camera);
}

The error in question:
Chromium 127.0.6533.89

GL_INVALID_OPERATION: Invalid copy texture format combination.

Firefox 127.0.2

WebGL warning: copyTexSubImage: Implementation bug, please file at https://bugzilla.mozilla.org/enter_bug.cgi?product=Core&component=Canvas%A+WebGL! ANGLE is particular about CopyTexSubImage formats matching exactly. 

I’ve tried following this example with no success:
https://github.com/mrdoob/three.js/blob/817a222f2d12baf44a38baf256bc9d4f65d82465/examples/webgl_framebuffer_texture.html

Three version: 0.166.1

I’ve never used copyFramebufferToTexture because I always do it with the renderTarget. But what I see is that your frameBuffer has no width and no height. Your new THREE.Vector2() is empty. In the example you can see that the vector is filled first and only then is copyFramebufferToTexture rendered with the filled vector. In your case width and height are undefined and that leads to an error.

new THREE.vector2()

You need

new THREE.vector2(width, height);

So that the vector doesn’t have to be recreated in every render loop, it’s best to set it in the init. So try it with width and height, then it will definitely be better :blush:

An alternative way to render a scene into a texture is to use a renderTarget

//in the init

let frameBuffer = new THREE.WebGLRenderTarget(width, height, {
    format: THREE.RGBAFormat,
    minFilter: THREE.LinearMipmapLinearFilter,
    magFilter: THREE.LinearFilter,
    generateMipmaps: true,
    wrapS: THREE.RepeatWrapping,
    wrapT: THREE.RepeatWrapping
});


let target = frameBuffer.texture;

//renderloop

renderer.setRenderTarget(frameBuffer);
renderer.render(bufferScene, camera);
renderer.setRenderTarget(null);	

renderer.render(mainScene, camera);

By the way, you don’t necessarily need a bufferScene. You can render your planemesh directly if it is the only thing you want rendered in the bufferScene.

So that’s how:

renderer.render(planemesh, camera);

You can imagine this as if you had glued the planemesh to the camera lens.

1 Like

renderTarget works perfectly! + I followed your optimizations. It’s very performant now. You have no idea how much time I’ve spent on this. Thank you!

1 Like