As a newcomer to both ThreeJS and GLSL, I am exploring ways to reuse the output of a fragment shader in another shader, while also utilizing that same output in the subsequent frame of the same shader. Essentially, the output of the shader is dependent on the output of the previous frame. My approach involves using WebGLRenderTarget to achieve this goal.
Below is the code snippet I am working with:
import * as THREE from "three"
var camera, camera_2, fireShader, mainShader, renderer, scene, scene_2
const width = 1200
const height = 720
const texture = new THREE.TextureLoader().load('./images/00_map.png')
var fire = new THREE.TextureLoader().load('./images/fire_01.png')
const fireLayer = new THREE.WebGLRenderTarget(width, height)
const uniforms = {
iTime: { value: 0 },
iResolution: { value: new THREE.Vector3(width, height, 1) },
iTexture: { value: texture},
iFire: { value: fire }
}
const now = new Date()
async function init() {
const stage = document.getElementById('stage')
renderer = new THREE.WebGLRenderer({antialias: true})
scene = new THREE.Scene()
camera = new THREE.OrthographicCamera(width / -2, width / 2, height / 2, height / -2, 0.1, 20)
camera.position.z = 5
renderer.setSize(width, height)
stage.appendChild(renderer.domElement)
mainShader = await (await fetch('shaders/frag.glsl')).text()
const geometry = new THREE.PlaneGeometry(width, height)
const material = new THREE.ShaderMaterial({
uniforms,
fragmentShader: mainShader
})
material.needsUpdate = true
const plane = new THREE.Mesh(geometry, material)
scene.add(plane)
}
async function init_2 () {
scene_2 = new THREE.Scene()
camera_2 = new THREE.OrthographicCamera(width / -2, width / 2, height / 2, height / -2, 0.1, 20)
camera_2.position.z = 5
fireShader = await (await fetch('shaders/fire.glsl')).text()
const geometry = new THREE.PlaneGeometry(width, height)
const material = new THREE.ShaderMaterial({
uniforms,
fragmentShader: fireShader
})
material.needsUpdate = true
const plane = new THREE.Mesh(geometry, material)
scene_2.add(plane)
}
function render() {
uniforms.iTime.value = (new Date() - now) * .001
renderer.setRenderTarget(fireLayer)
renderer.render(scene_2, camera_2)
if (scene.children[0])
scene.children[0].material.uniforms.iFire.value = fireLayer.texture
renderer.setRenderTarget(null)
renderer.render(scene, camera)
}
function animate() {
render()
requestAnimationFrame(animate)
}
init()
init_2()
animate()
While attempting to update the texture using
scene.children[0].material.uniforms.iFire.value = fireLayer.texture
, I encountered an illegal feedback error. Additionally, trying {...fireLayer.texture}
did not display anything, possibly due to issues with image copying.
How can I efficiently copy the output of a fragment shader and utilize it within the same shader that generated it?