我目前正在编写我的第一个Three.js / WebGL应用程序,它在我的PC(Chrome)上运行得非常好。可悲的是,在许多其他PC上,帧速率通常会低于每秒30帧。
由于应用程序实际上并不复杂,我想询问一些与应用程序相关的提示,以提高性能。 该应用程序的一个版本可以在这里找到:
www.wrodewald.de/StackOverflowExample /
应用程序包含一个使用64²顶点的动态(变形)平面。矩阵用于存储静态高度图和波形图。每个帧都会更新波形图以重新计算自身,一些滤波器用于与其顶点相比“均匀”每个顶点。 因此,必须更新平面的每个帧(颜色和顶点位置),这可能是性能问题的原因
第二个对象(菱形)不应该是一个问题,静止,移动一点但没什么特别的。
有三种灯光(环境光,方向光,球面光),无阴影,倾斜移位着色器和晕影着色器。
以下是每帧调用的函数:
var render = function() {
requestAnimationFrame( render );
var time = clock.getDelta();
world.updateWorld(time);
diamond.rotate(time);
diamond.update(time);
control.updateCamera(camera, time);
composer.render();
stats.update();
}
这是world.updateWorld(time)
做的
//in world.updateWorld(time) where
// accmap: stores acceleration and wavemap stores position
// this.mapSize stores the size of the plane in vertices (64)
// UPDATE ACCELERATION MAP
for(var iX = 1; iX < (this.mapSize-1); iX++) {
for(var iY = 1; iY < (this.mapSize-1); iY++) {
accmap[iX][iY] -= dT * (wavemap[iX][iY]) * Math.abs(wavemap[iX][iY]);
}
}
// SMOOTH ACCELERATION MAP
for(var iX = 1; iX < (this.mapSize-1); iX++) {
for(var iY = 1; iY < (this.mapSize-1); iY++) {
tempmap[iX][iY] = accmap[iX-1][iY-1] * 0.0625
+ accmap[iX-1][iY ] * 0.125
+ accmap[iX-1][iY+1] * 0.0625
+ accmap[iX ][iY-1] * 0.125
+ accmap[iX ][iY ] * 0.25
+ accmap[iX ][iY+1] * 0.125
+ accmap[iX+1][iY-1] * 0.0625
+ accmap[iX+1][iY ] * 0.125
+ accmap[iX+1][iY+1] * 0.0625;
accmap[iX][iY] = tempmap[iX][iY];
}
}
// UPDATE WAVE MAP
for(var iX = 1; iX < (this.mapSize-1); iX++) {
for(var iY = 1; iY < (this.mapSize-1); iY++) {
wavemap[iX][iY] += dT * accmap[iX][iY];
}
}
for(var i = 0; i < this.mapSize; i++) {
for(var k = 0; k < this.mapSize; k++) {
geometry.vertices[ i * this.mapSize + k ].y = wavemap[i][k] + heightmap[i][k];
}
}
for(var i = 0; i < geometry.faces.length; i++) {
var vertexA = geometry.vertices[geometry.faces[i].a];
var vertexB = geometry.vertices[geometry.faces[i].b];
var vertexC = geometry.vertices[geometry.faces[i].c];
var val = (vertexA.y + vertexB.y + vertexC.y) / 3.0;
val = (val / 200.) + 0.5;
geometry.faces[i].color.r = val;
geometry.faces[i].color.g = val;
geometry.faces[i].color.b = val;
}
geometry.colorsNeedUpdate = true;
geometry.verticesNeedUpdate = true;
这些是“钻石”功能
this.rotate = function(dT) {
counter += 0.5 * dT;
counter % 1;
var x = 0.0025 * (Math.sin((counter) * 2 * Math.PI));
var y = 0.0025 * (Math.cos((counter) * 2 * Math.PI));
this.mesh.rotateOnAxis(new THREE.Vector3(1,0,0), x);
this.mesh.rotateOnAxis(new THREE.Vector3(0,0,1), y);
}
this.update = function(dT) {
for(var i = 0; i < geometry.faces.length; i++) {
geometry.faces[i].color.lerp(color, dT*(0.9));
}
geometry.colorsNeedUpdate = true;
}
您是否发现帧率如此不一致的任何原因?
答案 0 :(得分:5)
修改强>
我发现了你需要改进的两件大事:
使用GPU更新平面
加速:高
让我们从plane.js中选择您的代码
timer += dT;
if(timer > 0.1) {
var x = 2 + Math.floor(Math.random() * (this.mapSize - 4));
var y = 2 + Math.floor(Math.random() * (this.mapSize - 4));
//accmap[x][y] += 30000 * Math.random () - 15000
}
// UPDATE ACCELERATION MAP
for(var iX = 1; iX < (this.mapSize-1); iX++) {
for(var iY = 1; iY < (this.mapSize-1); iY++) {
accmap[iX][iY] -= dT * (wavemap[iX][iY]) * Math.abs(wavemap[iX][iY]);
}
}
所以你有4096个顶点,你想用CPU每17毫秒更新一次。请注意,您没有使用任何GPU优势。应该怎么做:
每次渲染都会在顶点着色器中完成此操作:
"gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",
来自你的cg / shaders / VerticalTiltShiftShader.js
如果要旋转平面,则不要将每个顶点相乘,但只需将模型矩阵乘以一次(js与THREE.js函数):
projectionMatrix.makeRotationY(dT);
然后每个顶点在顶点着色器中与此矩阵相乘,这样更快。
Javascript风格
加速:无 - 中等,但它可以让您更快地编码
让我们以你的plane.js为例。
// this is your interface
function PlaneWorld () {
this.init = function() {};
this.updateVertices = function() {};
this.updateWorld = function(dT) {};
// ... and more
}
// and somewhere else:
var world = new PlaneWorld();
如果您的项目中只有一个平面,您可以将其视为单例并且实现正常。但是,如果要创建2个或更多平面,则会为每个实例(new PlaneWorld()
)重新创建所有函数。正确的方法是:
function PlaneWorld () {
...
}
PlaneWorld.prototype.init = function() {};
PlaneWorld.prototype.updateVertices = function() {};
PlaneWorld.prototype.updateWorld = function(dT) {};
// ... and more
var world = new PlaneWorld();
// calling methods works same
world.updateVertices();
或更复杂的匿名函数版本:
var PlaneWorld = (function() {
// something like private static variables here
var PlaneWorld = function () {
...
}
PlaneWorld.prototype = {
init: function() {},
updateVertices: function() {},
updateWorld: function(dT) {}
// ... and more
}
return PlaneWorld();
})();
var world = new PlaneWorld();
// calling methods works same
world.updateVertices();
然后降低新实例成本。现在可能连接的东西,每个实例应共享相同的网格,但有自己的modelViewMatrix。