PyOpenGL - 最小的 glDrawArrays 示例
PyOpenGL - Minimal glDrawArrays Example
我看过许多最小的 PyOpenGL 示例,但 none 我发现的示例使用了 VAO 或 glDrawArrays / glDrawElements。相反,它们都使用 glVertex、过剩形状,偶尔还使用旧的 glCallList 函数。
我现在正在尝试编写一个使用顶点数组和缓冲区存储顶点数据的最小工作示例。如果我正确理解 PyOpenGL,下面的代码应该在屏幕上绘制一个白色三角形,但我得到的是一个空白屏幕。
我可能做错了什么?我也很难理解 PyOpenGL documentation. Many of the functions are defined one way, but are used in many places and work a totally different way, and some don't even seem to work the way they're defined (e.g. glGenBuffers,它声明它接受两个参数,但似乎只接受一个和 return 生成的缓冲区)。
p.s。我既没有使用 numpy,也没有使用 pygame.
from OpenGL.GLUT import *
from OpenGL.GLU import *
from OpenGL.GL import *
import ctypes
import sys
name = 'PyOpenGL Example'
vao = None
program = None
def main():
glutInit(sys.argv)
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH)
glutInitContextVersion(4,0)
glutInitWindowSize(600,400)
glutCreateWindow(name)
print(glGetString(GL_VERSION))
glClearColor(0,0,0,1)
glutDisplayFunc(display)
# glutMouseFunc(callback)
# glutMotionFunc(callback)
# glutPassiveMotionFunc(callback)
# glutKeyboardFunc(callback)
# glutSpecialFunc(callback)
vshader = glCreateShader(GL_VERTEX_SHADER)
fshader = glCreateShader(GL_FRAGMENT_SHADER)
glShaderSource(vshader,["""
#version 400
uniform mat4 u_model;
uniform mat4 u_view;
in vec4 a_pos;
in vec4 a_color;
in vec4 a_normal;
out vec4 v_color;
out vec4 v_normal;
void main() {
gl_Position = a_pos; // * u_model * u_view;
v_color = a_color;
v_normal = normalize(a_normal);
}
"""])
glCompileShader(vshader)
msg = glGetShaderInfoLog(vshader)
if msg:
print(f"Failed to compile Vertex Shader: {msg}")
exit(0)
glShaderSource(fshader,["""
#version 400
uniform mat4 u_model;
uniform mat4 u_view;
in vec4 v_color;
in vec4 v_normal;
layout(location=0) out vec4 f_color;
void main() {
f_color = v_color;
}
"""])
glCompileShader(fshader)
msg = glGetShaderInfoLog(fshader)
if msg:
print(f"Failed to compile Fragment Shader: {msg}")
exit(0)
global program
program = glCreateProgram()
glAttachShader(program,vshader)
glAttachShader(program,fshader)
glLinkProgram(program)
msg = glGetProgramInfoLog(program)
if msg:
print(f"Failed to link Program: {msg}")
exit(0)
glUseProgram(program)
uniforms = {
'model': glGetUniformLocation(program,'u_model'),
'view': glGetUniformLocation(program,'u_view'),
}
print(uniforms)
attrs = {
'pos': glGetAttribLocation(program,'a_pos'),
'color': glGetAttribLocation(program,'a_color'),
'normal': glGetAttribLocation(program,'a_normal'),
}
print(attrs)
global vao
vao = glGenVertexArrays(1)
glBindVertexArray(vao)
verts = [
-1, -1, 0, 1,
1, -1, 0, 1,
0, 1, 0, 1,
]
colors = [
1, 1, 1, 1,
1, 1, 1, 1,
1, 1, 1, 1,
]
normals = [
0, 0, 1, 0,
0, 0, 1, 0,
0, 0, 1, 0,
]
vbuf,cbuf,nbuf = glGenBuffers(3)
glBindBuffer(GL_ARRAY_BUFFER,vbuf)
glBufferData(GL_ARRAY_BUFFER,(ctypes.c_float*len(verts))(*verts),GL_STATIC_DRAW)
glVertexAttribPointer(attrs['pos'],4,GL_FLOAT,GL_FALSE,0,0)
glEnableVertexAttribArray(attrs['pos'])
glBindBuffer(GL_ARRAY_BUFFER,cbuf)
glBufferData(GL_ARRAY_BUFFER,(ctypes.c_float*len(colors))(*colors),GL_STATIC_DRAW)
glVertexAttribPointer(attrs['color'],4,GL_FLOAT,GL_FALSE,0,0)
glEnableVertexAttribArray(attrs['color'])
glBindBuffer(GL_ARRAY_BUFFER,nbuf)
glBufferData(GL_ARRAY_BUFFER,(ctypes.c_float*len(normals))(*normals),GL_STATIC_DRAW)
# glVertexAttribPointer(attrs['normal'],4,GL_FLOAT,GL_FALSE,0,0)
# glEnableVertexAttribArray(attrs['normal'])
glBindBuffer(GL_ARRAY_BUFFER,0)
glBindVertexArray(0)
identity = [
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1,
]
# glUniformMatrix4fv(uniforms['model'],1,GL_FALSE,(ctypes.c_float*16)(*identity))
# glUniformMatrix4fv(uniforms['view'],1,GL_FALSE,(ctypes.c_float*16)(*identity))
glutMainLoop()
return
def display():
glUseProgram(program)
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)
glViewport(0,0,600,400)
print(vao)
glBindVertexArray(vao)
glDrawArrays(GL_TRIANGLES,0,3)
glBindVertexArray(0)
glutSwapBuffers()
return
def callback(*args):
print(*args)
if __name__ == '__main__': main()
如果绑定了命名数组缓冲区对象,则 glVertexAttribPointer
的最后一个参数(第 6 个参数)将被视为缓冲区对象数据存储中的字节偏移量。参数的数据类型必须是 ctypes.c_void_p
。
这意味着您必须使用 ctypes.cast
:
例如
glVertexAttribPointer(attrs['pos'], 4, GL_FLOAT, GL_FALSE, 0,
ctypes.cast(0, ctypes.c_void_p))
或None
:
glVertexAttribPointer(attrs['pos'], 4, GL_FLOAT, GL_FALSE, 0, None)
另外注意,如果你在GLSL代码中做矩阵变换,那么向量必须乘以从右到右的矩阵。
参见 GLSL Programming/Vector and Matrix Operations
例如
gl_Position = u_view * u_model * a_pos;
我看过许多最小的 PyOpenGL 示例,但 none 我发现的示例使用了 VAO 或 glDrawArrays / glDrawElements。相反,它们都使用 glVertex、过剩形状,偶尔还使用旧的 glCallList 函数。
我现在正在尝试编写一个使用顶点数组和缓冲区存储顶点数据的最小工作示例。如果我正确理解 PyOpenGL,下面的代码应该在屏幕上绘制一个白色三角形,但我得到的是一个空白屏幕。
我可能做错了什么?我也很难理解 PyOpenGL documentation. Many of the functions are defined one way, but are used in many places and work a totally different way, and some don't even seem to work the way they're defined (e.g. glGenBuffers,它声明它接受两个参数,但似乎只接受一个和 return 生成的缓冲区)。
p.s。我既没有使用 numpy,也没有使用 pygame.
from OpenGL.GLUT import * from OpenGL.GLU import * from OpenGL.GL import * import ctypes import sys name = 'PyOpenGL Example' vao = None program = None def main(): glutInit(sys.argv) glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH) glutInitContextVersion(4,0) glutInitWindowSize(600,400) glutCreateWindow(name) print(glGetString(GL_VERSION)) glClearColor(0,0,0,1) glutDisplayFunc(display) # glutMouseFunc(callback) # glutMotionFunc(callback) # glutPassiveMotionFunc(callback) # glutKeyboardFunc(callback) # glutSpecialFunc(callback) vshader = glCreateShader(GL_VERTEX_SHADER) fshader = glCreateShader(GL_FRAGMENT_SHADER) glShaderSource(vshader,[""" #version 400 uniform mat4 u_model; uniform mat4 u_view; in vec4 a_pos; in vec4 a_color; in vec4 a_normal; out vec4 v_color; out vec4 v_normal; void main() { gl_Position = a_pos; // * u_model * u_view; v_color = a_color; v_normal = normalize(a_normal); } """]) glCompileShader(vshader) msg = glGetShaderInfoLog(vshader) if msg: print(f"Failed to compile Vertex Shader: {msg}") exit(0) glShaderSource(fshader,[""" #version 400 uniform mat4 u_model; uniform mat4 u_view; in vec4 v_color; in vec4 v_normal; layout(location=0) out vec4 f_color; void main() { f_color = v_color; } """]) glCompileShader(fshader) msg = glGetShaderInfoLog(fshader) if msg: print(f"Failed to compile Fragment Shader: {msg}") exit(0) global program program = glCreateProgram() glAttachShader(program,vshader) glAttachShader(program,fshader) glLinkProgram(program) msg = glGetProgramInfoLog(program) if msg: print(f"Failed to link Program: {msg}") exit(0) glUseProgram(program) uniforms = { 'model': glGetUniformLocation(program,'u_model'), 'view': glGetUniformLocation(program,'u_view'), } print(uniforms) attrs = { 'pos': glGetAttribLocation(program,'a_pos'), 'color': glGetAttribLocation(program,'a_color'), 'normal': glGetAttribLocation(program,'a_normal'), } print(attrs) global vao vao = glGenVertexArrays(1) glBindVertexArray(vao) verts = [ -1, -1, 0, 1, 1, -1, 0, 1, 0, 1, 0, 1, ] colors = [ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ] normals = [ 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, ] vbuf,cbuf,nbuf = glGenBuffers(3) glBindBuffer(GL_ARRAY_BUFFER,vbuf) glBufferData(GL_ARRAY_BUFFER,(ctypes.c_float*len(verts))(*verts),GL_STATIC_DRAW) glVertexAttribPointer(attrs['pos'],4,GL_FLOAT,GL_FALSE,0,0) glEnableVertexAttribArray(attrs['pos']) glBindBuffer(GL_ARRAY_BUFFER,cbuf) glBufferData(GL_ARRAY_BUFFER,(ctypes.c_float*len(colors))(*colors),GL_STATIC_DRAW) glVertexAttribPointer(attrs['color'],4,GL_FLOAT,GL_FALSE,0,0) glEnableVertexAttribArray(attrs['color']) glBindBuffer(GL_ARRAY_BUFFER,nbuf) glBufferData(GL_ARRAY_BUFFER,(ctypes.c_float*len(normals))(*normals),GL_STATIC_DRAW) # glVertexAttribPointer(attrs['normal'],4,GL_FLOAT,GL_FALSE,0,0) # glEnableVertexAttribArray(attrs['normal']) glBindBuffer(GL_ARRAY_BUFFER,0) glBindVertexArray(0) identity = [ 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, ] # glUniformMatrix4fv(uniforms['model'],1,GL_FALSE,(ctypes.c_float*16)(*identity)) # glUniformMatrix4fv(uniforms['view'],1,GL_FALSE,(ctypes.c_float*16)(*identity)) glutMainLoop() return def display(): glUseProgram(program) glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT) glViewport(0,0,600,400) print(vao) glBindVertexArray(vao) glDrawArrays(GL_TRIANGLES,0,3) glBindVertexArray(0) glutSwapBuffers() return def callback(*args): print(*args) if __name__ == '__main__': main()
如果绑定了命名数组缓冲区对象,则 glVertexAttribPointer
的最后一个参数(第 6 个参数)将被视为缓冲区对象数据存储中的字节偏移量。参数的数据类型必须是 ctypes.c_void_p
。
这意味着您必须使用 ctypes.cast
:
例如
glVertexAttribPointer(attrs['pos'], 4, GL_FLOAT, GL_FALSE, 0,
ctypes.cast(0, ctypes.c_void_p))
或None
:
glVertexAttribPointer(attrs['pos'], 4, GL_FLOAT, GL_FALSE, 0, None)
另外注意,如果你在GLSL代码中做矩阵变换,那么向量必须乘以从右到右的矩阵。
参见 GLSL Programming/Vector and Matrix Operations
例如
gl_Position = u_view * u_model * a_pos;