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
scene_setup();
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 );
bufferScene.add(bufferObject);
//Draw textureB to screen
finalMaterial = new THREE.MeshBasicMaterial({map: textureB});
quad = new THREE.Mesh( plane, finalMaterial );
scene.add(quad);
}
buffer_texture_setup();
//Render everything!
function render() {
requestAnimationFrame( render );
//Draw to textureB
// renderer.render(bufferScene,camera,textureB,true);
renderer.setRenderTarget(textureB);
renderer.clear();
renderer.render(bufferScene,camera);
//Swap textureA and B
var t = textureA;
textureA = textureB;
textureB = t;
quad.material.map = textureB;
bufferMaterial.uniforms.bufferTexture.value = textureA;
//Finally, draw to the screen
renderer.render( scene, camera );
}
render();
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;
}