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))
我最近开始通过 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))