0

嘿嘿,

我正在用 OpenGL ES 2.0 为 Android 创建简单的游戏。游戏将包含几种不同的精灵,但这些精灵会不止一次出现。

现在假设我有 1 个对象(精灵)。到目前为止,我已经实现了 VBO 和索引缓冲,因此据我所知,整个对象都存储在 GPU 上。

我现在想做的是多次绘制这个对象,只是它的位置不同。就目前而言,这是按如下方式实现的:

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer.getBufferId());
for(int i=0; i<1000; i++){
    multiplyMM(MVP, 0, viewMatrix, 0, tempGetRandomMVPMatrix(), 0);
    glUniformMatrix4fv(uMatrixLocation, 1, false, MVP, 0);//TODO


    if(androidVersion > Build.VERSION_CODES.FROYO)
        glDrawElements(GL_TRIANGLES, indexArray.length, GL_UNSIGNED_SHORT, 0);
    else{
        if(repairedGL20 == null){
            repairedGL20 = new AndroidGL20();
        }
        repairedGL20.glDrawElements(GL_TRIANGLES, indexArray.length, GL_UNSIGNED_SHORT, 0);
    }

}

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);

如果我理解正确,主要问题是调用 glDrawElements ,每次更改 MVP 矩阵时都会调用它。有什么方法可以将所有 MVP 矩阵发送到 GPU 并在那里多次绘制一个元素,而只需调用 1 次 glDrawElements?

有关对象的更多信息。它有大约 24 个顶点和 64x64 纹理。目前有 1k 个对象,我有 35FPS,我想获得更高的 fps,因为我将绘制更多的精灵。

这是我的着色器: 顶点:

    uniform mat4 u_Matrix;

attribute vec4 a_Position;
attribute vec2 a_TextureCoordinates;

varying vec2 v_TextureCoordinates;

void main(){
    v_TextureCoordinates = a_TextureCoordinates;
    gl_Position = u_Matrix * a_Position;
}

分段:

precision mediump float;

uniform sampler2D u_TextureUnit;//actual texture data
varying vec2 v_TextureCoordinates;

void main(){
    gl_FragColor = texture2D(u_TextureUnit, v_TextureCoordinates);
}

还有一件事我不太了解纹理。如果我创建这样的纹理:

glBindTexture(GL_TEXTURE_2D, textureObjectIds[0]);//binds texture to texture object

        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);//minimization filter
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

        texImage2D(GL_TEXTURE_2D, 0, bitmap, 0);//send texture data to OpenGL to the CURRENTLY BOUND object

当我将使用此纹理绘制对象时,纹理保存在哪里,在 CPU 的内存或 GPU 上?此外,在上面的示例中,我正在绘制相同的精灵,每次绘制调用是否都会将纹理发送到 GPU?如果是这样,有没有办法优化它(类似于 VBO)?

4

1 回答 1

3

例如,假设我有 1 个带有 2 个顶点的对象,我想用 MVP 将其转换为 2 个位置。如何使“gl_Position”同时在 2 个不同的地方绘制?

那是永远做不到的。我在最初的评论中指的是一个顶点缓冲区,每个精灵都包含 N 多个(可能是 4 个)顶点......如果除了顶点缓冲区中的位置之外,您还包括一个额外的字段,您可以转换在着色器中使用不同矩阵的顶点。您将始终必须为每个对象定义 N 个顶点,但您可以使用静态顶点缓冲区来执行此操作,我将在下面解释。

假设您有一个由点定义的精灵(在转换之前):

   Position
   <0.0,0.0>
   <1.0,0.0>
   <1.0,1.0>
   <0.0,1.0>

如果您的模型视图矩阵包含缩放信息,那么您可以一遍又一遍地使用相同的点集。

现在,如果你想扩展它以在一次调用中绘制 3 个精灵,你可以这样做:

  Position  Idx
  <0.0,0.0> [0]
  <1.0,0.0> [0]
  <1.0,1.0> [0]
  <0.0,1.0> [0]

  <0.0,0.0> [1]
  <1.0,0.0> [1]
  <1.0,1.0> [1]
  <0.0,1.0> [1]

  <0.0,0.0> [2]
  <1.0,0.0> [2]
  <1.0,1.0> [2]
  <0.0,1.0> [2]

基本上我在顶点缓冲区中添加了一个新字段,它标识了每组 4 个点所属的精灵;使用 aGLubyte以获得最佳性能。您会注意到同一组点一遍又一遍地重复。以这种方式实现实例化有效地将存储需求增加到O (N*V + 4N),其中 V 是 4 个点的原始顶点数据结构的大小,N 是精灵的数量。

您可以定义一个顶点缓冲区,其中包含足够 16 个精灵的点,然后当您想在一次调用中绘制多个精灵时,您将始终使用相同的顶点缓冲区并使用总点数的子集. 要使用此顶点缓冲区绘制 4 个精灵,只需从它总共包含的 64 个点中绘制前 16 个。

现在,这只是过程的一半。您还需要设置您的顶点着色器以获取定义每个精灵的转换的模型视图矩阵制服数组。

这是一个可用于执行此操作的示例顶点着色器:

#version 100

uniform mat4    proj_mat;
uniform mat4    instanced_mv [16];

attribute vec4  vtx_pos;
attribute vec2  vtx_st;
attribute float vtx_sprite_idx; // This would be a uint in desktop GLSL

varying   vec2  tex_st;

void main (void) {
  gl_Position = proj_mat * instanced_mv [(int)vtx_sprite_idx] * vtx_pos;
  tex_st      = vtx_st;
}

这里有几点需要注意:

  1. GLES 2.0 不支持整数顶点属性,所以索引必须是浮点数

    • 索引统一数组必须使用顶点着色器中的整数表达式来完成,因此需要强制转换。

  2. 模型视图制服的数量实际上是您一次可以实例化多少个精灵的限制因素

    • 顶点着色器只需要支持 128 个 4 分量统一变量(mat4算作 4 个 4 分量统一变量),因此这意味着如果您的顶点着色器只有模型视图统一变量,您最多可以支持 32 个 (128/4) 的数组。

  3. 将精灵索引作为 a 存储GLubyte在顶点缓冲区中,但请确保在设置顶点属性时启用浮点规范化。指针。

最后,此着色器尚未经过测试。如果您在此处无法理解任何内容或遇到实施此问题的问题,请随时发表评论。

于 2013-10-21T17:24:26.763 回答