Three.js Shader-Texture闪烁

时间:2013-02-25 22:30:16

标签: three.js shader gpu

我是three.js的新手并认为这很棒。我试图更好地保持将纹理数据移动到着色器,以便我可以主要使用GPU。我的程序基于Doob先生的魔法粉尘示例,但我没有使用存储在纹理中的粒子而是加载的模型。我现在遇到一个问题,我在那里闪烁。下面的代码是闪烁的一个粗略的例子,并且与我正在做的事情有一些接近。如果有人能帮助我理解我做错了什么或闪烁来自哪里......我很确定一切都是最新的,就像在纹理映射和three.js版本中一样。 非常感谢

<!doctype html>
<html>
    <head>
        <meta charset="utf-8" />
        <title>Sample Three.js</title>
    </head>

    <div id="container">
    </div>

    <body>
        <script type="text/javascript" src="./Scripts/three.js"></script>

        <script type="text/javascript">

        //
        // as name suggests - utilty functions mostly from Mr.doob from THREE.FBOUtils
        //
        UtilityFuncs = function() {
            this.textureWidth = 0;
            this.textureHeight = 0;
            this.scene = null;
            this.camera = null;
            this.renderer = null;
            this.material = null;
            this.jsonLoader = null;
            this.jsonModel = null;
            this.loadCount = 0;
        }

        UtilityFuncs.prototype.createScene = function( textureWidth, textureHeight, renderer ) {
            var gl = renderer.getContext();

            if( !gl.getExtension( "OES_texture_float" )) {
                    alert( "No OES_texture_float support for float textures!" );
                    return;
            }

            if( gl.getParameter(gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS) == 0) {
                    alert( "No support for vertex shader textures!" );
                    return;
            }

            var camera = new THREE.OrthographicCamera(-textureWidth/2, textureHeight/2,
                                                      textureWidth/2, -textureHeight/2,
                                                      -1000, 1000);
            camera.position.z = 100;

            // Shader Stuff
            var vertex_shader = [
                "varying vec2 vUv;",
                "void main() {",
                "    vUv = vec2(uv.x, 1.0 - uv.y);",
                "    gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",
                "} "
            ].join("\n");

            var fragment_shader = [
                "varying vec2 vUv;",
                "uniform sampler2D tPositions;",
                "void main() {",
                "    vec4 pos = texture2D( tPositions, vUv );",
                "    gl_FragColor = pos;",
                "}"
            ].join("\n");

            var material = new THREE.ShaderMaterial({
                    uniforms: {
                        tPositions: { type: "t", value: null }
                    },
                    vertexShader: vertex_shader,
                    fragmentShader: fragment_shader,
                    blending: THREE.NoBlending,
                    depthTest: false,
                    depthWrite: false,
                    side: THREE.DoubleSide
            });

            var plane = new THREE.PlaneGeometry(textureWidth, textureHeight);
            var quad = new THREE.Mesh(plane, material);
            quad.position.z = 0;
            var scene = new THREE.Scene();
            scene.add(camera);
            scene.add(quad);

            this.textureWidth = textureWidth;
            this.textureHeight = textureHeight;
            this.scene = scene;
            this.camera = camera;
            this.renderer = renderer;
            this.material = material;
        }

        UtilityFuncs.prototype.createRenderTarget = function(width, height) {
            var rtTexture = new THREE.WebGLRenderTarget(width, height,
                                            {
                                                wrapS:THREE.RepeatWrapping,
                                                wrapT:THREE.RepeatWrapping,
                                                minFilter: THREE.NearestFilter,
                                                magFilter: THREE.NearestFilter,
                                                format: THREE.RGBAFormat,
                                                type:THREE.FloatType,
                                                // renderbuffer defaults to RGB4
                                                // if stencil & depth false! 
                                                // three.js, setupRenderBuffer::24848 
                                                stencilBuffer: false,
                                                depthBuffer: true
                                            });
            rtTexture.generateMipmaps = false;
            return rtTexture;
        }

        UtilityFuncs.prototype.createFloatTextureFromData = function(width, height, data) {
            var texture = new THREE.DataTexture(
                data,
                width,
                height,
                THREE.RGBAFormat,
                THREE.FloatType,
                null,
                THREE.RepeatWrapping,
                THREE.RepeatWrapping,
                THREE.NearestFilter,
                THREE.NearestFilter
            );

            texture.generateMipmaps = false;
            texture.needsUpdate = true;

            return texture;
        };

        UtilityFuncs.prototype.readFramebuffer = function(renderer, framebuffer, width, height) {
                var gl = renderer.getContext();
                gl.flush();
                if (framebuffer != null)
                    gl.bindFramebuffer( gl.FRAMEBUFFER, framebuffer );
                var rdData = new Uint8Array(width*height*4);
                gl.readPixels( 0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, rdData );
                return rdData;
        }

        UtilityFuncs.prototype.readFloatFramebuffer = function(renderer, framebuffer, width, height) {
                var gl = renderer.getContext();
                gl.flush();
                if (framebuffer != null)
                    gl.bindFramebuffer( gl.FRAMEBUFFER, framebuffer );
                var rdData = new Float32Array(width*height*4);
                gl.readPixels( 0, 0, width, height, gl.RGBA, gl.FLOAT, rdData );
                return rdData;
        }

        UtilityFuncs.prototype.renderToTexture = function(texture, renderToTexture) {
            this.material.uniforms.tPositions.value = texture;
            this.renderer.render(this.scene, this.camera, renderToTexture, false);
        };

        UtilityFuncs.prototype.render = function(texture) {
            this.material.uniforms.tPositions.value = texture;
            this.renderer.render(this.scene, this.camera);
        };

        //
        // start of main routines
        //
        var WIDTH = window.innerWidth,
            HEIGHT = window.innerHeight;
        var texWidth = 4,
            texHeight = 4;
        var container, renderer;
        var start = Date.now();
        var rtTexture, rtTexture2;
        var utilities;
        var rdData, rdData2, ardData, ardData2;

        function launch() {

            container = document.getElementById("container");
            renderer = new THREE.WebGLRenderer({antialias:true});
            renderer.setSize(WIDTH, HEIGHT);
            container.appendChild(renderer.domElement);

            utilities = new UtilityFuncs();

            utilities.createScene( texWidth, texHeight, renderer );

            rtTexture = utilities.createRenderTarget(texWidth, texHeight);
            rtTexture2 = utilities.createRenderTarget(texWidth, texHeight);


            // Create constant color test textures
            var mData = new Float32Array(texWidth*texHeight*4);
            for (var i = 0; i < 8; i++) {
                    mData[4*i] = 1.0; mData[4*i+1] = 0.0; mData[4*i+2] = 1.0; mData[4*i+3] = 1.0;
            }
            magentaTexture = utilities.createFloatTextureFromData(texWidth, texHeight, mData)

            // Create constant color test textures
            var cData = new Float32Array(texWidth*texHeight*4);
            for (var i = 0; i < 8; i++) {
                    cData[4*i] = 0.0; cData[4*i+1] = 1.0; cData[4*i+2] = 1.0; cData[4*i+3] = 1.0;
            }
            cyanTexture = utilities.createFloatTextureFromData(texWidth, texHeight, cData)

            utilities.renderToTexture(cyanTexture, rtTexture);
            rdData = utilities.readFramebuffer(renderer, rtTexture.__webglFramebuffer,
                                               texWidth, texHeight);

            utilities.renderToTexture(magentaTexture, rtTexture2);
            rdData2 = utilities.readFramebuffer(renderer, rtTexture2.__webglFramebuffer,
                                                texWidth, texHeight);

            if (rdData[0] != 0 || rdData[1] != 255 || rdData[2] != 255 || rdData[3] != 255)
                console.log("rtTexture load fail\n");

            if (rdData2[0] != 255 || rdData2[1] != 0 || rdData2[2] != 255 || rdData2[3] != 255)
                console.log("rtTexture2 load fail\n");

            animate();
        }

        var timer = 0;

        function animate() {
            requestAnimationFrame( animate );
            render();
        }

        function render() {
            //
            // copy rtTexture and rtTexture2 between each other
            //

            utilities.renderToTexture(rtTexture, rtTexture2);
            ardData2 = utilities.readFramebuffer(renderer, rtTexture2.__webglFramebuffer,
                                                 texWidth, texHeight);

            utilities.renderToTexture(rtTexture2, rtTexture);
            ardData = utilities.readFramebuffer(renderer, rtTexture.__webglFramebuffer,
                                                   texWidth, texHeight);

            if (timer & 1)
                utilities.render(rtTexture2);
            else
                utilities.render(rtTexture);

            if (ardData[0] != 0 || ardData[1] != 255 || ardData[2] != 255 || ardData[3] != 255)
                console.log("rtTexture fail\n");
            if (ardData2[0] != 0 || ardData2[1] != 255 || ardData2[2] != 255 || ardData2[3] != 255)
                console.log("rtTexture2 fail\n");
            timer++;
        }

        //launch();

        </script>
        <button id="renderButton" onClick="launch()">Render</button>
        <br/>
    </body>
</html>

1 个答案:

答案 0 :(得分:0)

如果您更改填充纹理的for循环,闪烁将停止:

for (var i = 0; i < 8; i++) ==>> for (var i = 0; i < texWidth*texHeight*4; i++)

但我在chrome和firefox上都一直“rtTexture2失败”。

我发现了另一个错误。线;

if (ardData2[0] != 0 || ardData2[1] != 255 || ardData2[2] != 255 || ardData2[3] != 255)

应该是:

if (ardData2[0] != 255 || ardData2[1] != 0 || ardData2[2] != 255 || ardData2[3] != 255)

但我仍然无法摆脱上述错误。