如何减少大量纹理的绘图调用次数?

Wil*_*iam 5 c++ opengl

我正在尝试为基于2D平铺的游戏开发地图,我正在使用的方法是将地图图像保存在大纹理(平铺集)中,并通过顶点着色器更新位置,在屏幕上仅绘制所需的平铺然而,在10x10地图上涉及100个glDrawArrays调用,通过任务管理器查看,这消耗了5%的CPU使用率和4%~5%的GPU,想象一下如果它是一个包含数十个调用的完整游戏,有一种方法可以优化这样,比如准备整个场景,只做一次平局,一次全部绘制,或者其他一些方法?

void GameMap::draw() {
  m_shader - > use();
  m_texture - > bind();

  glBindVertexArray(m_quadVAO);

  for (size_t r = 0; r < 10; r++) {
    for (size_t c = 0; c < 10; c++) {
      m_tileCoord - > setX(c * m_tileHeight);
      m_tileCoord - > setY(r * m_tileHeight);
      m_tileCoord - > convert2DToIso();

      drawTile(0);
    }
  }

  glBindVertexArray(0);
}

void GameMap::drawTile(GLint index) {
  glm::mat4 position_coord = glm::mat4(1.0 f);
  glm::mat4 texture_coord = glm::mat4(1.0 f);

  m_srcX = index * m_tileWidth;

  GLfloat clipX = m_srcX / m_texture - > m_width;
  GLfloat clipY = m_srcY / m_texture - > m_height;

  texture_coord = glm::translate(texture_coord, glm::vec3(glm::vec2(clipX, clipY), 0.0 f));
  position_coord = glm::translate(position_coord, glm::vec3(glm::vec2(m_tileCoord - > getX(), m_tileCoord - > getY()), 0.0 f));
  position_coord = glm::scale(position_coord, glm::vec3(glm::vec2(m_tileWidth, m_tileHeight), 1.0 f));

  m_shader - > setMatrix4("texture_coord", texture_coord);
  m_shader - > setMatrix4("position_coord", position_coord);

  glDrawArrays(GL_TRIANGLES, 0, 6);
}

--Vertex Shader

#version 330 core
layout (location = 0) in vec4 vertex; // <vec2 position, vec2 texCoords>

out vec4 TexCoords;

uniform mat4 texture_coord;
uniform mat4 position_coord;
uniform mat4 projection;

void main()
{
    TexCoords =    texture_coord * vec4(vertex.z, vertex.w, 1.0, 1.0);
    gl_Position =   projection * position_coord * vec4(vertex.xy, 0.0, 1.0);
}

-- Fragment Shader
#version 330 core
out vec4 FragColor;

in vec4 TexCoords;

uniform sampler2D image;
uniform vec4 spriteColor;

void main()
{
    FragColor = vec4(spriteColor) * texture(image, vec2(TexCoords.x, TexCoords.y));
}
Run Code Online (Sandbox Code Playgroud)

Fre*_*yck 2

您可以将所有参数上传到 GPU 内存,并仅使用一次绘制调用来绘制所有内容。这样就不需要更新顶点着色器制服,并且 CPU 负载应该为零。

我已经使用 OpenGL 3 年了,所以我只能为您指明正确的方向。开始阅读一些材料,例如:

https://ferransole.wordpress.com/2014/07/09/multidrawindirect/

https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glDrawArraysIndirect.xhtml

另外,请记住这是 GL 4.x 的东西,检查您的目标平台(软件+硬件)GL 版本支持。