我正在试验一个深受Unity结构启发的基于组件的游戏引擎,我似乎以正确的方式做事,但我的帧速率非常低。
我的设置涉及一个具有自己的init()
和draw()
方法的 MeshRenderer 对象。
初始化
在init()
期间,我调用一个initMesh()
函数:
function initMesh(mesh) {
if(!mesh.vertices) {
mesh.vertices = new Float32Array([
0, 1,
0, 0,
1, 0,
1, 0,
1, 1,
0, 1
]);
}
if(!mesh.uvs) {
mesh.uvs = new Float32Array([
0, 1,
0, 0,
1, 0,
1, 0,
1, 1,
0, 1
]);
}
mesh.itemSize = 2;
mesh.numItems = mesh.vertices.length / mesh.itemSize;
mesh.vertexBuffer = gl.createBuffer();
mesh.uvBuffer = gl.createBuffer();
}
以及一个initMaterial()
函数:
function initMaterial(material, fs, vs) {
material.program = initShaders(fs, vs);
if(material.image) {
material.texture = gl.createTexture();
}
}
画
在draw()
方法中,我调用了一个setMeshBuffer()
函数:
function setMeshBuffer(mesh, material) {
// Vertex buffer
gl.bindBuffer(gl.ARRAY_BUFFER, mesh.vertexBuffer);
gl.bufferData(gl.ARRAY_BUFFER, mesh.vertices, gl.STATIC_DRAW);
gl.vertexAttribPointer(material.program.aVertexPosition, mesh.itemSize, gl.FLOAT, false, 0, 0);
if(material.texture) {
// UV buffer
gl.bindBuffer(gl.ARRAY_BUFFER, mesh.uvBuffer);
gl.bufferData(gl.ARRAY_BUFFER, mesh.uvs, gl.STATIC_DRAW);
gl.enableVertexAttribArray(material.program.aTexCoord);
gl.vertexAttribPointer(material.program.aTexCoord, mesh.itemSize, gl.FLOAT, false, 0, 0);
}
}
以及setMaterialBuffer()
函数:
function setMaterialBuffer(material) {
gl.useProgram(material.program);
gl.uniform4fv(material.program.uColor, [
material.color.r,
material.color.g,
material.color.b,
material.color.a
]);
if(material.texture) {
gl.bindTexture(gl.TEXTURE_2D, material.texture);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, material.image);
}
}
最后,我调用drawBuffers()
函数
function drawBuffers(numItems) {
gl.drawArrays(gl.TRIANGLES, 0, numItems);
}
问题
那么,我能做些什么来优化这个流程呢?我还没有能够找到像这样的模块化结构的综合指南。
我的项目在这里,如果你喜欢尝试一下,它是test.html
文件。
根据要求,我以扩展的答案形式发表评论:
您每帧都会上传新的顶点和纹理数据,基本上每次渲染时都会重新创建它。而是在初始化期间上传数据。 您可以通过将bufferData调用移动到initMesh()方法,并将texImage2D调用移动到initMaterial方法来实现此目的(当然,您必须首先绑定创建的对象)。一旦这些从绘制中消失,您将看到更好的性能。
关于您关于每帧更改UV坐标的评论,您有一些选项应该比您拥有的选项表现更好。
第一个选项是更新 CPU 上的数据(就像您现在所做的那样)。 UV 数据位于单独的缓冲区中是件好事 - 使 CPU 更新更快、缓存更连贯。 按照我的建议在 initMaterial 调用期间初始化数据,但将 usage 参数更改为 GL_DYNAMIC_DRAW 而不是 GL_STATIC_DRAW。 这是对驱动程序的提示,指示您计划经常更改数据。 然后,在setMeshBuffer中,使用gl.bufferSubData而不是gl.bufferData。 这允许您仅更新部分数据,但即使在上传全新数据时,它通常仍然要快得多。
第二种选择 - 我更喜欢 - 是保持UV静态。 与其在 CPU 上修改它们,不如在顶点程序中修改它们。 根据您更改 UV 的方式,这通常比在 CPU 上更改要快得多。
希望这有帮助,祝你好运!