question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

WebGLRenderTarget.copy Bug: Copying from render target results in targets sharing .texture.image

See original GitHub issue

Here’s a snippet to reproduce the issue:

const x = new THREE.WebGLRenderTarget();
const y = new THREE.WebGLRenderTarget();

console.log( x.texture.image === y.texture.image ); // false

x.copy( y );

console.log( x.texture.image === y.texture.image ); // true

What this means is that when x.setSize is called the object at y.texture.image is inadvertently modified but and is now out of sync with the true dimensions of render target y.

This line is the problem in Texture.copy:

this.image = source.image;

I assume this was originally intended to handle moving over an <img> tag without duplicating it – ~maybe it makes sense to duplicate the image tag? Or maybe it should clone the object in some cases:~

this.image = source.image instanceof Image ? source.image : { ...source.image };

~I imagine copy would behave a bit confusingly for DataTexture, as well.~

Edit: I see now that retaining the image data reference is important for dealing with cloning textures before they’ve been fully loaded and is valuable for minimizing data duplication.

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Comments:7

github_iconTop GitHub Comments

2reactions
Mugen87commented, Mar 16, 2022

Good catch. Let me fix this with a PR.

1reaction
ankhzetcommented, Mar 16, 2022

@mrdoob Now cloning WebGLRenderTarget breaks (?) it’s texture, as far as I understand. In the constructor texture receives this flag:

  this.texture.isRenderTargetTexture = true;

If you don’t add it during/after cloning, f.e. like this:

  this.texture = source.texture.clone();
  this.texture.isRenderTargetTexture = true;

then, if texture then is used in shader, setTexture2D() will try to upload the texture, resulting in gl.texSubImage2D throwing an error, as it can’t find the correct method overload to load the image

Struggled with this issue when tried to implement outline effect using postprocessing@6.25.0 + three@0.138.3. postprocessing modules use code like this to create internally used textures for shaders:

    this.renderTargetMask.texture.name = "Outline.Mask";
    this.uniforms.get("maskTexture").value = this.renderTargetMask.texture;
    this.renderTargetOutline = this.renderTargetMask.clone(); // <= .clone() here
    this.renderTargetOutline.texture.name = "Outline.Edges";
    this.renderTargetOutline.depthBuffer = false;
    this.uniforms.get("edgeTexture").value = this.renderTargetOutline.texture; // <= texture without 'isRenderTargetTexture' flag is used in a shader texture uniform

Worth mentioning, the lacking flag wasn’t breaking my code per se, but it generated dubious error message, which I believed was the reason, why my code didn’t work, leading me in a completely wrong direction from actual solution %). Don’t know, if it’s an issue with cloning, or such usage of WebGLRenderTarget should be discouraged in a consumer code.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Persistence postprocessing in three.js with 2 renderTargets
You need 3 render targets. Let's call them sceneTarget , previousTarget , resultTarget. Step 1: Render your scene to the sceneTarget .
Read more >
Tutorial 5: Render to Texture - TDA362/DIT223
A framebuffer is a "render target", a place OpenGL can draw pixels to. ... 2 textures: the color texture, which is copied to...
Read more >
WebGLRenderTarget – three.js docs
WebGLRenderTarget. A render target is a buffer where the video card draws pixels for a scene that is being rendered in the background....
Read more >
WebGL Rendering to a Texture
In this article we'll render to textures using WebGL. Note this topic was covered tersely under image processing but let's cover it in...
Read more >
Three.js Render Targets
By default WebGLRenderTarget creates 2 textures. A color texture and a depth/stencil texture. · You might need to change the size of a...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found