目录
1.前言
2.开始玩转VBO
2.1 准备工作
2.2 创建顶点缓冲区对象
2.3 开始绘制
2.4解绑
2.5绘图
3 第一个VBO程序
1.前言
由于网上的许多关于VBO的解析的文章很少(特别是关于Python),有许多文章写的很笼统,使许多人不知道VBO怎么使用,但它又很有必要(提高渲染效率,这在进行大量绘图时很有用),为了节省大家的时间,也为了让大家更好的了解和使用VBO,现在本文章将系统的讲解VBO。(由于本人还不是太熟悉,如果有什么问题,欢迎大家在评论区指正,请见谅)
2.开始玩转VBO
用PyOpenGL绘图时往往要处理几百个点,这时立即模式(使用glBegin/glEnd方式)就显得无能为力 (况且Python运行效率本来就慢), 这时VBO是最好的选择
VBO(顶点缓冲)是把我们要渲染的图元信息(比如纹理、颜色)一次性发送到GPU,和立即模式下相比,它的渲染效率显然更高 所以我们首选VBO进行大量绘图
VBO绘图流程:
| 1、创建顶点缓冲区对象 |
| 2、分离顶点混合数组 |
| 3,、绘制 |
| 4、解绑顶点缓冲区对象 |
2.1 准备工作
我们先导入库:
from OpenGL.GL import * from OpenGL.arrays import vbo from OpenGL.GLU import * from OpenGL.GLUT import * import numpy as np
2.2 创建顶点缓冲区对象
我们先以绘制正方体为例子,先定义一个函数(我定义的函数名是cube()),再在函数中写入正方体的顶点数据(坐标):
# 顶点集
vertices = np.array([
-0.5, 0.5, 0.5,
0.5, 0.5, 0.5,
0.5, -0.5, 0.5,
-0.5, -0.5, 0.5,
-0.5, 0.5, -0.5,
0.5, 0.5, -0.5,
0.5, -0.5, -0.5,
-0.5, -0.5, -0.5
], 'f')
# 索引集
indices = np.array([
0, 1, 2, 3,
4, 5, 1, 0,
3, 2, 6, 7,
5, 4, 7, 6,
1, 5, 6, 2,
4, 0, 3, 7
],'H')
#numpy数组类型很重要,否则你用不正确的数组绘图就会一片空白(本人真实经历)
在这里我解释一下索引集的作用:正方体有6个面,4个点构成一个面,则有24个点,但有16个点是重复的,索引值的作用类似于字串符的索引,你可以把顶点集的一组数据看做一个字符,索引值的每一个值为索引(我讲的有点乱,但知道字串符索引应该理解),把那些数据按索引传到GPU,减小了顶点集占的空间。
接下来我们要把这些数据传到GPU上,方法如下:
def cube():
...
vbo1 = vbo.VBO(vertices)
vbo2 = vbo.VBO(indices, target=GL_ELEMENT_ARRAY_BUFFER)
2.3 开始绘制
话不多说,先上代码:
-
def cube(): ... vbo1.bind() glInterleavedArrays(GL_V3F,0,None) vbo2.bind() glDrawElements(GL_QUADS,24,GL_UNSIGNED_SHORT,None) - glInterleavedArrays()函数:
这个函数用来分离顶点数据(以后我们会讲分离颜色)
第一个参数有12个选项:
| GL_V2F | |
| GL_V3F | |
| GL_C4UB_V2F | |
| GL_N3F_V3F | |
| GL_C3F_V3F | |
| GL_C4F_N3F_V3F | |
| GL_T2F_V3F | |
| GL_T4F_V4F | |
| GL_T2F_C4UB_V3F | |
| GL_T2F_C3F_V3F | |
| GL_T2F_N3F_V3F | |
| GL_T2F_C4F_N3F_V3F | |
| GL_T4F_C4F_N3F_V4F |
glInterleavedArrays()函数的后两个参数只能是0和None
- 函数:glDrawElements()
- 第一个参数:
和立即模式一样,指定绘图模式,其模式名及其作用都与立即模式一样
可以参见:pyoepngl全解析-2_Hit-road的博客-CSDN博客,这里面有对模式的讲解
- 第二个参数:
传入大小,大小计算用下面代码即可
len('索引集')
- 第三个参数:
表示第四个参数的类型 (但第四个参数貌似只能是None),共有3个选项:
| GL_UNSIGNED_INT | |
| GL_UNSIGNED_BYT | |
| GL_UNSIGNED_SHORT |
- 第四个参数:
上文已经说了,只能是None,传给一个空指针
2.4解绑
没什么可讲的:
def cube():
...
vbo2.unbind()
vbo1.unbind()
2.5绘图
注意,我们的工作没完,我们的最终目的是把我们绘制的图呈现到电脑屏幕上,其方法和之前一样,用glutDisplayFunc()函数把我们想要的东西呈现在屏幕上(至于其他的设置,你是奔着VBO来的,所以其他设置你应该是知道的):
def cube():
...
def draw():
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
cube()
glutSwapBuffers()
...
glutDisplayFunc(draw)
当然,你也可以这样:
def cube():
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
vertices = np.array([
...
...
])
...
...
glutSwapBuffers()
...
...
glutDisplayFunc(cube)
若你真不会,请参见另一个博主写的文章:写给 python 程序员的 OpenGL 教程
3 第一个VBO程序
完整代码:
from OpenGL.GL import *
from OpenGL.arrays import vbo
from OpenGL.GLU import *
from OpenGL.GLUT import *
import numpy as np
def cube():
vertices = np.array([
-0.5, 0.5, 0.5,
0.5, 0.5, 0.5,
0.5, -0.5, 0.5,
-0.5, -0.5, 0.5,
-0.5, 0.5, -0.5,
0.5, 0.5, -0.5,
0.5, -0.5, -0.5,
-0.5, -0.5, -0.5
],'f')
indices = np.array([
0, 1, 2, 3,
4, 5, 1, 0,
3, 2, 6, 7,
5, 4, 7, 6,
1, 5, 6, 2,
4, 0, 3, 7
],'H')
vbo1 = vbo.VBO(vertices)
vbo2 = vbo.VBO(indices,target = GL_ELEMENT_ARRAY_BUFFER)
eboLength = len(indices)
vbo1.bind()
glInterleavedArrays(GL_V3F,0,None)
vbo2.bind()
glDrawElements(GL_QUADS,eboLength,GL_UNSIGNED_SHORT,None)
vbo2.unbind()
vbo1.unbind()
def Draw():
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
cube()
glutSwapBuffers()
glutInit()
glutInitDisplayMode(GLUT_DOUBLE | GLUT_ALPHA | GLUT_DEPTH)
glutInitWindowSize(600, 600)
glutInitWindowPosition(300, 200)
glutCreateWindow('cube')
glClearColor(0.0, 0.0, 0.0, 1.0)
glEnable(GL_DEPTH_TEST)
glDepthFunc(GL_LEQUAL)
glutDisplayFunc(Draw)
glutMainLoop()
运行结果:
怎么让立方体动起来,请参见
写给 python 程序员的 OpenGL 教程
pyopengl全解析-4
不过颜色好单调,好白
>>>PyOpenGL_VBO解析_2_颜色
暑期编程PK赛 得CSDN机械键盘等精美礼品!


