pythonopenglvbopyopenglopengl-compat

Python OpenGL VAO - How to use separate arrays for vertex and color data


I'm having a hard time finding information / explanations for how to properly bind and unbind the vertex buffer object and the color buffer object and what changes are made to the draw call when the vertex and color data is stored in separate arrays.

The working code I have properly (I hope) creates the VBO, binds it to the VAO, and passes the vertex data in order for it to be displayed:

from pygame.locals import *
from OpenGL.GL import *
from OpenGL.GLU import *
import pygame
import numpy as np
import time

vertex_Data = [
    -1.0, -1.0, -1.0,
    -1.0, -1.0, 1.0,
    -1.0, 1.0, 1.0,
    1.0, 1.0, -1.0,
    -1.0,-1.0, -1.0,
    -1.0, 1.0, -1.0,
    1.0, -1.0, 1.0,
    -1.0, -1.0, -1.0,
    1.0, -1.0, -1.0,
    1.0, 1.0, -1.0,
    1.0, -1.0, -1.0,
    -1.0,- 1.0, -1.0,
    -1.0, -1.0, -1.0,
    -1.0, 1.0, 1.0,
    -1.0, 1.0, -1.0,
    1.0, -1.0, 1.0,
    -1.0, -1.0, 1.0,
    -1.0, -1.0, -1.0,
    -1.0, 1.0, 1.0,
    -1.0, -1.0, 1.0,
    1.0, -1.0, 1.0,
    1.0, 1.0, 1.0,
    1.0, -1.0, -1.0,
    1.0, 1.0, -1.0,
    1.0, -1.0, -1.0,
    1.0, 1.0, 1.0,
    1.0,-1.0, 1.0,
    1.0, 1.0, 1.0,
    1.0, 1.0, -1.0,
    -1.0, 1.0, -1.0,
    1.0, 1.0, 1.0,
    -1.0, 1.0, -1.0,
    -1.0, 1.0, 1.0,
    1.0, 1.0, 1.0,
    -1.0, 1.0, 1.0,
    1.0, -1.0, 1.0
]

color_Data = [
    0.583,  0.771,  0.014,
    0.609,  0.115,  0.436,
    0.327,  0.483,  0.844,
    0.822,  0.569,  0.201,
    0.435,  0.602,  0.223,
    0.310,  0.747,  0.185,
    0.597,  0.770,  0.761,
    0.559,  0.436,  0.730,
    0.359,  0.583,  0.152,
    0.483,  0.596,  0.789,
    0.559,  0.861,  0.639,
    0.195,  0.548,  0.859,
    0.014,  0.184,  0.576,
    0.771,  0.328,  0.970,
    0.406,  0.615,  0.116,
    0.676,  0.977,  0.133,
    0.971,  0.572,  0.833,
    0.140,  0.616,  0.489,
    0.997,  0.513,  0.064,
    0.945,  0.719,  0.592,
    0.543,  0.021,  0.978,
    0.279,  0.317,  0.505,
    0.167,  0.620,  0.077,
    0.347,  0.857,  0.137,
    0.055,  0.953,  0.042,
    0.714,  0.505,  0.345,
    0.783,  0.290,  0.734,
    0.722,  0.645,  0.174,
    0.302,  0.455,  0.848,
    0.225,  0.587,  0.040,
    0.517,  0.713,  0.338,
    0.053,  0.959,  0.120,
    0.393,  0.621,  0.362,
    0.673,  0.211,  0.457,
    0.820,  0.883,  0.371,
    0.982,  0.099,  0.879
]



if __name__ == '__main__':

    # create and initialize window
    pygame.init()
    display = (1920, 1080)
    pygame.display.set_mode(display, DOUBLEBUF | OPENGL)

    # set perspective and near and far view limits
    gluPerspective(10, (display[0] / display[1]), 0.1, 500.0)

    # move and rotate world space
    glTranslatef(0, 0, -80)
    glRotatef(-10, 1, 0, 0)

    # Enables Z depth testing
    glEnable(GL_DEPTH_TEST)

    # ____Vertex____

    # Enables capability
    # (capability to enable)
    glEnableClientState(GL_VERTEX_ARRAY)

    # Generates n buffer objects
    # (number of names to generate)
    vertex_buffer_object = glGenBuffers(1)

    # Binds the buffer to a target
    # (target = Vertex Array Object, name of buffer object)
    # GL_ARRAY_BUFFER = vertex attributes
    glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer_object)


    # Copies data into target (currently bound buffer)
    # (Target, size in bites, data, usage)
    glBufferData(GL_ARRAY_BUFFER, len(vertex_Data) * 4, np.array(vertex_Data, dtype="float32"), GL_DYNAMIC_DRAW)

    # defines the array of vertex data
    # (number of coordinates per vertex, data type, stride = offset between end of vertex and start of next, pointer to first coordinate = must be None for python?)
    glVertexPointer(3, GL_FLOAT, 0, None)

    # ____Color____
    # glEnableClientState(GL_COLOR_ARRAY)
    # color_buffer_object = glGenBuffers(1)
    # glBindBuffer(GL_ARRAY_BUFFER, color_buffer_object)
    # glBufferData(GL_ARRAY_BUFFER, len(color_Data) * 4, np.array(color_Data, dtype="float32"), GL_DYNAMIC_DRAW)
    # glBindBuffer(GL_ARRAY_BUFFER, color_buffer_object)
    # glColorPointer(3, GL_FLOAT, 0, None)

    while True:
        # enable event detection for closing the window
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                quit()

        # rotate the world space
        glRotatef(-10, 0, 1, 0)

        # clears target buffers
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)

        # render primitives
        # (type of primitives to be rendered, starting index, number of indices to be rendered)
        glDrawArrays(GL_TRIANGLES, 0, int(len(vertex_Data) / 3))

        # update window and sleep
        pygame.display.flip()
        time.sleep(.1)

My code produces a rotating, white cube, but I don't fully grasp how the gl calls are interfacing with each other, and as such I dont know exactly how I would integrate a second buffer object into the VAO or if thats even what I should be intending to do.

From the gl documentation, I believe I need to enable the GL_COLOR_ARRAY, create another buffer object (would it still be called a VBO?), bind that object to the VAO, pass along the color data, and define the array of color data using glColorPointer. But as to the order of those in relation to the existing code for vertex_Data as well as when/if I am unbinding, I am at a loss.

Any help or insight would be appreciated.


Solution

  • Create an array buffer like you do for the vertices:

    color_buffer_object = glGenBuffers(1)
    glBindBuffer(GL_ARRAY_BUFFER, color_buffer_object)
    glBufferData(GL_ARRAY_BUFFER, len(color_Data) * 4, np.array(color_Data, dtype="float32"), GL_DYNAMIC_DRAW)
    

    Define the array of color attributes with glColorPointer and enable the client state:

    glBindBuffer(GL_ARRAY_BUFFER, color_buffer_object)
    glColorPointer(3, GL_FLOAT, 0, None)
    glEnableClientState(GL_COLOR_ARRAY)
    

    OpenGL is a state engine. A state is kept util it is changed again. The current array buffer binding is a global state (which is set with glBindBuffer(GL_ARRAY_BUFFER, object)). If you specify an array with glVertexPointer or glColorPointer, the corresponding buffer object must be bound. When this instructions are called, the buffer which is currently bound to the GL_ARRAY_BUFFER target is associated to the fixed function attribute (vertex respectively color).