问题描述
我是three.js的新手,并且认为它很棒.我试图更好地控制将纹理数据移动到着色器,因此我主要可以使用GPU.我的程序基于Doob先生的魔术之尘示例,但我没有使用粒子,而是使用存储在纹理中的加载模型.我目前遇到一个闪烁的问题.下面的代码是闪烁的粗糙示例,与我在做的事情有些相似.如果有人可以帮助我了解我在做什么错或闪烁是从哪里来的……我很确定所有内容都是最新的,例如纹理映射和three.js版本.非常感谢
I'm new to three.js and think it's great. I'm trying to get a better hold on moving texture data to the shader so I can mostly use GPU. I base my program on Mr. Doob's magic dust example, but I'm not using particles rather loaded models stored in a texture. I'm having an issue currently where I get flickering. The code below is a rough example of the flickering and has some closeness to what I'm doing. If anyone could help me understand what I'm doing wrong or where the flickering is coming from ... I'm pretty sure everything is up-to-date, as in the texture mapping and three.js revision.Thanks a lot
<!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>
推荐答案
如果更改for循环,并在其中填充纹理,则闪烁将停止:
Well the flickering will stop if you change your for loop where you fill the textures from:
for (var i = 0; i < 8; i++) ==>> for (var i = 0; i < texWidth*texHeight*4; i++)
但是我在chrome和firefox上都一直遇到"rtTexture2失败"的情况.
but I keep getting "rtTexture2 fail" both on chrome and firefox.
我发现了另一个错误.行;
I spotted another error. Line;
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)
但是我仍然无法摆脱上面的错误.
but I still cannot get rid of the above error.
这篇关于Three.js着色器纹理闪烁的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!