Three.js - 首先渲染到renderTarget,然后在白色屏幕上显示结果

时间:2012-11-22 14:49:33

标签: webgl three.js

在我当前的项目中,我想在一个渲染过程中使用多个着色器。我认为这可以通过仅将最后一次传递到屏幕并将所有先前的传递渲染到renderTarget,然后将此renderTarget作为纹理传递到下一个着色器来实现。

我的案例中的问题似乎出现在以下代码的渲染循环中:

// something is going wrong here:    
viewer.renderer.render(viewer.scene, viewer.camera, viewer.renderTarget);

viewer.uniforms.tDiffuse.value = viewer.renderTarget;
viewer.uniforms.fragmentShader = viewer.fragment2;

viewer.renderer.render(viewer.scene, viewer.camera);

为了使事情更清楚,我构建了这个片段

var viewer = {
    width: 512,
    height: 512
};

initViewer = function() {
    viewer.vertex     = $('#vertexShader').text();
    viewer.fragment1  = $('#fragmentShader1').text();
    viewer.fragment2  = $('#fragmentShader2').text();    

    
    viewer.camera = new THREE.OrthographicCamera(viewer.width / -2, viewer.width / 2, viewer.height / 2, viewer.height / -2, -1000, 1000);

    viewer.camera.position.z = 100;

    viewer.renderer = new THREE.WebGLRenderer();
    viewer.scene = new THREE.Scene();

    viewer.uniforms = {
        alpha: {
            type: 'f',
            value: '1.0'
        }, tDiffuse: {
            type: 't',
            value: ''
        }
    };
    
    viewer.initialMaterial = new THREE.ShaderMaterial({
        uniforms: viewer.uniforms,
        vertexShader: viewer.vertex,
        fragmentShader: viewer.fragment1
    });
    
    viewer.plane = new THREE.Mesh(new THREE.PlaneGeometry(viewer.width, viewer.height), viewer.initialMaterial);

    viewer.scene.add(viewer.plane);
    
    $('body').append(viewer.renderer.domElement);
    
    viewer.renderTarget = new THREE.WebGLRenderTarget( 512, 512 );
    
    render();
};

render = function() {
    
    // commenting out the next line makes everything work
    viewer.renderer.render(viewer.scene, viewer.camera, viewer.renderTarget);
    
    viewer.uniforms.tDiffuse.value = viewer.renderTarget;
    viewer.uniforms.fragmentShader = viewer.fragment2;

    
    viewer.renderer.render(viewer.scene, viewer.camera);

    requestAnimationFrame(render);
};

initViewer();
canvas 
{
    border: 1px solid lime;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script id="vertexShader" type="x-shader/x-vertex">

precision mediump float;

varying vec2 v_texCoord;
varying vec4 vertexPosition;

void main()
{
    v_texCoord = uv;
    vec3 p = position;
    vec4 mvPosition = modelViewMatrix * vec4(p, 1.0 );
    gl_Position = projectionMatrix * mvPosition;
    vertexPosition = gl_Position;
}
</script>

<script id="fragmentShader1" type="x-shader/x-fragment">

precision mediump float;

void main()
{
    gl_FragColor = vec4(1.0, 0.0, 0.0, 0.2);
}
</script>

<script id="fragmentShader2" type="x-shader/x-fragment">

precision mediump float;
uniform sampler2D tDiffuse;
varying vec2 v_texCoord;

void main()
{
    gl_FragColor = texture2D( tDiffuse, v_texCoord) * vec4(0.0, 1.0, 1.0, 0.2);
}
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/91/three.min.js"></script>

关于我做错的任何想法?

2 个答案:

答案 0 :(得分:1)

通过从块中构建我需要的着色器来解决它(像这样:https://github.com/mrdoob/three.js/blob/r50/src/renderers/WebGLShaders.js

答案 1 :(得分:0)

最简单的方法:渲染所有传递以分离纹理,然后将它们应用于full-screen quad,将它们与着色器混合。或者在单独的全屏四边形上设置Blending进行添加。 您也可以只使用不同着色方法(read this)对相同对象进行混合和乘法渲染,如果只需要简单的合成,它将为您节省GPU内存和Texture Fill Rate