在Mali-400 MP设备上渲染精灵

时间:2016-01-04 21:31:30

标签: android opengl-es 2d

我开始使用OpenGL开发一个小型跨平台游戏引擎,我正在使用sprite批量渲染器。
在OS X,iOS,Win32和一些Android设备上一切正常。结果如下:

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

这是我的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);

欢迎任何关于可能导致该错误的建议。

1 个答案:

答案 0 :(得分:0)

您的代码:

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来查询位置。