Как вы преобразуете проект OpenGL из старых методов glVertexAttribPointer в новые методы привязки glVertexAttribBinding?

#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);  

После внесения изменений процедуры ничего не выводят на экран. Там нет никаких исключений или указаний (которые я могу сказать) на проблему с выполнением команд. Это просто оставляет пустой экран.

Общие вопросы:

  1. Правильно ли выглядит мое преобразование в более новые методы массива вершин? Видите ли вы какие-либо ошибки в логике?
  2. Должен ли я выполнять определенные вызовы glEnable, чтобы заставить этот метод работать вместо старого метода?
  3. Могу ли я смешивать и сопоставлять два метода для заполнения атрибутов в одной и той же программе шейдера? (например, в дополнение к вышесказанному я заполняю данные треугольника и использую их в той же программе шейдера. Если я не переключил этот процесс на новый метод, это вызовет проблему)?

Если мне здесь чего-то еще не хватает, я был бы очень признателен, если бы вы дали мне знать.

Ответ №1:

Еще немного поисков, и я понял свою ошибку:

При использовании glVertexAttribPointer вы можете установить параметр шага равным 0 (нулю), и OpenGL автоматически определит шаг; однако при использовании glVertexAttribFormat вы должны установить шаг самостоятельно.

Как только я вручную установил значение шага glVertexAttribFormat , все работало так, как ожидалось.