Search code examples
three.jstextures

how to switch the texture of render target in three js?


I need to perform some calculation based on texture.

I have two textures: current texture and next texture. The content of the next texture depends on the current texture.

Here is the procedure of my program

  1. Initialize the current texture and next texture

    let array = new Float32Array(3 * amount);
    array = init(array);
    currentTexture= new THREE.DataTexture(array ,
        textureSize, textureSize,
        THREE.RGBFormat, THREE.FloatType);
    
    let textureOptions = {
        format: THREE.RGBAFormat,
        type: THREE.FloatType
    };
    nextTexture= new THREE.WebGLRenderTarget(textureSize, textureSize, textureOptions);
    
  2. render to next texture and swap the current texture and next texture for next render

    renderer.render(scene, camera, nextTexture);
    let temp = mesh.material.uniforms.currentTexture.value;
    mesh.material.uniforms.currentTexture.value = nextTexture.texture;
    mesh.material.needsUpdate = true;
    nextTexture.texture = temp;
    

But my program doesn't work, the browser console is full of GL ERROR :GL_INVALID_OPERATION : glDrawArrays: Source and destination textures of the draw are the same. I think this is because the current texture and next texture are not swapped successfully.

How can I fix it? Thanks


Solution

  • You can't modify a Render Target's texture field so you'll need two render textures and to use one as a render target and one as a mesh texture. You'll have to seed the initial render target with the data by some means like rendering a full screen quad to the Render Target first.

    Here's an example of what the initialization might look like:

    let array = new Float32Array(3 * amount);
    array = init(array);
    
    let dataTex = new THREE.DataTexture(array,
        textureSize, textureSize,
        THREE.RGBFormat, THREE.FloatType);
    
    // Create the textures to swap
    let textureOptions = {
        format: THREE.RGBAFormat,
        type: THREE.FloatType
    };
    let currentTexture = new THREE.WebGLRenderTarget(textureSize, textureSize, textureOptions);
    let nextTexture = new THREE.WebGLRenderTarget(textureSize, textureSize, textureOptions);
    
    // material with shader to render next frame based on the current texture
    const material = /* custom material */; 
    
    // ... init the current texture by rendering a quad with the data texture to seed the texture
    

    And then rendering the textures before swapping them:

    // render the animation step
    material.uniforms.currentTexture.value = currentTexture.texture;
    renderer.render(scene, camera, nextTexture);
    
    // swap the textures
    let temp = currentTexture;
    currentTexture = nextTexture;
    nextTexture = temp;
    

    Hope that helps!