[PYTHON] Zeichnen Sie mit PyOpenGL. Verwirrung um VBO

Sie müssen dies für PyOpenGL niedrig halten. OpenGL hat die alte API während des Shader-Übergangs nicht vollständig abgeschnitten. Mehrdeutige Codierungen, die auf einer Mischung aus alten und neuen Methoden und impliziten Standardwerten beruhen, sind weit verbreitet. Ich bin süchtig nach C, aber in Python ist es verwirrender.

Code

Stufe 0: glBegin

Jetzt ist es veraltet, aber dieses ist am einfachsten, ein Dreieck zu zeichnen.

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,
        ]

#
#Zeichenfunktion 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()

Level 1: glVertexPointer ohne VBO

Sie können Arrays verwenden. Nicht zu früh.

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

Level 2: glVertexPointer mit VBO ohne Shader

Übertragen Sie das Array auf die GPU. schnell. Es ist jedoch schwer zu verstehen. Da das Raw-Array von Python nicht akzeptiert wird, erstellen Sie eine Byte-Zeichenfolge mit ctypes und übergeben Sie sie an die API. Ich habe diese Methode gerade zum ersten Mal gelernt.

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), #Geheimnisvolle Typen
            GL_STATIC_DRAW)
    glBindBuffer(GL_ARRAY_BUFFER, buffers[1])
    glBufferData(GL_ARRAY_BUFFER, 
            len(colors)*4, # byte size 
            (ctypes.c_float*len(colors))(*colors),  #Geheimnisvolle Typen
            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),  #Geheimnisvolle Typen
            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()

Level 3: glVertexPointer mit VBO mit Shader

Wie schreibe ich eine Mischung aus alter API und Shader. Der alte Code könnte so aussehen. Da alle Variablen (gl_XXX) im Shader von BuiltIn definiert werden, Der Umfang der Beschreibung wird reduziert, es gibt jedoch viele implizite Teile. Als ich es vorher getan habe, um die neue OpenGL-Funktion zu verwenden http://glewpy.sourceforge.net/ Ich musste viele Vorbereitungen treffen, aber jetzt kann ich neue Funktionen wie glCreateProgram verwenden, ohne etwas zu tun.

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()

Stufe 4: glVertexAttribPointer

Ein moderner Typ. Ist dies das einzige GLES oder WebGL? Wenn Sie jedoch den Speicherort der Shader-Variablen verwenden, dauert die Vorbereitung Ihrer eigenen Funktion aufgrund der Abschaffung von Setter, glu und glMatrix der einheitlichen Variablen länger, sodass ich sie beim nächsten Mal senden werde. Ich hatte das Gefühl, dass Python die leichteste Umgebung sein könnte, um mit Shader zu spielen, wenn es ein Dienstprogramm gäbe, das es hier einrichten könnte.

Zusammenfassung

Ich vergesse es jedes Mal und überprüfe es erneut, also habe ich versucht, das VBO von PyOpenGL als eigenes Memorandum zusammenzufassen.

Recommended Posts

Zeichnen Sie mit PyOpenGL. Verwirrung um VBO
Shader-Programmierung mit pyOpenGL
Zeichnen Sie die Bezier-Kurve mit Go
Zeichnen Sie mit NetworkX ein Diagramm
Zeichne Hallo Welt mit mod_wsgi
Spielen Sie mit Linux-Partitionen herum
Zeichnen Sie eine netCDF-Datei mit Python
Zeichnen Sie mit networkx ein Diagramm
Anwendungen mit PyOpenCL (PIL & PyOpenGL)