базовый openGL, вершинные буферы и pyglet - PullRequest
6 голосов
/ 06 января 2011

Изменить: rotoglup обнаружил проблемы в моем коде, добавив шейдеры, которые я удалил, завершил решение. Смотрите мой ответ ниже для правильного кода (с шейдерами).

Привет всем!

Я пытаюсь изучить некоторые основы современного OpenGL из этого урока .

Я бы хотел сделать это с python / pyglet вместо C ++. Я знаю, что Pyglet может абстрагироваться от OpenGL низкого уровня; Я хочу понять некоторые основы, прежде чем перейти к тому, чтобы скрыть их за слоями абстракции.

Моя проблема предельно проста: код ниже рисует только одну точку вместо ожидаемых 3. Мой код, насколько я могу судить, идентичен C ++ в учебнике, за исключением удаления вершинных и фрагментных шейдеров (выполняется через gletools в python), что, по-видимому, не имеет никакого значения для моего проблема.

Упрощение вещей до единой точки показывает поведение, которого я не понимаю (кажется, что первая координата - единственная, которая влияет на что-либо), что возвращает меня к моему убеждению, что я просто не смог понять чего-то очень базового в обоих pyglet , OpenGL или даже 3D в целом: p

Вот соответствующий код:

import pyglet
from pyglet.gl import *

window = pyglet.window.Window()

positionBufferObject = GLuint()
vao = GLuint()

vertexPositions = [0.0, 0.0, 0.0,
                   0.25, 0.0, 0.0,
                   1.75, 1.75, 0.0]

vertexPositionsGl = (GLfloat * len(vertexPositions))(*vertexPositions)

@window.event
def on_draw():
    glBindBuffer(GL_ARRAY_BUFFER, positionBufferObject)
    glEnableVertexAttribArray(0)
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0)
    glDrawArrays(GL_POINTS, 0, 3)
    glDisableVertexAttribArray(0)

glGenBuffers(1, positionBufferObject)
glBindBuffer(GL_ARRAY_BUFFER, positionBufferObject)
glBufferData(GL_ARRAY_BUFFER, len(vertexPositionsGl)*4, vertexPositionsGl, GL_STATIC_DRAW)
glBindBuffer(GL_ARRAY_BUFFER, 0)

glClearColor(0.0, 0.0, 0.0, 0.0)
pyglet.app.run()

Ответы [ 2 ]

5 голосов
/ 06 января 2011
glDrawArrays(GL_POINTS, 0, 1)

приказывает нарисовать 1 очко, в вашем уроке 1 равно 3:

glDrawArrays(GL_POINTS, 0, 3)

Обратите также внимание, что 4-й (w) компонент ваших вершин должен быть 1, а не 0:

  vertexPositions = [0.0, 0.0, 0.0, 1.0,
                     0.25, 0.0, 0.0, 1.0,
                     1.75, 1.75, 0.0, 1.0]

Кроме того, вы можете удалить компонент w,

  vertexPositions = [0.0, 0.0, 0.0,
                     0.25, 0.0, 0.0,
                     1.75, 1.75, 0.0]

и измените следующий вызов на:

glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0)

Другое дело, я не эксперт в pyglet, но возможно, что glBufferData, как и его аналог в C, принимает размер в байтах, а не в элементах. Каждый float по 4 байта, вы можете попробовать:

glBufferData(GL_ARRAY_BUFFER, len(vertexPositionsGl)*4, vertexPositionsGl, GL_STATIC_DRAW)
4 голосов
/ 07 января 2011

Я наконец понял это правильно!

Кажется, меня вводит в заблуждение тот факт, что игра с вершинами, glDrawArrays и glVertexAttribPointer иногда приводила к отображению одной точки. Похоже, это случайность: с поправками, указанными в ответе rotoglup, вообще ничего не нарисовано. Это «правильное» поведение кода в моем исходном вопросе.

Инвентаризация моих ошибок на случай, если она кому-нибудь поможет:

  • установка координаты w равной 0, а не 1, полностью пропуская объяснения для преобразования пространства клипа в учебнике.

  • давая glBufferData размер буфера в вершинах, когда он ожидает байты.

  • удаление вершинных и фрагментных шейдеров (для упрощения кода при поиске двух вышеупомянутых проблем). Это гарантировало, что ничто не будет визуализировано ... кроме (глючной?) Единственной точки, которую я иногда получал.

Для справки, приведенный ниже код отображает один треугольник с проходными шейдерами, который, я надеюсь, будет в курсе и исправит OpenGL. Требования: pyglet и gletools.

import pyglet
from pyglet.gl import *
from gletools import ShaderProgram, FragmentShader, VertexShader

window = pyglet.window.Window()

positionBufferObject = GLuint()

vertexPositions = [0.75, 0.75, 0.0, 1.0,
                   0.75, -0.75, 0.0, 1.0,
                   -0.75, -0.75, 0.0, 1.0]
vertexPositionsGl = (GLfloat * len(vertexPositions))(*vertexPositions)

program = ShaderProgram(
    FragmentShader('''
    #version 330
    out vec4 outputColor;
    void main()
    {
       outputColor = vec4(1.0f, 1.0f, 1.0f, 1.0f);
    }'''),
    VertexShader('''
    #version 330
    layout(location = 0) in vec4 position;
    void main()
    {
        gl_Position = position;
    }''')
)

@window.event
def on_draw():
    with program:
        glBindBuffer(GL_ARRAY_BUFFER, positionBufferObject)
        glEnableVertexAttribArray(0)
        glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, 0)
        glDrawArrays(GL_TRIANGLES, 0, 3)
        glDisableVertexAttribArray(0)

glGenBuffers(1, positionBufferObject)
glBindBuffer(GL_ARRAY_BUFFER, positionBufferObject)
glBufferData(GL_ARRAY_BUFFER, len(vertexPositionsGl)*4, vertexPositionsGl, GL_STATIC_DRAW)
glBindBuffer(GL_ARRAY_BUFFER, 0)

pyglet.app.run()
...