Webgl 2D渲染图像太重

Webgl 2D rendering images too heavy

我刚刚开始使用 webgl。我在 youtube 上遵循了一个简单的初学者教程。现在,我正在尝试创建一个简单的 2D 游戏。

在那个游戏中,我想用图像渲染一个简单的物品栏。当我这样做时,我的 fps 在 10 秒后下降到 2。如果我删除库存呈现的代码,它会保持在 60。

我知道我的问题在 game/js/engine/inventory/inventory.js 中的第 82 行。在那里,我渲染了 35 张图像,其中包含我在观看教程时制作的精灵 class。我想是因为我看了一个简单的教程,其中渲染图像的代码没有优化,可能不是最好的方法。精灵 class 位于 game/js/engine/material.js:127。在精灵 class 中,我设置了可以解析到我的顶点和片段着色器的简单变量。

精灵设置

在设置方法中,我为图像设置了所有参数。

gl.useProgram(this.material.program);

this.gl_tex = gl.createTexture();

gl.bindTexture(gl.TEXTURE_2D, this.gl_tex);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.MIRRORED_REPEAT);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.MIRRORED_REPEAT);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, this.image);
gl.bindTexture(gl.TEXTURE_2D, null);

this.uv_x = this.size.x / this.image.width;
this.uv_y = this.size.y / this.image.height;

this.tex_buff = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, this.tex_buff);
gl.bufferData(gl.ARRAY_BUFFER, Sprite.createRenderRectArray(0, 0, this.uv_x, this.uv_y), gl.STATIC_DRAW);

this.geo_buff = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, this.geo_buff);
gl.bufferData(gl.ARRAY_BUFFER, Sprite.createRectArray(0, 0, this.size.x, this.size.y), gl.STATIC_DRAW);

gl.useProgram(null);

精灵渲染

在渲染方法中,我首先绑定纹理。然后,我为我的世界绑定一个 tex 坐标缓冲区、一个地理缓冲区和一些偏移量。最后,我绘制数组。

let frame_x = Math.floor(frames.x) * this.uv_x;
let frame_y = Math.floor(frames.y) * this.uv_y;

let oMat = new M3x3().transition(position.x, position.y);
gl.useProgram(this.material.program);

this.material.set("u_color", 1, 1, 1, 1);

gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, this.gl_tex);
this.material.set("u_image", 0);

gl.bindBuffer(gl.ARRAY_BUFFER, this.tex_buff);
this.material.set("a_texCoord");

gl.bindBuffer(gl.ARRAY_BUFFER, this.geo_buff);
this.material.set("a_position");

this.material.set("u_texeloffset", 0.5 / (this.image.width * scale.x), 0.5 / (this.image.height * scale.y));
this.material.set("u_frame", frame_x, frame_y);
this.material.set("u_world", worldSpaceMatrix.getFloatArray());
this.material.set("u_object", oMat.getFloatArray());

gl.drawArrays(gl.TRIANGLE_STRIP, 0, 6);
gl.useProgram(null);

Github: https://github.com/DJ1TJOO/2DGame/

有人知道我该如何 fixe/optimize 吗? 或者也许有更好的方法来呈现库存?

如果您找到任何其他方法来改进我的 webgl 或 javascript,请告诉我。

is a better way to render an inventory?

有几种优化方法。

  1. 仅使用 HTML 可能会更快

    说真的:您还可以获得简单的国际字体渲染、样式、 CSS 等的响应速度......很多游戏都这样做。

  2. 通常使用纹理图集(具有许多不同图像的单个纹理)速度更快,然后将顶点生成到库存所有部分的顶点缓冲区中。然后通过一次绘制调用绘制所有内容。例如 Dear ImGUI works to make all of these amazing GUIs 就是这样。它本身不绘制任何东西,它只是生成一个顶点缓冲区,其中包含纹理图集的位置和纹理坐标。

  3. 执行#2,除了不是每帧都生成整个顶点缓冲区,而是更新发生变化的部分。

    例如,假设您的库存显示

    [gold  ] 123
    [silver] 54
    [copper] 2394
    

    假设您总是画 [gold ][silver][copper],但只有数字会发生变化。您可以生成包含每个字母的所有位置的顶点缓冲区作为精灵,然后为每个值说出 6 个字符占位符。您只需要在数字发生变化时通过记住它们在顶点缓冲区中的位置来更新数字。对于您不想绘制的任何数字,您可以将其顶点移到屏幕外。

  4. 将库存绘制到纹理(或其中的一部分)中。然后在屏幕上绘制纹理。只更新纹理发生变化的部分。

    这基本上就是what the browser itself does。基于各种 CSS 设置,页面的各个部分被划分为纹理。当某些 HTML 或 CSS 发生变化时,仅重新渲染那些发生变化的纹理,然后绘制所有纹理以重新合成页面。