Как правильно использовать вызовы open gl с libGDX

Я пытаюсь визуализировать ландшафт, используя свой собственный шейдер и используя методы open gl низкого уровня. Но другие части игры используют SpriteBatch и другие классы рендеринга GDXlib.

Мой код openGL для ландшафта отображается правильно, пока я не вызову:

spriteBatch.draw(...);

или что-то подобное, например:

stage.draw();

После этого вызова мой код openGL больше не рисовался. Никаких ошибок, просто ничего на экране. Но SpriteBatch работает нормально.

Спустя долгое время я понял, что мне нужно позвонить

glEnableVertexAttribArray(...);    

и

Gdx.gl.glBindBuffer(GL20.GL_ARRAY_BUFFER, posVertexBufferLoc);
Gdx.gl.glVertexAttribPointer(positionAttribLoc, 4, GL20.GL_FLOAT, false, 0, 0);

МНЕ НУЖНО ВЫЗВАТЬ ЭТО ПЕРЕД ВЫЗОВОМ --> glDrawArrays(...);

КАЖДЫЙ РАЗ ПЕРЕД ИСПОЛЬЗОВАНИЕМ glDraw... , -› КАЖДЫЙ КАДР

Если я не вызываю первый, ничего не отображается.

Если я не вызываю второй, он отображается в неправильных позициях.

Похоже, каждый раз, когда я использую классы GDXlib для рендеринга, это каким-то образом портит мои атрибуты.

Код инициализации:

shaderProgram = new ShaderProgram(baseVertexShader, baseFragmentShader);
if (!shaderProgram.isCompiled()) {
    Gdx.app.error("TerrainRenderer - Cannot compile shader", shaderProgram.getLog());
}

shaderProgram.begin();

//vertexBuffers
vertexBuffer = BufferUtils.newFloatBuffer(quadPosVertices.length);
vertexBuffer.put(quadPosVertices);
vertexBuffer.rewind();
//VBOs
//generate buffers
posVertexBufferLoc = Gdx.gl.glGenBuffer();
//pass data into buffers
Gdx.gl.glBindBuffer(GL20.GL_ARRAY_BUFFER, posVertexBufferLoc);
Gdx.gl.glBufferData(GL20.GL_ARRAY_BUFFER, vertexBuffer.capacity()*4, vertexBuffer, GL20.GL_STATIC_DRAW);
//attributes
//locations
positionAttribLoc = shaderProgram.getAttributeLocation("position");
//attributes specifications
Gdx.gl.glBindBuffer(GL20.GL_ARRAY_BUFFER, posVertexBufferLoc);
Gdx.gl.glVertexAttribPointer(positionAttribLoc, 4, GL20.GL_FLOAT, false, 0, 0);
//enabling attributes
shaderProgram.enableVertexAttribute(positionAttribLoc);
//end shader
shaderProgram.end();
Gdx.gl.glBindBuffer(GL20.GL_ARRAY_BUFFER, 0); //unbind

Нарисовать код:

Gdx.gl.glBindBuffer(GL20.GL_ARRAY_BUFFER, posVertexBufferLoc);
Gdx.gl.glVertexAttribPointer(positionAttribLoc, 4, GL20.GL_FLOAT, false, 0, 0);

shaderProgram.enableVertexAttribute(positionAttribLoc);

shaderProgram.begin();
Gdx.gl.glDrawArrays(GL20.GL_TRIANGLES, 0, 6);
shaderProgram.end();
Gdx.gl.glBindBuffer(GL20.GL_ARRAY_BUFFER, 0);

Как правильно использовать методы openGL с классами GDXlib? Мне действительно нужно вызывать эти атрибутивные функции в каждом кадре?


person Jerry Lundegaard    schedule 06.07.2020    source источник
comment
Какую версию OpenGL вы используете? В OpenGL 3.0 вы можете использовать объекты массива вершин   -  person Rabbid76    schedule 06.07.2020
comment
Согласно этому: badlogicgames.com/forum/viewtopic.php?f= 11&t=25760 Должно быть 4.1, если я правильно понимаю. Но вот вопрос - › Можно ли узнать, как использовать VAO для решения моей проблемы?   -  person Jerry Lundegaard    schedule 06.07.2020
comment
да. VAO хранит спецификацию вершины. достаточно привязать VAO перед вызовом отрисовки. Обратите внимание: если вы не используете именованный VAO, то автоматически используется VAO по умолчанию (0), а спецификация вершины сохраняется в VAO по умолчанию.   -  person Rabbid76    schedule 06.07.2020
comment
Вы идете ниже уровня, чем вам нужно. Вы можете использовать для этого класс Mesh, и он будет правильно связываться и развязываться, поэтому вы не будете заимствовать и возиться с сеткой вашего SpriteBatch.   -  person Tenfour04    schedule 06.07.2020
comment
@ Tenfour04 Я знаю, но я думал, что это тоже должно работать...   -  person Jerry Lundegaard    schedule 06.07.2020
comment
@ Tenfour04 Рендеринг с использованием экземпляра Mesh работает!   -  person Jerry Lundegaard    schedule 07.07.2020
comment
Отлично, извините, у меня не было возможности посмотреть подробности. Могут быть некоторые подробности о чем-то, что нужно было связать/развязать, что класс Mesh делает для вас, но вы случайно пропустили в своем собственном коде.   -  person Tenfour04    schedule 07.07.2020
comment
@Tenfour04, @Rabbid76, я обнаружил, что Mesh.class вызывает: glBindBuffer(GL20.GL_ARRAY_BUFFER, location) glVertexAttribPointer(...) и glEnableVertexAttribArray(...) перед каждым вызовом отрисовки. Мне кажется, что GDXlib по какой-то причине не использует VAO, и поэтому его нужно вызывать каждый кадр. Я прав? Влияет ли вызов производительности перед каждым вызовом отрисовки?   -  person Jerry Lundegaard    schedule 08.07.2020
comment
Как mesh.draw(...) может уничтожить мою настройку атрибута? Он даже не использует тот же шейдер?   -  person Jerry Lundegaard    schedule 10.07.2020
comment
@JerryLundegaard Это не имеет ничего общего с шейдером. Спецификация вершины хранится в VAO. Если вы не используете VAO с разными именами, то VAO по умолчанию (0) повторно используется для каждой сетки. Если вы используете один и тот же VAO, вам придется менять спецификацию вершины перед каждым вызовом отрисовки.   -  person Rabbid76    schedule 11.07.2020
comment
@ Rabbid76 О, я думал, что glGetAttribLocation(program, name) возвращает другой номер местоположения для атрибута, потому что он использует другой шейдер, но вы правы, это не так. Теперь это имеет смысл для меня. Сетка использует те же номера местоположений для своих атрибутов.   -  person Jerry Lundegaard    schedule 11.07.2020


Ответы (1)


OpenGL — это конечный автомат. Когда libGDX делает что-то с OpenGL, это неизбежно изменит состояние контекста OpenGL на что-то другое.

Канонический способ рисования в OpenGL:

  1. Установите для каждого состояния, от которого вы зависите, значения, необходимые для рисования.

  2. Затем нарисуйте его.

Долгое время в OpenGL не было VAO (объектов массива вершин), и вам фактически приходилось выполнять комбинацию glBindBuffer, glVertexAttribPointer каждый раз, когда вы переключали буферы вершин. Большинство драйверов OpenGL хорошо оптимизированы в этом пути кода, и, на самом деле, еще тогда, когда были представлены VAO, их использование снижало производительность. Это уже не так, но раньше было.

Также вы не можете улучшить производительность, экономя вызовы OpenGL. OpenGL не находится на этом низком уровне и во многом работает так же, как современный ЦП с внеочередным выполнением: пока результат идентичен тому, что было бы отображено, если бы каждая команда выполнялась в порядок может задерживать и перестраивать операции.

person datenwolf    schedule 17.07.2020