将数据传递给 PyOpenGL 中的 glBufferData,空屏幕

passing data to glBufferData in PyOpenGL, empty screen

我正在使用 PyOpenGL 绘制一个简单的三角形。但是,我只得到一个空屏幕。我认为问题是我没有正确地将数据传递给 glBufferData。我尝试按照 this Whosebug question 中的答案进行操作,但没有结果。由于使用 glBegin() 和 glVertex() 进行绘图,因此着色器可以正常编译和工作。但是,使用 glDrawElements 或 glDrawArrays 绘图不起作用。这是我的代码(我为 OpenGL window 使用 pygame):

import numpy as np
import pygame as pg
from pygame.locals import *
from array import array
SCREEN_SIZE = (800, 600)


from OpenGL.GL import *
from OpenGL.GLU import *

def resize(width, height):

    glViewport(0, 0, width, height)
    glMatrixMode(GL_PROJECTION)
    glLoadIdentity()
    gluPerspective(60.0, float(width)/height, .1, 1000.)
    glMatrixMode(GL_MODELVIEW)
    glLoadIdentity()




def create_shader(shader_type,source):
    shader = glCreateShader(shader_type)
    glShaderSource(shader,source)
    glCompileShader(shader)
    print(glGetShaderiv(shader, GL_COMPILE_STATUS, None))
    return shader

pg.init()
screen = pg.display.set_mode(SCREEN_SIZE, HWSURFACE|OPENGL|DOUBLEBUF)

resize(*SCREEN_SIZE)

#creating and compiling fragment shader
fragment = create_shader(GL_FRAGMENT_SHADER,"""

#version 130

out vec4 finalColor; 

void main()
{
    finalColor = vec4(.0,0.0,1.0,1.0);
}
""")

#creating and compiling vertex shader
vertex = create_shader(GL_VERTEX_SHADER,"""

#version 130


in vec3 pos;

void main()
{   

    gl_Position=gl_ProjectionMatrix*gl_ModelViewMatrix *vec4(pos,1.0);



}
""")

#create and link program
program = glCreateProgram()
glAttachShader(program, fragment)
glAttachShader(program, vertex)
glLinkProgram(program)
#get location of the position variable in vertex shader
posAttrib = glGetAttribLocation(program, "pos")


vbo=glGenBuffers(1)
ebo=glGenBuffers(1)
vao=glGenVertexArrays(1)

#specify the integer and float types to use in the glGenBuffer function
dtypei=np.dtype('<u4')
dtypef=np.dtype('<f4')

glBindVertexArray(vao)

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo)
glBufferData(GL_ELEMENT_ARRAY_BUFFER, np.array([0,1,2],dtype=dtypei), GL_STATIC_DRAW)
glBindBuffer(GL_ARRAY_BUFFER, vbo)

vert=[-1.5, -0.5, -4.0, -0.5, -0.5, -4.0, -0.5, 0.5, -4.0]
nparray = np.array(vert,dtype=dtypef)
glBufferData(GL_ARRAY_BUFFER, nparray, GL_STATIC_DRAW)

#can also try using the array library
#ar = array("f",vert)
#glBufferData(GL_ARRAY_BUFFER, ar.tostring(), GL_STATIC_DRAW)

#specify how the variable pos gets data from the buffer data
glEnableVertexAttribArray(posAttrib)
glVertexAttribPointer(posAttrib, 3, GL_FLOAT, False, 3*4,0)

while 1:


    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glClearColor(1.0, 1.0, 1.0, 0.0)

    glUseProgram(program)
    glBindVertexArray(vao)
    #this draw function produces NOTHING
    glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, 0)
    #can also try using glDrawArrays
    #glDrawArrays(GL_TRIANGLES, 0, 3)

    #this drawing produces a triangle
    #glBegin(GL_TRIANGLES)
    #glColor3f( 0,1,0 )
    #glVertex3f( -1.5, -0.5, -4.0 )
    #glColor3f( 0,1,1 )
    #glVertex3f( -0.5, -0.5, -4.0 )
    #glColor3f( 1,1,0 )
    #glVertex3f( -0.5, 0.5, -4.0 )    
    #glEnd()



    pg.display.flip()
    pg.time.delay(10)

您可以取消注释 glBegin()...glEnd() 部分,您会看到将绘制一个蓝色三角形,因此着色器可以正常工作。

我曾尝试更改变量 dtypei 和 dtypef(分别对应于传递给 glGenBuffers 的 numpy 数组的 int 类型和 float 类型),但没有成功。可以尝试的不同类型是

dtypei=np.dtype('<i4')
dtypei=np.dtype('>i4')
dtypei=np.dtype('=i4')
dtypei=np.int32

dtypei=np.dtype('<u4')
dtypei=np.dtype('>u4')
dtypei=np.dtype('=u4')
dtypei=np.uint32

dtypef=np.dtype('>f4')
dtypef=np.dtype('<f4')
dtypef=np.dtype('=f4')
dtypef=np.float32

对应于 integers/floats 具有不同的字节顺序(uint32、int32 和 float32 可能是多余的)。看到这个 documentation。我也尝试使用数组库中的数组对象,正如另一个 Whosebug post 中所建议的那样,也没有任何结果

我真的迷路了

问题不在于 numpy 数据类型对象,而是调用 glVertexAttribPointerglDrawElements:

glVertexAttribPointer的第6个参数的数据类型必须是ctypes.c_void_p

这意味着您必须使用 ctypes.cast:

glVertexAttribPointer(posAttrib, 3, GL_FLOAT, False, 3*4, ctypes.cast(0, ctypes.c_void_p))

None:

glVertexAttribPointer(posAttrib, 3, GL_FLOAT, False, 3*4, None)


glDrawElements

的第4个参数也是如此

两者都

glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, ctypes.cast(0, ctypes.c_void_p))

glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, None)