我是新手,刚接触 three.js,感觉很好。我试图更好地掌握将纹理数据移动到着色器中的方法,以便大部分使用 GPU。我基于 Mr. Doob 的 magic dust 示例编写了程序,但我没有使用粒子,而是加载存储在纹理中的模型。目前我遇到了闪烁的问题。下面的代码是一个大致的闪烁示例,与我正在做的事情有些相似。如果有人能帮助我理解我做错了什么或闪烁来自哪里...我相信一切都是最新的,就像纹理映射和 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>