优化帮助:使用程序调用每一帧和低FPS



我正在试验一个深受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 上更改要快得多。

希望这有帮助,祝你好运!

最新更新