【问题标题】:Rendering sprites on a Mali-400 MP device在 Mali-400 MP 设备上渲染精灵
【发布时间】:2016-01-04 21:31:29
【问题描述】:

我开始使用 OpenGL 开发一个小型跨平台游戏引擎,实际上我正在开发一个精灵批处理渲染器。
在 OS X、iOS、Win32 和一些 Android 设备上一切正常。这是结果:


左图显示了正确的结果,并在三星 Galaxy S1、Galaxy J5、Galaxy S3、Galaxy Tab 3 上进行了测试。 在右侧给出这些奇怪结果的设备是带有 Mali-400 MP 渲染器的三星 Galaxy Core 2。
当我使用多个纹理时,我开始得到奇怪的结果。

这是我的 Sprite Batch 类:

Glyph::Glyph(const maths::vec2 &position, const maths::vec2 &dimensions, const maths::vec4 &uvRect, GLuint texture, unsigned int color, float zOrder) :
textureID(texture) {

    a_zOrder = zOrder;

    topLeft.m_color = color;
    topLeft.setPosition(position.x, position.y + dimensions.y);
    topLeft.setUV(uvRect.x, uvRect.y + uvRect.w);

    bottomLeft.m_color = color;
    bottomLeft.setPosition(position.x, position.y);
    bottomLeft.setUV(uvRect.x, uvRect.y);

    bottomRight.m_color = color;
    bottomRight.setPosition(position.x + dimensions.x, position.y);
    bottomRight.setUV(uvRect.x + uvRect.z, uvRect.y);

    topRight.m_color = color;
    topRight.setPosition(position.x + dimensions.x, position.y + dimensions.y);
    topRight.setUV(uvRect.x + uvRect.z, uvRect.y + uvRect.w);
}


//SpriteBatch
ORendererSpriteBatch::ORendererSpriteBatch(): m_vboID(0), m_vaoID(0)
{
    Init();
}

ORendererSpriteBatch::~ORendererSpriteBatch()
{
    if (m_vboID != 0) {
        glDeleteBuffers(1, &m_vboID);
    }

    if (m_vaoID != 0) {
        glDeleteVertexArrays(1, &m_vaoID);
    }
}

void ORendererSpriteBatch::Init()
{
    createVertexArray();
}

void ORendererSpriteBatch::Begin()
{
    m_renderBatches.clear();

    // Makes _glpyhs.size() == 0, however it does not free internal memory.
    // So when we later call emplace_back it doesn't need to internally call new.
    m_glyphs.clear();
}

void ORendererSpriteBatch::Submit(const OSprite* renderable)
{
    m_glyphs.emplace_back(renderable->GetPosition(), renderable->GetSize(), renderable->GetUV(), renderable->GetTID(), renderable->GetColor(), renderable->GetZOrder());
}

void ORendererSpriteBatch::End()
{
    // Set up all pointers for fast sorting
    m_glyphPointers.resize(m_glyphs.size());
    for (size_t i = 0; i < m_glyphs.size(); i++) {
        m_glyphPointers[i] = &m_glyphs[i];
    }

    sortGlyphs();
    createRenderBatches();
}

void ORendererSpriteBatch::Flush(OLayer2D *layer)
{
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

    ORendererFactory::OShader_Simple2D->bind();
    glActiveTexture(GL_TEXTURE0);
    ORendererFactory::OShader_Simple2D->setUniform1i("u_diffuse", 0);
    ORendererFactory::OShader_Simple2D->setUniformMat4("u_MVP", layer->getCamera()->getCameraMatrix());
    glBindVertexArray(m_vaoID);

    for (size_t i = 0; i < m_renderBatches.size(); i++) {
        glBindTexture(GL_TEXTURE_2D, m_renderBatches[i].texture);

        glDrawArrays(GL_TRIANGLES, m_renderBatches[i].offset, m_renderBatches[i].numVertices);
    }

    ORendererFactory::OShader_Simple2D->unbind();
    glBindVertexArray(0);
}


void ORendererSpriteBatch::createRenderBatches() {
    // This will store all the vertices that we need to upload
    std::vector <VertexData2D> vertices;
    // Resize the buffer to the exact size we need so we can treat
    // it like an array
    vertices.resize(m_glyphPointers.size() * 6);

    if (m_glyphPointers.empty()) {
        return;
    }

    int offset = 0; // current offset
    int cv = 0; // current vertex

    //Add the first batch
    m_renderBatches.emplace_back(offset, 6, m_glyphPointers[0]->textureID);
    vertices[cv++] = m_glyphPointers[0]->topLeft;
    vertices[cv++] = m_glyphPointers[0]->bottomLeft;
    vertices[cv++] = m_glyphPointers[0]->bottomRight;
    vertices[cv++] = m_glyphPointers[0]->bottomRight;
    vertices[cv++] = m_glyphPointers[0]->topRight;
    vertices[cv++] = m_glyphPointers[0]->topLeft;
    offset += 6;

    //Add all the rest of the glyphs
    for (size_t cg = 1; cg < m_glyphPointers.size(); cg++) {

        // Check if this glyph can be part of the current batch
        if (m_glyphPointers[cg]->textureID != m_glyphPointers[cg - 1]->textureID) {
            // Make a new batch
            m_renderBatches.emplace_back(offset, 6, m_glyphPointers[cg]->textureID);
        } else {
            // If its part of the current batch, just increase numVertices
            m_renderBatches.back().numVertices += 6;
        }
        vertices[cv++] = m_glyphPointers[cg]->topLeft;
        vertices[cv++] = m_glyphPointers[cg]->bottomLeft;
        vertices[cv++] = m_glyphPointers[cg]->bottomRight;
        vertices[cv++] = m_glyphPointers[cg]->bottomRight;
        vertices[cv++] = m_glyphPointers[cg]->topRight;
        vertices[cv++] = m_glyphPointers[cg]->topLeft;
        offset += 6;
    }

    glBindVertexArray(m_vaoID);

    // Bind our VBO
    glBindBuffer(GL_ARRAY_BUFFER, m_vboID);
    // Orphan the buffer (for speed)
    glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(VertexData2D), NULL, GL_DYNAMIC_DRAW);
    // Upload the data
    glBufferSubData(GL_ARRAY_BUFFER, 0, vertices.size() * sizeof(VertexData2D), vertices.data());

    glBindVertexArray(0);
    // Unbind the VBO
    //        glBindBuffer(GL_ARRAY_BUFFER, 0);

}

void ORendererSpriteBatch::createVertexArray() {

    // Generate the VAO if it isn't already generated
    if (m_vaoID == 0) {
        glGenVertexArrays(1, &m_vaoID);
    }

    // Bind the VAO. All subsequent opengl calls will modify it's state.
    glBindVertexArray(m_vaoID);

    //G enerate the VBO if it isn't already generated
    if (m_vboID == 0) {
        glGenBuffers(1, &m_vboID);
    }
    glBindBuffer(GL_ARRAY_BUFFER, m_vboID);

    //Tell opengl what attribute arrays we need
    glEnableVertexAttribArray(0);
    glEnableVertexAttribArray(1);
    glEnableVertexAttribArray(2);

    glVertexAttribPointer(0, 2, GL_FLOAT,         GL_FALSE, sizeof(VertexData2D), (void *)offsetof(VertexData2D, m_vertex));
    glVertexAttribPointer(1, 4, GL_UNSIGNED_BYTE, GL_TRUE , sizeof(VertexData2D), (void *)offsetof(VertexData2D, m_color));
    glVertexAttribPointer(2, 2, GL_FLOAT        , GL_FALSE, sizeof(VertexData2D), (void *)offsetof(VertexData2D, m_uv));

    glBindVertexArray(0);

}

void ORendererSpriteBatch::sortGlyphs() {

    std::stable_sort(m_glyphPointers.begin(), m_glyphPointers.end(), compareFunction);

}

bool ORendererSpriteBatch::compareFunction(Glyph* a, Glyph* b) {
    if (a->a_zOrder == b->a_zOrder) {
        return (a->textureID < b->textureID);
    }
    return (a->a_zOrder < b->a_zOrder);
}


这就是我如何称呼该类:

    m_CurrentRenderer->Begin();

    for (const OSprite* renderable : m_Renderables)
        if(m_Camera->isBoxInView(renderable->GetPosition(), renderable->GetSize())){
            renderable->Submit(m_CurrentRenderer);
        }

    m_CurrentRenderer->End();
    m_CurrentRenderer->Flush(this);

欢迎就可能导致该错误的原因提出任何建议。

【问题讨论】:

    标签: android opengl-es 2d


    【解决方案1】:

    您的代码:

    glVertexAttribPointer(0, 2, GL_FLOAT,         GL_FALSE, sizeof(VertexData2D), (void *)offsetof(VertexData2D, m_vertex));
    glVertexAttribPointer(1, 4, GL_UNSIGNED_BYTE, GL_TRUE , sizeof(VertexData2D), (void *)offsetof(VertexData2D, m_color));
    glVertexAttribPointer(2, 2, GL_FLOAT        , GL_FALSE, sizeof(VertexData2D), (void *)offsetof(VertexData2D, m_uv));
    

    假设顶点位置是属性#0,颜色是属性#1,uv是属性#2。

    您是否以任何方式强制执行?在顶点着色器中以该顺序声明属性并不能保证属性将采用该顺序。

    您可以在链接程序之前使用 glBindAttribLocation 指定属性位置,也可以使用 glGetAttribLocation 来查询位置。

    【讨论】:

    • 是的,我已经使用 glBindAttribLocation 强制执行了。否则这在任何 OpenGL ES 设备上都不起作用。正如我所提到的,它可以在大多数设备上运行,除了那个,如果我所有的精灵都使用相同的纹理,那么精灵批处理就可以了。但是当我使用多个纹理时,它会给我这些奇怪的结果
    • 啊哈——所以它只有在 glDrawArrays 中有偏移时才会发生——这可能是一个驱动程序错误。我在一台装有 Mali-400(Tesco Hudl)的设备上出现了一个奇怪的故障,我相信这与这里描述的相同:community.arm.com/message/19003。令人讨厌的是,ARM 没有在其 GL_VERSION 字符串中包含内部版本号的习惯,因此要确定您是否可能受到影响并不容易。最后我没有找到解决方法,因为故障在我的应用程序中是短暂的。如果您能够更新该设备上的驱动程序,那么这可能值得一试。
    • 所以没有解决方法来解决这个问题?除了更新驱动?
    • 可能有一个解决方法,但我没有费心去尝试,因为对我来说,故障只持续了大约一秒钟,然后渲染恢复正常,所以我决定我可以忍受它。无法保证我看到的问题与链接中的问题或您的问题有关。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-08
    • 2019-06-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多