I attempted to implement the pingpong texture swap technique to generate smoke in threejs by following a tutorial that was published some years ago. Unfortunately, this tutorial utilizes an outdated version of threejs, and I am experiencing difficulties trying to make it work with the latest library version.
Even though there are no visible errors, nothing seems to render on the screen. I am uncertain about where I might have made a mistake. Can someone please help me identify what went wrong?
The code snippet below shows my own endeavor to get the initial step of the tutorial functioning - it encompasses the texture swap and a simple shader that smoothly transitions from black to red. As previously mentioned, everything runs smoothly on an older iteration of the library, which can be observed here. My goal is to comprehend how to successfully execute it on the most recent build of threejs.
I stumbled upon a hint from a related question pointing out that in newer versions of threejs, the .render()
method only accepts two arguments. This led me to believe that might be the cause of my issue-less black screen. Despite delving deeper into the documentation and tweaking my code correspondingly, I still cannot seem to get things operational and lack any error messages to guide my troubleshooting efforts.
Below is the JavaScript code:
import * as THREE from 'three';
import FragmentShader from './main.frag';
var scene;
var camera;
var renderer;
function scene_setup(){
//Basic scene setup
scene = new THREE.Scene();
var width = window.innerWidth;
var height = window.innerHeight;
//Using an orthographic camera instead of perspective
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 Three.js scene
scene_setup();
var bufferScene;
var textureA;
var textureB;
var bufferMaterial;
var plane;
var bufferObject;
var finalMaterial;
var quad;
function buffer_texture_setup(){
//Creating buffer scene
bufferScene = new THREE.Scene();
//Generating 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} );
//Assigning textureA to shader
bufferMaterial = new THREE.ShaderMaterial( {
uniforms: {
bufferTexture: { type: "t", value: textureA },
res : {type: 'v2', value:new THREE.Vector2(window.innerWidth,window.innerHeight)} //Maintains resolution
},
fragmentShader: FragmentShader
} );
plane = new THREE.PlaneGeometry( window.innerWidth, window.innerHeight );
bufferObject = new THREE.Mesh( plane, bufferMaterial );
bufferScene.add(bufferObject);
//Displaying textureB on screen
finalMaterial = new THREE.MeshBasicMaterial({map: textureB});
quad = new THREE.Mesh( plane, finalMaterial );
scene.add(quad);
}
buffer_texture_setup();
//Rendering components!
function render() {
requestAnimationFrame( render );
//Drawing to textureB
//renderer.render(bufferScene,camera,textureB,true);
renderer.setRenderTarget(textureB);
renderer.clear();
renderer.render(bufferScene,camera);
//Swapping textureA and B
var t = textureA;
textureA = textureB;
textureB = t;
quad.material.map = textureB;
bufferMaterial.uniforms.bufferTexture.value = textureA;
//Lastly, rendering to the screen
renderer.render( scene, camera );
}
render();
The shader looks like this:
uniform vec2 res; //Screen width and height
uniform sampler2D bufferTexture; //Input texture
void main() {
vec2 pixel = gl_FragCoord.xy / res.xy;
gl_FragColor = texture2D( bufferTexture, pixel );
gl_FragColor.r += 0.01;
}