Using pingpong approach for rendering to texture - no errors, nothing rendering to screen :/

I’m trying to use the pingpong texture swap approach to create some smoke in threejs, following this tutorial which dates back a few years. It uses an older version of threejs, and I can’t seem to get it working with the most current version of the library.

There are no errors showing yet nothing is rendering to the screen… I wonder if anyone can help me see where I’ve gone wrong?

The code below was my own attempt at getting the first step of the tutorial to work - which involves the texture swap and a very simple shader that briefly fades from black to red. As I mentioned, everything works fine on an older version of library, which you can see running here. I’d like to understand how to get it running properly on the most up to date iteration of threejs.

I found a clue from this earlier question about how in the more up to date versions of threejs, .render() only accepts two arguments, which made me think that was the culprit of my error-less black screen, but even after reading through the docs some more, and adjusting my code, I still can’t seem to get things working and have no errors to guide my searching.

the javascript:

import * as THREE from 'three';
import FragmentShader from './main.frag';

var scene;
var camera;
var renderer;

function scene_setup(){
    //This is the basic scene setup
    scene = new THREE.Scene();
    var width = window.innerWidth;
    var height = window.innerHeight;
    //Note that we're using an orthographic camera here rather than a prespective
    camera = new THREE.OrthographicCamera( width / - 2, width / 2, height / 2, height / - 2, 1, 1000 );
    camera.position.z = 2;

    renderer = new THREE.WebGLRenderer();
    renderer.setSize( window.innerWidth, window.innerHeight );
    document.body.appendChild( renderer.domElement );
//Initialize the Threejs scene

var bufferScene;
var textureA;
var textureB;
var bufferMaterial;
var plane;
var bufferObject;
var finalMaterial;
var quad;

function buffer_texture_setup(){
    //Create buffer scene
    bufferScene = new THREE.Scene();
    //Create 2 buffer textures
    textureA = new THREE.WebGLRenderTarget( window.innerWidth, window.innerHeight, { minFilter: THREE.LinearFilter, magFilter: THREE.NearestFilter});
    textureB = new THREE.WebGLRenderTarget( window.innerWidth, window.innerHeight, { minFilter: THREE.LinearFilter, magFilter: THREE.NearestFilter} );

    //Pass textureA to shader
    bufferMaterial = new THREE.ShaderMaterial( {
    uniforms: {
        bufferTexture: { type: "t", value: textureA },
        res : {type: 'v2',value:new THREE.Vector2(window.innerWidth,window.innerHeight)}//Keeps the resolution
    fragmentShader: FragmentShader
    } );
    plane = new THREE.PlaneGeometry( window.innerWidth, window.innerHeight );
    bufferObject = new THREE.Mesh( plane, bufferMaterial );

    //Draw textureB to screen 
    finalMaterial =  new THREE.MeshBasicMaterial({map: textureB});
    quad = new THREE.Mesh( plane, finalMaterial );

//Render everything!
function render() {

    requestAnimationFrame( render );

    //Draw to textureB
    // renderer.render(bufferScene,camera,textureB,true);
    //Swap textureA and B
    var t = textureA;
    textureA = textureB;
    textureB = t; = textureB;
    bufferMaterial.uniforms.bufferTexture.value = textureA;

    //Finally, draw to the screen
    renderer.render( scene, camera );

the shader:

uniform vec2 res; //The width and height of our screen 
uniform sampler2D bufferTexture; //Our input texture 
void main() {
    vec2 pixel = gl_FragCoord.xy / res.xy;
    gl_FragColor = texture2D( bufferTexture, pixel );
    gl_FragColor.r += 0.01;


hi @elizasj
you’re very close to the goal here, i think you just need to set your material map and bufferMaterial.uniform value to


check the following codepen i’ve modified to work with three r148, there’s not much difference from this to your code apart from the mentioned changes above…

hope this helps.


Ah amazing, thank you! Wow, I really wasn’t that far at all.
I really appreciate your help with this :smiling_face: :pray:

1 Like