glDrawElements 在 PyOpenGL 中绘制立方体

glDrawElements to draw a cube in PyOpenGL

我最近开始通过 Python 学习 OpenGL 多亏了几个教程(尤其是 Nicolas P. Rougier 的教程:http://www.labri.fr/perso/nrougier/teaching/opengl/)。

我现在正在切换到 3D,我正在尝试绘制立方体。

因此,我设法得到一些不呈现立方体的三角形(这似乎是正常的,因为我没有复制我的顶点并且我使用了 glDrawArrays 函数)。

然而,之后,我构建了一个索引 "vector" 以进一步使用 glDrawElements 函数来渲染我的立方体。结果,我没有收到任何错误,但屏幕上什么也没有显示。

希望对您有所帮助!

这是我的代码:

#! /usr/bin/env python
# -*- coding: utf-8 -*-

import sys
import ctypes
import numpy as np
import OpenGL.GL as gl
import OpenGL.GLUT as glut

vertex_code = """

    uniform float scale;
    uniform mat4 matCam;
    attribute vec4 color;
    attribute vec3 position;
    varying vec4 v_color;
    void main()
    {
        gl_Position = matCam*vec4(scale*position, 1.0);
        v_color = color;
    } """

fragment_code = """
    varying vec4 v_color;
    void main()
    {
        gl_FragColor = v_color;
    } """

def display():
    gl.glClear(gl.GL_COLOR_BUFFER_BIT)
    #gl.glDrawArrays(gl.GL_TRIANGLES, 0, 12)

    gl.glDrawElements(gl.GL_TRIANGLES, len(index), gl.GL_UNSIGNED_INT, index) # render nothing (i.e. only the background color)
    glut.glutSwapBuffers()

def reshape(width,height):
    gl.glViewport(0, 0, width, height)

def keyboard( key, x, y ):
    if key == '3':
        sys.exit( )

def timer(fps):
    global clock
    clock += 0.0005*1000.0/fps
    print(clock)
#    eye = np.array([0,0,1])
#    center = np.array([0,clock,0])
#    up = np.array([0,1,0])
#    mat = computeLookAtMatrix(eye, center, up)
    theta = clock;
    mat = np.array([[np.cos(theta), 0, np.sin(theta), 0],
                [0, 1, 0, 0],
                [-np.sin(theta), 0, np.cos(theta), 0],
                [0, 0, 0, 1]])
    loc = gl.glGetUniformLocation(program, "matCam")
    gl.glUniformMatrix4fv(loc, 1, False, mat)



    glut.glutTimerFunc(1000/fps, timer, fps)
    glut.glutPostRedisplay()


# GLUT init
# --------------------------------------
glut.glutInit()
glut.glutInitDisplayMode(glut.GLUT_DOUBLE | glut.GLUT_RGBA)
glut.glutCreateWindow('Hello world!')
glut.glutReshapeWindow(512,512)
glut.glutReshapeFunc(reshape)
glut.glutDisplayFunc(display)
glut.glutKeyboardFunc(keyboard)
glut.glutTimerFunc(1000/60, timer, 60)

# Build data
# --------------------------------------
data = np.zeros(8, [("position", np.float32, 3),
                    ("color",    np.float32, 4)])

data['color']    = [ (1,0,0,1), (0,1,0,1), (0,0,1,1), (1,1,0,1),
                    (1,0,0,1), (0,1,0,1), (0,0,1,1), (1,1,0,1) ]

data['position'] = [ (-1,-1,1),
                     (1,-1,1),
                        (1,1,1),   
                        (-1,1,1),
                        (-1,-1,-1),
                        (1,-1,-1),
                        (1,1,-1),
                        (-1,1,-1)]

index = np.array([0,1,2,
                2,3,0,
                1,5,6,
                6,2,1,
                7,6,5,
                5,4,7,
                4,0,3,
                3,7,4,
                4,5,1,
                1,0,4,
                3,2,6,
                6,7,3])

# Build & activate program
# --------------------------------------

# Request a program and shader slots from GPU
program  = gl.glCreateProgram()
vertex   = gl.glCreateShader(gl.GL_VERTEX_SHADER)
fragment = gl.glCreateShader(gl.GL_FRAGMENT_SHADER)

# Set shaders source
gl.glShaderSource(vertex, vertex_code)
gl.glShaderSource(fragment, fragment_code)

# Compile shaders
gl.glCompileShader(vertex)
gl.glCompileShader(fragment)

# Attach shader objects to the program
gl.glAttachShader(program, vertex)
gl.glAttachShader(program, fragment)

# Build program
gl.glLinkProgram(program)

# Get rid of shaders (no more needed)
gl.glDetachShader(program, vertex)
gl.glDetachShader(program, fragment)

# Make program the default program
gl.glUseProgram(program)


# Build buffer
# --------------------------------------

# Request a buffer slot from GPU
buffer = gl.glGenBuffers(1)

# Make this buffer the default one
gl.glBindBuffer(gl.GL_ARRAY_BUFFER, buffer)

# Upload data
gl.glBufferData(gl.GL_ARRAY_BUFFER, data.nbytes, data, gl.GL_DYNAMIC_DRAW)

# same for index buffer
buffer_index= gl.glGenBuffers(1)
gl.glBindBuffer(gl.GL_ELEMENT_ARRAY_BUFFER, buffer_index)
gl.glBufferData(gl.GL_ELEMENT_ARRAY_BUFFER, index.nbytes, index, gl.GL_STATIC_DRAW)


# Bind attributes
# --------------------------------------
stride = data.strides[0]
offset = ctypes.c_void_p(0)
loc = gl.glGetAttribLocation(program, "position")
gl.glEnableVertexAttribArray(loc)
gl.glBindBuffer(gl.GL_ARRAY_BUFFER, buffer)
gl.glVertexAttribPointer(loc, 3, gl.GL_FLOAT, False, stride, offset)

offset = ctypes.c_void_p(data.dtype["position"].itemsize)
loc = gl.glGetAttribLocation(program, "color")
gl.glEnableVertexAttribArray(loc)
gl.glBindBuffer(gl.GL_ARRAY_BUFFER, buffer)
gl.glVertexAttribPointer(loc, 4, gl.GL_FLOAT, False, stride, offset)

gl.glBindBuffer(gl.GL_ELEMENT_ARRAY_BUFFER, buffer_index)

# Bind uniforms
# --------------------------------------
loc = gl.glGetUniformLocation(program, "scale")
gl.glUniform1f(loc, 0.5)
clock = 0

loc = gl.glGetUniformLocation(program, "matCam")
print(loc)
gl.glUniformMatrix4fv(loc, 1, False, np.eye(4))

# Enter mainloop
# --------------------------------------
glut.glutMainLoop()
gl.glDrawElements(gl.GL_TRIANGLES, len(index), gl.GL_UNSIGNED_INT, index)

根据 ELEMENT_ARRAY_BUFFER 是否绑定,索引参数有两种不同的含义:

  • 如果没有绑定:则它指定一个指向存储索引的客户端内存的指针
  • 如果绑定了 ELEMENT_ARRAY_BUFFER,则索引参数指定了此缓冲区的偏移量。这定义了索引在缓冲区中的起始位置。

在你的例子中,缓冲区是绑定的,所以你告诉 OpenGL 从缓冲区的某个地方开始。但是你想要的是从缓冲区的开头开始,因此你必须将索引设置为 0.

gl.glDrawElements(gl.GL_TRIANGLES, len(index), gl.GL_UNSIGNED_INT, ctypes.c_void_p(0))