Dessinez avec PyOpenGL. Confusion autour de VBO

Vous devez garder cela pour PyOpenGL. OpenGL n'a pas complètement tronqué l'ancienne API pendant la transition Shader, Le codage ambigu qui repose sur un mélange d'anciennes et de nouvelles méthodes et de valeurs implicites par défaut est devenu monnaie courante. Je suis accro au C, mais c'est plus déroutant en Python.

Code

Niveau 0: glBegin

Maintenant, il est obsolète, mais celui-ci est le plus simple pour dessiner un triangle.

cube


# coding: utf-8
from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL.GLUT import *
import sys

s=0.5
vertices=[
        -s, -s, -s,
         s, -s, -s,
         s,  s, -s,
        -s,  s, -s,
        -s, -s,  s,
         s, -s,  s,
         s,  s,  s,
        -s,  s,  s,
        ]
colors=[
        0, 0, 0,
        1, 0, 0,
        0, 1, 0,
        0, 0, 1,
        0, 1, 1,
        1, 0, 1,
        1, 1, 1,
        1, 1, 0,
        ]
indices=[
        0, 1, 2, 2, 3, 0,
        0, 4, 5, 5, 1, 0,
        1, 5, 6, 6, 2, 1,
        2, 6, 7, 7, 3, 2,
        3, 7, 4, 4, 0, 3,
        4, 7, 6, 6, 5, 4,
        ]

#
#Fonction de dessin glBegin
#
def draw_cube0():
    glBegin(GL_TRIANGLES)
    for i in range(0, len(indices), 3):
        index=indices[i]*3
        glColor3f(*colors[index:index+3])
        glVertex3f(*vertices[index:index+3])

        index=indices[i+1]*3
        glColor3f(*colors[index:index+3])
        glVertex3f(*vertices[index:index+3])

        index=indices[i+2]*3
        glColor3f(*colors[index:index+3])
        glVertex3f(*vertices[index:index+3])
    glEnd()

def initialize():
    glClearColor(0.0, 0.0, 0.0, 0.0)
    glClearDepth(1.0)
    glDepthFunc(GL_LESS)
    glEnable(GL_DEPTH_TEST)

def resize(Width, Height):
    # viewport
    if Height == 0:
        Height = 1
    glViewport(0, 0, Width, Height)
    # projection
    glMatrixMode(GL_PROJECTION)
    glLoadIdentity()
    gluPerspective(45.0, float(Width)/float(Height), 0.1, 100.0)

yaw=0
pitch=0
def draw():
    global yaw, pitch
    # clear
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)

    # view
    glMatrixMode(GL_MODELVIEW)
    glLoadIdentity()
    yaw+=0.39
    pitch+=0.27
    glTranslatef(0.0, 0.0, -2.0)
    glRotatef(yaw, 0, 1, 0)
    glRotatef(pitch, 1, 0, 0)

    # cube
    draw_cube0()

    glFlush()


##############################################################################
# glut driver
##############################################################################

def reshape_func(w, h):
    resize(w, h == 0 and 1 or h)

def disp_func():
    draw()
    glutSwapBuffers()

if __name__=="__main__":
    glutInit(sys.argv)
    glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH)
    glutInitWindowSize(256, 256)
    glutCreateWindow(b"vbo")
    glutDisplayFunc(disp_func)
    glutIdleFunc(disp_func)
    glutReshapeFunc(reshape_func)

    initialize()

    glutMainLoop()

Niveau 1: glVertexPointer sans VBO

Vous pouvez utiliser des tableaux. Pas trop tôt.

def draw_cube1():
    glEnableClientState(GL_VERTEX_ARRAY);
    glEnableClientState(GL_COLOR_ARRAY);
    glVertexPointer(3, GL_FLOAT, 0, vertices);
    glColorPointer(3, GL_FLOAT, 0, colors)
    glDrawElements(GL_TRIANGLES, len(indices), GL_UNSIGNED_INT, indices);
    glDisableClientState(GL_COLOR_ARRAY)
    glDisableClientState(GL_VERTEX_ARRAY);

Niveau 2: glVertexPointer avec VBO sans Shader

Transférez la baie vers le GPU. vite. Cependant, c'est difficile à comprendre. Puisque le tableau brut de python n'est pas accepté, créez une chaîne d'octets avec des ctypes et transmettez-la à l'API. Je viens d'apprendre cette méthode pour la première fois.

draw2


buffers=None
def create_vbo():
    buffers = glGenBuffers(3)
    glBindBuffer(GL_ARRAY_BUFFER, buffers[0])
    glBufferData(GL_ARRAY_BUFFER, 
            len(vertices)*4,  # byte size
            (ctypes.c_float*len(vertices))(*vertices), #Ctypes mystérieux
            GL_STATIC_DRAW)
    glBindBuffer(GL_ARRAY_BUFFER, buffers[1])
    glBufferData(GL_ARRAY_BUFFER, 
            len(colors)*4, # byte size 
            (ctypes.c_float*len(colors))(*colors),  #Ctypes mystérieux
            GL_STATIC_DRAW)
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[2])
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, 
            len(indices)*4, # byte size
            (ctypes.c_uint*len(indices))(*indices),  #Ctypes mystérieux
            GL_STATIC_DRAW)
    return buffers

def draw_vbo():
    glEnableClientState(GL_VERTEX_ARRAY);
    glEnableClientState(GL_COLOR_ARRAY);
    glBindBuffer(GL_ARRAY_BUFFER, buffers[0]);
    glVertexPointer(3, GL_FLOAT, 0, None);
    glBindBuffer(GL_ARRAY_BUFFER, buffers[1]);
    glColorPointer(3, GL_FLOAT, 0, None);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[2]);
    glDrawElements(GL_TRIANGLES, len(indices), GL_UNSIGNED_INT, None);
    glDisableClientState(GL_COLOR_ARRAY)
    glDisableClientState(GL_VERTEX_ARRAY);

def draw_cube2():
    global buffers
    if buffers==None:
        buffers=create_vbo()
    draw_vbo()

Niveau 3: glVertexPointer avec VBO avec Shader

Comment écrire un mélange d'anciennes API et de Shader. L'ancien code peut ressembler à ceci. Puisque toutes les variables (gl_XXX) du shader sont définies par BuiltIn, La quantité de description est réduite, mais il existe de nombreuses parties implicites. Quand je l'ai fait avant, pour utiliser la nouvelle fonction OpenGL http://glewpy.sourceforge.net/ J'avais besoin de faire beaucoup de préparatifs, mais maintenant je peux utiliser de nouvelles fonctions telles que glCreateProgram sans rien faire.

draw3


class Shader(object):

    def initShader(self, vertex_shader_source, fragment_shader_source):
        # create program
        self.program=glCreateProgram()
        print('create program')
        printOpenGLError()

        # vertex shader
        print('compile vertex shader...')
        self.vs = glCreateShader(GL_VERTEX_SHADER)
        glShaderSource(self.vs, [vertex_shader_source])
        glCompileShader(self.vs)
        glAttachShader(self.program, self.vs)
        printOpenGLError()

        # fragment shader
        print('compile fragment shader...')
        self.fs = glCreateShader(GL_FRAGMENT_SHADER)
        glShaderSource(self.fs, [fragment_shader_source])
        glCompileShader(self.fs)
        glAttachShader(self.program, self.fs)
        printOpenGLError()

        print('link...')
        glLinkProgram(self.program)
        printOpenGLError()

    def begin(self):
        if glUseProgram(self.program):
            printOpenGLError()

    def end(self):
        glUseProgram(0)

shader=None
def draw_cube3():
    global shader, buffers
    if shader==None:
        shader=Shader()
        shader.initShader('''
void main()
{
    gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
    gl_FrontColor = gl_Color;
}
        ''',
        '''
void main()
{
    gl_FragColor = gl_Color;
}
        ''')
        buffers=create_vbo()

    shader.begin()
    draw_vbo()
    shader.end()

Niveau 4: glVertexAttribPointer

Un gars moderne. Est-ce le seul GLES ou WebGL? Cependant, si l'emplacement de la variable Shader est pris, il faudra plus de temps pour préparer la propre fonction en raison de l'abolition du setter de variable uniforme, glu et glMatrix, donc je l'enverrai la prochaine fois. J'ai senti que Python pourrait être l'environnement le plus léger pour jouer avec Shader s'il y avait un utilitaire qui pouvait le configurer ici.

Résumé

Je l'oublie à chaque fois et le vérifie à nouveau, alors j'ai essayé de résumer la VBO de PyOpenGL comme un mémorandum de mon choix.

Recommended Posts

Dessinez avec PyOpenGL. Confusion autour de VBO
Programmation Shader avec pyOpenGL
Dessinez la courbe de Bézier avec Go
Dessinez un graphique avec NetworkX
Dessinez bonjour le monde avec mod_wsgi
Jouez avec les partitions Linux
Dessiner un fichier netCDF avec python
Dessinez un graphique avec networkx
Applications avec PyOpenCL (PIL et PyOpenGL)