PyOpenGL、Pygame 和着色器似乎不合作
我一直在研究这个 优秀教程 现代 OpenGL 编程,我正在慢慢调整它以在 PyOpenGL 和 pygame 上工作。然而,我很难得到一个“简单”的例子来处理透视几何。代码如下所示:
import pygame
import numpy as np
from OpenGL.GL import *
##########################################
# Define the simple pass-through shaders
##########################################
import cStringIO
vshade = cStringIO.StringIO("""
#version 110
uniform mat4 p_matrix;
uniform mat4 mv_matrix;
attribute vec4 position;
void main()
{
vec4 eye_position = mv_matrix * position;
gl_Position = p_matrix * eye_position;
}
""")
fshade = cStringIO.StringIO("""
#version 110
void main()
{
gl_FragColor = vec4(1.0,0.0,0.0,1.0);
}
""")
###################################################
# Set up a simple square composed of two triangles
###################################################
verts = np.array([[0,0,0,1],[1,0,0,1],[1,1,0,1],[0,1,0,1]]).astype(np.float32)
polys = np.array([[0,1,3],[1,2,3]]).astype(np.ushort)
mv_matrix = np.eye(4)
mv_matrix[:3,-1] = [0,0,2]
projection = np.array([ [ 1.071429, 0. , 0. , 0. ],
[ 0. , 1.428571, 0. , 0. ],
[ 0. , 0. , 1.000489, -0.125031],
[ 0. , 0. , 1. , 0. ]])
def _make_shader(stype, src):
shader = glCreateShader(stype)
glShaderSource(shader, src)
glCompileShader(shader)
if not glGetShaderiv(shader, GL_COMPILE_STATUS):
err = glGetShaderInfoLog(shader)
glDeleteShader(shader)
raise Exception(err)
return shader
##################################
# Initialize pygame and opengl
##################################
flags = pygame.DOUBLEBUF | pygame.HWSURFACE | pygame.OPENGL
pygame.display.set_mode((800,600), flags)
glEnable(GL_BLEND)
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
glClearColor(0.5,0.5,0.5,1)
glClearDepth(1.0)
glDepthFunc(GL_LESS)
glEnable(GL_DEPTH_TEST)
glEnable(GL_TEXTURE_2D)
######################################
# Make the shaders and programs
######################################
vshade = _make_shader(GL_VERTEX_SHADER, vshade.read())
fshade = _make_shader(GL_FRAGMENT_SHADER, fshade.read())
program = glCreateProgram()
glAttachShader(program, vshade)
glAttachShader(program, fshade)
glLinkProgram(program)
#######################################
# Fetch positions, push poly to card
#######################################
posidx = glGetAttribLocation(program, "position")
pidx = glGetUniformLocation(program, "p_matrix")
mvidx = glGetUniformLocation(program, "mv_matrix")
vbuf = glGenBuffers(1)
ebuf = glGenBuffers(1)
glBindBuffer(GL_ARRAY_BUFFER, vbuf)
glBufferData(GL_ARRAY_BUFFER,
verts.astype(np.float32).ravel(), GL_STATIC_DRAW)
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebuf)
glBufferData(GL_ELEMENT_ARRAY_BUFFER,
polys.astype(np.uint16).ravel(), GL_STATIC_DRAW)
#####################################
# Enter main drawing loop!
#####################################
glViewport(0,0,800,600)
while True:
# Clear the screen
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
glUseProgram(program)
# Push the transforms to the card
glUniformMatrix4fv(pidx, 1, GL_TRUE, projection.astype(np.float32))
glUniformMatrix4fv(mvidx, 1, GL_TRUE, mv_matrix.astype(np.float32))
# Enable the position attribute
glEnableVertexAttribArray(posidx)
glBindBuffer(GL_ARRAY_BUFFER, vbuf)
glVertexAttribPointer( posidx, 4, GL_FLOAT, GL_FALSE, 4*4, 0)
# Draw the two triangles
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebuf);
glDrawElements(
GL_TRIANGLES, # mode
len(polys)*3, # count
GL_UNSIGNED_SHORT, # type
0 # element array buffer offset
)
glDisableVertexAttribArray(posidx)
#inspect the values -- does it make sense?
glBindBuffer(GL_ARRAY_BUFFER, vbuf)
l, l2 = (GLfloat*16)() , (GLushort*6)()
glGetBufferSubData(GL_ARRAY_BUFFER, 0, 4*4*4, l)
print list(l)
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebuf)
glGetBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, 2*6, l2)
print list(l2)
glGetUniformfv(program, pidx, l)
print list(l)
glGetUniformfv(program, mvidx, l)
print list(l)
pygame.display.flip()
根据我的理解,我应该得到一个红色方块来覆盖屏幕的右上象限,但我所做的任何事情似乎都不会影响完全灰色的屏幕。任何对错误的见解将不胜感激!
I've been working through this excellent tutorial on modern OpenGL programming, and I'm slowly adapting it to work on PyOpenGL and pygame. However, I'm having the hardest time getting what should be a "trivial" example to work with perspective geometry. Code is as found here:
import pygame
import numpy as np
from OpenGL.GL import *
##########################################
# Define the simple pass-through shaders
##########################################
import cStringIO
vshade = cStringIO.StringIO("""
#version 110
uniform mat4 p_matrix;
uniform mat4 mv_matrix;
attribute vec4 position;
void main()
{
vec4 eye_position = mv_matrix * position;
gl_Position = p_matrix * eye_position;
}
""")
fshade = cStringIO.StringIO("""
#version 110
void main()
{
gl_FragColor = vec4(1.0,0.0,0.0,1.0);
}
""")
###################################################
# Set up a simple square composed of two triangles
###################################################
verts = np.array([[0,0,0,1],[1,0,0,1],[1,1,0,1],[0,1,0,1]]).astype(np.float32)
polys = np.array([[0,1,3],[1,2,3]]).astype(np.ushort)
mv_matrix = np.eye(4)
mv_matrix[:3,-1] = [0,0,2]
projection = np.array([ [ 1.071429, 0. , 0. , 0. ],
[ 0. , 1.428571, 0. , 0. ],
[ 0. , 0. , 1.000489, -0.125031],
[ 0. , 0. , 1. , 0. ]])
def _make_shader(stype, src):
shader = glCreateShader(stype)
glShaderSource(shader, src)
glCompileShader(shader)
if not glGetShaderiv(shader, GL_COMPILE_STATUS):
err = glGetShaderInfoLog(shader)
glDeleteShader(shader)
raise Exception(err)
return shader
##################################
# Initialize pygame and opengl
##################################
flags = pygame.DOUBLEBUF | pygame.HWSURFACE | pygame.OPENGL
pygame.display.set_mode((800,600), flags)
glEnable(GL_BLEND)
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
glClearColor(0.5,0.5,0.5,1)
glClearDepth(1.0)
glDepthFunc(GL_LESS)
glEnable(GL_DEPTH_TEST)
glEnable(GL_TEXTURE_2D)
######################################
# Make the shaders and programs
######################################
vshade = _make_shader(GL_VERTEX_SHADER, vshade.read())
fshade = _make_shader(GL_FRAGMENT_SHADER, fshade.read())
program = glCreateProgram()
glAttachShader(program, vshade)
glAttachShader(program, fshade)
glLinkProgram(program)
#######################################
# Fetch positions, push poly to card
#######################################
posidx = glGetAttribLocation(program, "position")
pidx = glGetUniformLocation(program, "p_matrix")
mvidx = glGetUniformLocation(program, "mv_matrix")
vbuf = glGenBuffers(1)
ebuf = glGenBuffers(1)
glBindBuffer(GL_ARRAY_BUFFER, vbuf)
glBufferData(GL_ARRAY_BUFFER,
verts.astype(np.float32).ravel(), GL_STATIC_DRAW)
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebuf)
glBufferData(GL_ELEMENT_ARRAY_BUFFER,
polys.astype(np.uint16).ravel(), GL_STATIC_DRAW)
#####################################
# Enter main drawing loop!
#####################################
glViewport(0,0,800,600)
while True:
# Clear the screen
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
glUseProgram(program)
# Push the transforms to the card
glUniformMatrix4fv(pidx, 1, GL_TRUE, projection.astype(np.float32))
glUniformMatrix4fv(mvidx, 1, GL_TRUE, mv_matrix.astype(np.float32))
# Enable the position attribute
glEnableVertexAttribArray(posidx)
glBindBuffer(GL_ARRAY_BUFFER, vbuf)
glVertexAttribPointer( posidx, 4, GL_FLOAT, GL_FALSE, 4*4, 0)
# Draw the two triangles
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebuf);
glDrawElements(
GL_TRIANGLES, # mode
len(polys)*3, # count
GL_UNSIGNED_SHORT, # type
0 # element array buffer offset
)
glDisableVertexAttribArray(posidx)
#inspect the values -- does it make sense?
glBindBuffer(GL_ARRAY_BUFFER, vbuf)
l, l2 = (GLfloat*16)() , (GLushort*6)()
glGetBufferSubData(GL_ARRAY_BUFFER, 0, 4*4*4, l)
print list(l)
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebuf)
glGetBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, 2*6, l2)
print list(l2)
glGetUniformfv(program, pidx, l)
print list(l)
glGetUniformfv(program, mvidx, l)
print list(l)
pygame.display.flip()
Based on my understanding, I should get a red square to cover the upper right quadrant of the screen, but nothing I'm doing seems to affect the fully gray screen. Any insight into what's wrong would be much appreciated!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
在进一步压缩问题并在 C 中进行几乎逐行匹配之后,我意识到这是 pyopengl 中的问题,而不是 pygame 中的问题。我在他们的邮件列表上发布了示例代码,并找到了答案:
http://sourceforge .net/mailarchive/message.php?msg_id=28875534
看来他们实现 ctypes 包装器的方式有点“错误”对于 glDrawElements。最后一个参数给出了偏移量,需要类型 (void*)。简单的 0 传入的值不起作用,需要用 GLvoidp(0) 包装。
After condensing the problem down even further and making a nearly line-by-line match in C, I realized that it was a problem in pyopengl exclusively, not in pygame. I posted on their mailing list with the example code, and found the answer:
http://sourceforge.net/mailarchive/message.php?msg_id=28875534
It seems that there's a slight "misfeature" in how they implemented the ctypes wrapper for glDrawElements. The final argument, which gives the offset, requires type (void*). The value passed in by a simple 0 doesn't work, and needs to be wrapped with GLvoidp(0).