javascript 使用threejs和GLSL递归地使用WebGLRenderTarget

lnlaulya  于 12个月前  发布在  Java
关注(0)|答案(1)|浏览(98)

我对ThreeJS和GLSL都是新手。我试图在另一个片段着色器中重用一个片段着色器的输出,并在下一帧的同一着色器中使用相同的输出。换句话说,着色器的输出取决于前一帧中同一着色器的输出。我试图使用WebGLRenderTarget来实现这一点。
下面是我的代码:

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()

字符串
更新纹理如上图所示,即scene.children[0].material.uniforms.iFire.value = fireLayer.texture导致非法反馈错误。当我尝试使用{...fireLayer.texture}更新纹理时,什么都没有显示。我怀疑这是因为这样复制并没有复制图像。
如何正确复制片段着色器的输出并在生成它的同一着色器中使用它?

rjjhvcjd

rjjhvcjd1#

如果你尝试读写同一张图片,你会得到未定义的结果和一个非法的反馈错误。你必须使用FramebufferTexture。将着色器的输出复制到帧缓冲区纹理中,并将此纹理用作下一帧的输入:

const fireLayerFbCopy = new THREE.FramebufferTexture(width, height)
const fireLayer = new THREE.WebGLRenderTarget(width, height)

个字符

相关问题