【问题标题】:Spritebatch only drawing first spriteSpritebatch 只绘制第一个精灵
【发布时间】:2014-12-28 22:38:18
【问题描述】:

我已经实现了一个 OpenGL spritebatch,但是当对多个精灵使用相同的纹理时,它只会绘制第一个精灵。例如:如果我用它来渲染字符串“Hello”的字形,它只会渲染“H”。

我的着色器非常简单:

片段:

#version 150 core

uniform sampler2D tex;

in vec2 Texcoord;
out vec4 outColor;

void main()
{
    outColor = texture(tex, Texcoord); 
}

顶点:

#version 150 core

in vec3 position;
in vec2 texCoords;
out vec2 Texcoord;

void main()
{
    Texcoord = texCoords;
    gl_Position = vec4(position, 1.0f);
}

他们编译、链接和验证没有任何错误。

我的精灵批处理代码也很简单。下面是我初始化 Sprite Batch 的方法:

glGenVertexArrays(1, &mVao);
glBindVertexArray(mVao);

    // INDEX BUFFER
glGenBuffers(1, &mEbo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mEbo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, 0, NULL, GL_STREAM_DRAW);

    // VERTEX BUFFER
glGenBuffers(1, &mVbo);
glBindBuffer(GL_ARRAY_BUFFER, mVbo);
glBufferData(GL_ARRAY_BUFFER, 0, NULL, GL_STREAM_DRAW);

    // POS ATTRIB
GLint posAttrib;
posAttrib = glGetAttribLocation(mShader.getProgram(), "position");
glEnableVertexAttribArray(posAttrib);
glVertexAttribPointer(posAttrib, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), 0);

    // TEX ATTRIB
GLint texAttrib;
texAttrib = glGetAttribLocation(mShader.getProgram(), "texCoords");
glEnableVertexAttribArray(texAttrib);
glVertexAttribPointer(texAttrib, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float)));

最后,我是这样画的:

glBindVertexArray(mVao);

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mEbo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(GLuint), &indices[0], GL_STREAM_DRAW);

glBindBuffer(GL_ARRAY_BUFFER, mVbo);
glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(Vertex), &vertices[0], GL_STREAM_DRAW);

glDrawElements(GL_TRIANGLES, (GLsizei)indices.size(), GL_UNSIGNED_INT, 0);

glBindVertexArray(0);

据我所知,OpenGL 不会抛出任何错误,verticesindices 包含正确的数据。

对于代码量,我很抱歉,但因为我没有收到任何错误,所以我不知道哪里出错了。当我调试代码时,我没有看到任何不合适或错误的值。

编辑

我用来设置顶点和索引向量的代码是这样的:

for(int i = 0; i < currentSprites.size(); ++i)
{
   Sprite* current = currentSprites.at(i);

    // 4 * (2 (pos) + 2 (tex))
    float verticesArray[16] =
    {
         // TOP LEFT
         current->x,
         current->y,
         (float)current->textureRect.x / (float)current->texture.w,
         (float)current->textureRect.y / (float)current->texture.h,
         // TOP RIGHT
         current->x + current->w,
         current->y,
         (float)(current->textureRect.x + current->textureRect.w) / (float)current->texture.w,
         (float)current->textureRect.y / (float)current->texture.h,
         // BOTTOM RIGHT
         current->x + current->w,
         current->y + current->h,
         (float)(current->textureRect.x + current->textureRect.w) / (float)current->texture.w,
         (float)(current->textureRect.y + current->textureRect.h) / (float)current->texture.h,
         // BOTTOM LEFT
         current->x,
         current->y + current->h,
         (float)current->textureRect.x / (float)current->texture.w,
         (float)(current->textureRect.y + current->textureRect.h) / (float)current->texture.h
    };

    for(int v = 0; v < 16; v += 4)
    {

        float zPos = -(float)current->layer / 100.0f;

        // Projection matrix
        glm::vec4 result = mCamera.getProjectionMatrix() * glm::vec4(verticesArray[v], verticesArray[v+1], zPos, 1.0f); // This is just an orthographic projection matrix
        verticesArray[v] = result.x;
        verticesArray[v+1] = result.y;
        zPos = result.z;

        vertices.push_back(Vertex(glm::vec3(verticesArray[v], verticesArray[v + 1], zPos),
                                  glm::vec2(verticesArray[v + 2], verticesArray[v + 3])));
    }

    static GLuint _indices[6] =
    {
    0, 1, 3, 3, 1, 2
    };

    for(int index = 0; index < 6; ++index)
    {
        indices.push_back(_indices[index]);
    }
}

【问题讨论】:

  • 到目前为止发布的代码看起来不错。我认为我们至少需要查看设置indicesvertices 数组的代码。
  • @derhass 我已经添加了该代码。我希望不要太多。第一部分只是设置顶点和纹理坐标,然后将顶点转换为OpenGL剪辑空间坐标系。

标签: c++ opengl sprite


【解决方案1】:

我认为问题在于您的索引缓冲区。您正在将所有字形的顶点批处理到同一个 VBO 中,并通过一次绘制调用来绘制它们(这是一种好方法)。但是,对于每个 glypgh,您要添加 same 6 个索引:

static GLuint _indices[6] =
{
0, 1, 3, 3, 1, 2
};
for(int index = 0; index < 6; ++index)
{
    indices.push_back(_indices[index]);
}

因此,实际上,您的代码将一遍又一遍地绘制第一个四边形,从不使用您之后添加的任何顶点。

您需要为正在绘制的每个字形偏移索引,例如:

for(int index = 0; index < 6; ++index)
{
    indices.push_back(_indices[index] + 4*i);
}

【讨论】:

  • 谢谢。只说一句:它应该是+4 * i,因为每个字形有 4 个顶点。这解决了它。
  • @RaptorDotCpp:是的,可能不好。你是绝对正确的。感谢您发现这一点,我修复了答案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-06-09
  • 2023-03-31
  • 2023-03-06
  • 1970-01-01
  • 2016-08-21
相关资源
最近更新 更多