使用three.js中的交换缓冲区在反馈循环的第一帧中加载文件纹理

时间:2015-03-20 22:27:52

标签: debugging three.js webgl fbo feedback

我正在使用几个反馈着色器循环(纹理乒乓)在three.js的网站上工作。

当有人访问该网站时,循环应该从某个点继续(取决于他/她访问的时间)。为了达到这个目的,我打算在第一帧中从服务器加载一张图片(例如一个jpeg),将其渲染到我的乒乓缓冲区并从第2帧开始继续我的正常反馈循环。

这是我的问题的精简版,作为反馈功能,我只需在前一帧中为像素的颜色添加一个小值。

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <title>feedbacktest</title>
        <style>canvas { width: 100%; height: 100%; }</style>
    </head>
    <body>
        <!-- Main THREE includes -->
        <script src="js/three.min.js"></script>
        <script src="js/Detector.js"></script>
        <!-------------------->
        <!-- Shaders        -->
        <!-------------------->

                        <!-- no change vertex shader. used for all render stages. -->
        <script id="vs_output" type="x-shader/x-vertex">

            varying vec2 texCoord;

            void main(void)
            {
                texCoord = uv;                              
                gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
            }
        </script>

        <!-- feedback shader -->
        <script id="fs_feedback" type="x-shader/x-fragment">        
            // switch on high precision floats
            #ifdef GL_ES
            precision highp float;
            #endif      
            uniform sampler2D texture;
            uniform sampler2D texture2;
            varying vec2 texCoord;
            uniform float onOpen;

            void main() 
            {                       
                // sample textures
                vec4 result = texture2D(texture, texCoord);
                vec4 startT = texture2D(texture2, texCoord);                
                result.rgb+=0.001;
                result.rgb = mod(result.rgb, 1.0);
    /*          if (onOpen <=1.0){
                    result.rgb=startT.rgb;
                }*/
                result.a = 1.0;                                 
                gl_FragColor = result;              
            }
        </script>

        <!-- Final pass fragment shader. -->
        <script id="fs_output" type="x-shader/x-fragment">

            uniform sampler2D fb2output;                        
            varying vec2 texCoord;

            void main (void)
            {
                vec4 col = texture2D(fb2output, texCoord);                      
                gl_FragColor = col;
            }
        </script>

                <!-- init shader. -->
        <script id="fs_start" type="x-shader/x-fragment">

            uniform sampler2D texture;                      
            varying vec2 texCoord;

            void main (void)
            {
                vec4 col = texture2D(texture, texCoord);

                gl_FragColor = col;
            }
        </script>

        <!-------------------->
        <!-- Main Logic     -->
        <!-------------------->
        <script>
            if (!Detector.webgl)
            {
                Detector.addGetWebGLMessage();
            }
            //------------------------------------------
            // Globals
            //------------------------------------------
            var cameraLoop, cameraOutput, sceneFeedback, sceneOutput, renderer, sceneStart;
            var feedbackTexture, feedbackTexture2, loadTexture;         
            var feedbackUniforms, mainUniforms, startUniforms;
            var feedbackQuad, screenQuad, startQuad;
            var feedbackMat, screenMat, startMat;
            var loopRes = new THREE.Vector2(64.0, 64.0);
            var outputRes = new THREE.Vector2(512.0, 512.0);

            var doLoad =0.0;
//          var onOpen = 0.0;

            var renderTargetNearestFloatParams = {
                minFilter:THREE.NearestFilter,
                magFilter:THREE.NearestFilter,
                wrapS:THREE.ClampToEdgeWrapping,
                wrapT:THREE.ClampToEdgeWrapping,
                format:THREE.RGBAFormat,
                stencilBuffer:false,
                depthBuffer:false,
                needsUpdate:true,
                type:THREE.FloatType
            };

            //------------------------------------------
            // Main init and loop
            //------------------------------------------
            start();
            update();

            //------------------------------------------
            // Initialization
            //------------------------------------------
            function start() 
            {   

                //setup scenes          
                sceneOutput = new THREE.Scene();
                sceneFeedback = new THREE.Scene();
                sceneStart = new THREE.Scene();

                //setup renderer
                renderer = new THREE.WebGLRenderer({ precision:"highp"});
                renderer.setSize( window.innerWidth, window.innerHeight );
                renderer.setClearColor(0x808080);
                renderer.autoClear = false;
                document.body.appendChild( renderer.domElement );   

                // create buffers
                feedbackTexture = new THREE.WebGLRenderTarget( loopRes.x, loopRes.y, renderTargetNearestFloatParams );              
                feedbackTexture2 = new THREE.WebGLRenderTarget( loopRes.x, loopRes.y, renderTargetNearestFloatParams ); 

                // load a texture, set wrap mode
                var loadTexture = THREE.ImageUtils.loadTexture( "textures/tes2t.jpg" );
                loadTexture.wrapS = THREE.ClampToEdgeWrapping;
                loadTexture.wrapT = THREE.ClampToEdgeWrapping;
                loadTexture.minFilter = THREE.NearestFilter;
                loadTexture.magFilter = THREE.NearestFilter;
                loadTexture.format = THREE.RGBAFormat;
                loadTexture.type = THREE.FloatType;

                // Setup algorithm camera
                cameraLoop = new THREE.OrthographicCamera( loopRes.x / - 2, loopRes.x / 2, loopRes.y / 2, loopRes.y / - 2, -10000, 10000 );

                // Setup sceneOutput camera
                cameraOutput = new THREE.PerspectiveCamera( 60, window.innerWidth/window.innerHeight, 1, 10000 );
                cameraOutput.position.z = 300;

                // feedback shader
                feedbackUniforms = {
                    texture: { type: "t", value: feedbackTexture2 },
                    texture2: { type: "t", value: loadTexture },
                    onOpen: { type: "f", value: 0.0 },
                };
                feedbackMat = new THREE.ShaderMaterial({
                    uniforms: feedbackUniforms,
                    vertexShader: document.getElementById( 'vs_output' ).textContent,
                    fragmentShader: document.getElementById( 'fs_feedback' ).textContent
                });             
                var feedbackGeo = new THREE.PlaneBufferGeometry( loopRes.x, loopRes.y );
                feedbackQuad = new THREE.Mesh( feedbackGeo, feedbackMat );
                feedbackQuad.position.z = -100;
                sceneFeedback.add( feedbackQuad );

                // output shader
                mainUniforms = {
                    fb2output: { type: "t", value: feedbackTexture2 },                  
                };              
                screenMat = new THREE.ShaderMaterial({
                    uniforms: mainUniforms,
                    vertexShader: document.getElementById( 'vs_output' ).textContent,
                    fragmentShader: document.getElementById( 'fs_output' ).textContent,
                });
                var screenGeo = new THREE.PlaneBufferGeometry( outputRes.x, outputRes.y );              
                sceneQuad = new THREE.Mesh( screenGeo , screenMat );
                sceneQuad.position.z = -200;
                sceneOutput.add( sceneQuad );               

                            // init shader
                startUniforms = {
                    texture: { type: "t", value: loadTexture },                 
                };              
                startMat = new THREE.ShaderMaterial({
                    uniforms: startUniforms,
                    vertexShader: document.getElementById( 'vs_output' ).textContent,
                    fragmentShader: document.getElementById( 'fs_start' ).textContent,
                });
                var startGeo = new THREE.PlaneBufferGeometry(  loopRes.x, loopRes.y );              
                startQuad = new THREE.Mesh( startGeo , startMat );
                startQuad.position.z = -100;
                sceneStart.add( startQuad );                
            }           


            //------------------------------------------
            // Main loop
            //------------------------------------------
            function update() 
            {
                requestAnimationFrame( update );
                console.debug(doLoad.toString());
                render();               
            }

            //------------------------------------------
            // Main rendering
            //------------------------------------------
            function render() 
            {
                renderer.clear();

                if (doLoad < 1.0){

                    renderer.render( sceneStart, cameraLoop, feedbackTexture2);

                    doLoad = 1.0;

                } else {

                renderer.render( sceneFeedback, cameraLoop, feedbackTexture);

                var a = feedbackTexture2;
                feedbackTexture2 = feedbackTexture;
                feedbackTexture = a;
                feedbackUniforms.texture.value = feedbackTexture2;
                }

                renderer.render( sceneOutput, cameraOutput );
    //          feedbackUniforms.onOpen.value += 0.5;
            }

        </script>
    </body>
</html>  

正如你在渲染函数中看到的那样,我试图在第1帧中渲染sceneStart,然后在场景中渲染sceneFeedback(如果/ else阻止)。不幸的是,这不起作用。我已经尝试了各种各样的东西,也在着色器本身切换到开始纹理(参见注释代码),但没有运气。 我发现当我改变这条线时

doLoad = 1.0;

doLoad +=0.4;

或低于0.5的任何东西都可以。据我所知,它必须在我的反馈缓冲区中写入3次,直到正常循环可以在那里工作....但为什么?

在第一帧中写入反馈纹理也不起作用,正如您可能建议的那样......

不幸的是,将它渲染为3帧并不是我的解决方案,因为它会破坏我所涉及的实际着色器之一并且还会带来其他问题,这些问题比在第一帧中加载图片要复杂得多。 ...

在旁注中,我如何调试three.js应用程序的第一帧?我知道WebGL Inspector但是如果我在那里减慢帧速率然后刷新播放设置又恢复正常......有什么建议吗?

非常感谢你!

1 个答案:

答案 0 :(得分:1)

我很确定在开始渲染之前需要等待图像加载。图像加载异步,因此您的前几帧不会加载纹理。

看起来你正在使用THREE.ImageUtils.loadTextureAccording to the docs loadTexture需要4个参数(.loadTexture (url, mapping, onLoad, onError))第3个是加载图像时的回调。

在加载图像之前,您可能不想渲染。在您的代码的开头,您有

start();
update();   // delete this line

删除更新行,然后将loadTexture行更改为

// load a texture, set wrap mode
var loadTexture = THREE.ImageUtils.loadTexture( 
    "textures/tes2t.jpg", undefined, update );

当图像加载并开始渲染时,将调用update