PyOpenGL,Pygame和着色器似乎没有合作

时间:2012-02-22 11:28:02

标签: python glsl pygame pyopengl

我一直在研究现代OpenGL编程的这个excellent tutorial,我正在慢慢调整它以适应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()

根据我的理解,我应该得到一个红色正方形来覆盖屏幕的右上象限,但我正在做的任何事情似乎都不会影响完全灰色的屏幕。任何有关错误的见解都会受到高度赞赏!

1 个答案:

答案 0 :(得分:5)

在将问题进一步缩小并在C中进行几乎逐行匹配之后,我意识到这只是pyopengl中的一个问题,而不是pygame。我在他们的邮件列表上发布了示例代码,并找到了答案:

http://sourceforge.net/mailarchive/message.php?msg_id=28875534

似乎在他们如何为glDrawElements实现ctypes包装器方面存在轻微的“错误”。给出偏移量的最后一个参数需要type(void *)。由简单0传入的值不起作用,需要用GLvoidp(0)包装。