I am new to three.js and think this is great. I'm trying to better keep moving texture data in a shader, so I can mainly use the GPU. I base my program on the example of Mr. Oak magic, but I do not use particles, not loaded models, stored in the texture. I am currently having a problem when I flicker. The code below is an approximate example of flickering and has some affinity for what I'm doing. If anyone could help me understand what I am doing wrong or where the flicker occurs ... I am pretty sure that everything is updated, both in texture mapping and in the three.js edition. Thank you very much
<!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>