我开始使用OpenGL开发一个小型跨平台游戏引擎,我正在使用sprite批量渲染器。
在OS X,iOS,Win32和一些Android设备上一切正常。结果如下:
左边的图像显示正确的结果,并在三星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);
欢迎任何关于可能导致该错误的建议。
答案 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来查询位置。