#opengl #vertex-buffer #vao
Вопрос:
У меня есть проект OpenGL, в котором ранее использовались методы на основе OpenGL 3.0 для рисования массивов, и я пытаюсь преобразовать его в более новые методы (по крайней мере, доступные с OpenGL 4.3). Однако до сих пор мне не удавалось заставить его работать.
Фрагмент кода, который я буду использовать для объяснения, создает группы точек и проводит линии между ними. Он также может заполнить полученный многоугольник (используя треугольники). Я приведу пример, используя процедуры рисования точек. Вот псевдокод того, как он работал раньше:
[Подлинный текст] Когда точки генерируются впервые (происходит один раз):
// ORIGINAL, WORKING CODE RUN ONCE DURING SETUP: // NOTE: This code is in c# and uses a library called SharpGL // to invoke OpenGL calls via a context herein called "gl" float[] xyzArray = [CODE NOT SHOWN -- GENERATES ARRAY OF POINTS] // Create a buffer for the vertex data // METHOD CODE NOT SHOWN, but uses glGenBuffers to fill class-member buffer IDs GenerateBuffers(gl); // Note: we now have a VerticesBufferId // Set the vertex buffer as the current buffer and fill it gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, this.VerticesBufferId); gl.BufferData(OpenGL.GL_ARRAY_BUFFER, xyzArray, OpenGL.GL_STATIC_DRAW);
[Подлинный текст] В цикле, который выполняет рисование:
// ORIGINAL, WORKING CODE EXECUTED DURING EACH DRAW LOOP: // NOTE: This code is in c# and uses a library called SharpGL // to invoke OpenGL calls via a context herein called "gl" // Note: positionAttributeId (below) was derived from the active // shader program via glGetAttribLocation gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, this.VerticesBufferId); gl.EnableVertexAttribArray(positionAttributeId); gl.VertexAttribPointer(positionAttributeId, 3, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero); // Missing code sets some uniforms in the shader program and determines // the start (iStart) and length (pointCount) of points to draw gl.DrawArrays(OpenGL.GL_LINE_STRIP, iStart, pointCount);
Этот код работает уже довольно давно, но я пытаюсь перейти к более современным методам. Большая часть моего кода вообще не изменилась, и это новый код, который заменил вышеперечисленное:
[После Модов] Когда точки генерируются впервые (происходит один раз):
// MODIFIED CODE RUN ONCE DURING SETUP: // NOTE: This code is in c# and uses a library called SharpGL // to invoke OpenGL calls via a context herein called "gl" float[] xyzArray = [CODE NOT SHOWN -- GENERATES ARRAY OF POINTS] // Create a buffer for the vertex data // METHOD CODE NOT SHOWN, but uses glGenBuffers to fill class-member buffer IDs GenerateBuffers(gl); // Note: we now have a VerticesBufferId. // Set the vertex buffer as the current buffer gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, this.VerticesBufferId); gl.BufferData(OpenGL.GL_ARRAY_BUFFER, xyzArray, OpenGL.GL_STATIC_DRAW); // ^^^ ALL CODE ABOVE THIS LINE IS IDENTIAL TO THE ORIGINAL ^^^ // Generate Vertex Arrays // METHOD CODE NOT SHOWN, but uses glGenVertexArrays to fill class-member array IDs GenerateVertexArrays(gl); // Note: we now have a PointsArrayId // My understanding: I'm telling OpenGL to associate following calls // with the vertex array generated with the ID PointsArrayId... gl.BindVertexArray(PointsArrayId); // Here I associate the positionAttributeId (found from the shader program) // with the currently bound vertex array (right?) gl.EnableVertexAttribArray(positionAttributeId); // Here I tell the bound vertex array about the format of the position // attribute as it relates to that array -- I think. gl.VertexAttribFormat(positionAttributeId, 3, OpenGL.GL_FLOAT, false, 0); // As I understand it, I can define my own "local" buffer index // in the following calls (?). Below I use 0, which I then bind // to the buffer with id = this.VerticesBufferId (for the purposes // of the currently bound vertex array) gl.VertexAttribBinding(positionAttributeId, 0); gl.BindVertexBuffer(0, this.VerticesBufferId, IntPtr.Zero, 0); gl.BindVertexArray(0); // we no longer want to be bound to PointsArrayId
[После Модов] В цикле, который выполняет рисование:
// MODIFIED CODE EXECUTED DURING EACH DRAW LOOP:: // NOTE: This code is in c# and uses a library called SharpGL // to invoke OpenGL calls via a context herein called "gl" // Here I tell OpenGL to bind the VertexArray I established previously // (which should understand how to fill the position attribute in the // shader program using the "zeroth" buffer index tied to the // VerticesBufferId data buffer -- because I went through all the trouble // of telling it that above, right?) gl.BindVertexArray(this.PointsArrayId); // / / / NOTE: NO CODE CHANGES IN THE CODE BELOW ThIS LINE / / / // Missing code sets some uniforms in the shader program and determines // the start (iStart) and length (pointCount) of points to draw gl.DrawArrays(OpenGL.GL_LINE_STRIP, iStart, pointCount);
После внесения изменений процедуры ничего не выводят на экран. Там нет никаких исключений или указаний (которые я могу сказать) на проблему с выполнением команд. Это просто оставляет пустой экран.
Общие вопросы:
- Правильно ли выглядит мое преобразование в более новые методы массива вершин? Видите ли вы какие-либо ошибки в логике?
- Должен ли я выполнять определенные вызовы glEnable, чтобы заставить этот метод работать вместо старого метода?
- Могу ли я смешивать и сопоставлять два метода для заполнения атрибутов в одной и той же программе шейдера? (например, в дополнение к вышесказанному я заполняю данные треугольника и использую их в той же программе шейдера. Если я не переключил этот процесс на новый метод, это вызовет проблему)?
Если мне здесь чего-то еще не хватает, я был бы очень признателен, если бы вы дали мне знать.
Ответ №1:
Еще немного поисков, и я понял свою ошибку:
При использовании glVertexAttribPointer
вы можете установить параметр шага равным 0 (нулю), и OpenGL автоматически определит шаг; однако при использовании glVertexAttribFormat
вы должны установить шаг самостоятельно.
Как только я вручную установил значение шага glVertexAttribFormat
, все работало так, как ожидалось.