使用python调用OpenGL

前言

OpenGL原生接口是C和C++的,不过OpenGL也提供了python版本,在本文中只会演示OpenGL在python中的最简单使用方法,更具体的功能还需要参考相关库的资料。

另外一部分就是介绍3D加载库Assimp,由于实际的项目都是先用3D软件做好模型,再其他地方使用,所以Assimp是OpenGL项目中相对很实用的库,不过其python版本安装相对复杂,所以这里特殊说明。

PyOpenGL安装

为了用Python使用OpenGL,我们需要安装两个库:

  • PyOpenGL:OpenGL的python接口库
  • PyOpenGL_accelerate:对PyOpenGL进行加速

建议使用conda进行安装,因为conda可以自动安装或更新其他的依赖库如numpy、vs_runtion等等。

1
2
conda install PyOpenGL
conda install conda install PyOpenGL

PyOpenGL官方文档为:http://pyopengl.sourceforge.net/documentation/

演示代码

在PyOpenGL后,可以先用如下简单的代码测试以下,openGL是否能正常工作:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL.GLUT import *

def drawFunc():
glClear(GL_COLOR_BUFFER_BIT)
glRotatef(0.1, 0.1, 0.5, 0)
glutWireTeapot(0.5)
glFlush()

def main():
glutInit()
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGBA)
glutInitWindowPosition(0,0)
glutInitWindowSize(400, 400)
glutCreateWindow(b'first')
glutDisplayFunc(drawFunc)
glutMainLoop()

if __name__ == '__main__':
main()

运行以上代码,得到如下窗口:

teapot

关于OpenGL的封装库

在OpenGL中一般的函数命名如下:

<前缀><根函数><参数数目><参数类型>

前缀有gl、glu、aux、glut、wgl、glx、agl等等,分别表示该函数属于OpenGL那个开发库等。所谓开发库,要知道原生的OpenGL是跨平台的,跨平台意味着很多功能是无法统一实现,比如说Windows和X-Window的窗口实现机制是不同的,OpenGL并不关心这些东西,只管画图。所以,基本的OpenGL并没有窗口函数,比如无法创建窗口,无法获得输入等等,这些东西都需要其他的函数库来实现。

在上面的演示代码中我们主要使用两种库,一个是GLU库,它提供了比较基础的命令的封装,可以很简单的实现比较多的复杂功能;而另外一个就是GLUT,glut是不依赖于窗口平台的OpenGL工具包,目的是隐藏不同窗口平台API的复杂度,提供更为复杂的绘制功能。

结合上面的演示代码,可以看到PyOpenGL的用法其实和c++使用原生OpenGL区别非常小。所以更复杂的图形绘制,可以先找c++代码,然后将其变成python代码。

简单Glut的代码框架

虽然现在glut库基本上被其他库代替,但是在旧版的OpenGL中还是使用得比较多的,其基本代码框架python版本如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL.GLUT import *

def userinit():
glClearColor( 0.0, 0.0, 0.0, 0.0 )
glColor4f(1.0,1.0,0.0,0.0)

def drawFunc():
glClear(GL_COLOR_BUFFER_BIT)
glBegin(GL_TRIANGLES)
glVertex3f(-0.5,-0.5,0.0)
glVertex3f(0.5,0.0,0.0)
glVertex3f(0.0,0.5,0.0)
glEnd()
glFlush()

# 调整窗口大小回调函数
def reshape(w, h):
glViewport(0,0,w,h);

def keyboardAction(key, x, y):
print(key)
if key == b'q':
exit();

def main():
glutInit()
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGBA)
glutInitWindowPosition(0,0)
glutInitWindowSize(400, 400)
glutCreateWindow(b'first')

userinit()
# glutReshapeFunc(reshape)
glutDisplayFunc(drawFunc)
glutKeyboardFunc(keyboardAction)
glutMainLoop()


if __name__ == '__main__':
main()

3D模型文件与Assimp库

3D软件生成的模型文件有很多格式,如obj、3ds、c4e等,这些文件主要包含如下内容的数据:

  • 定点坐标
  • 法线坐标
  • 纹理坐标
  • 材质、灯光信息

如果希望在OpenGL中使用到这些模型,那么就需要对这些模型文件进行解析,对于某些简单的格式如obj,它是文本格式的文件,每一行的首字符作为标记,可以直接读取解析,但是对于复杂的格式就不那么方便了,最好可以使用他人提供的库来加载。

Assimp则是OpenGl中常用的模型加载库,全称 Open Asset Import Library,它支持很多种格式的模型文件。同样它也提供了python版本pyassimp

pyassimp安装

pyassimpy的安装不一样,我们先使用pip安装后,它仍然是不能导入的,且提示错误:

“ pyassimp.errors.AssimpError: assimp library not found”

这是因为仅仅这样安装只是安装了其python接口,并没有将assimp库文件安装。通常我们需要下载其源码自己编译,对于windows系统就是编译生成其对应的.dll文件。下载地址:http://assimp.sourceforge.net/main_downloads.html

由于assimp使用cmake管理的,所以在编译assmip前,先确保cmake安装。关于cmake在windows下如何于VS协同使用可以参考如下链接:CMake入门1——CMake与VS编译器和nmake的结合使用

在使用cmake配置项目的时候,需要注意python的是64bit还是32bit,如我的是64bit,在选择编译器就要选择对应的VS64bit版本,否则python将仍然无法导入assimp:

cmake

如果cmake没有选择正确,而在VS中又强制编译另一个版本的库,则编译时会如下如下错误:

“>x64\Debug\adler32.obj : fatal error LNK1112: 模块计算机类型“x64”与目标计算机类型“X86”冲突”

在编译完成后将生成的.dll库文件如下:

cmake

我们需要将其放入到python能够找到的目录下,我是直接放到site-packages/pyassimp的目录下。

完成上面操作后,可以测试运行如下,检查是否成功导入:

1
2
3
4
5
6
7
8
9
10
11
12
13
import pyassimp

objpath = r'1.obj'
scene = pyassimp.load(objpath)

assert len(scene.meshes)
mesh = scene.meshes[0]
print(mesh)

assert len(mesh.vertices)
print(mesh.vertices[0])

pyassimp.release(scene)

assimp读取模型数据结构

当导入一个模型文件时,即Assimp加载一整个包含所有模型和场景数据的模型文件到一个scene对象时,Assimp会为这个模型文件中的所有场景节点、模型节点都生成一个具有对应关系的数据结构,且将这些场景中的各种元素与模型数据对应起来。下图展示了一个简化,的Assimp生成的模型文件数据结构:

assmip

下载pyassimp源码安装包中,在其中的scripts文件中,提供了使用例子,可以参考其中的代码学习。源码安装地址:https://pypi.org/project/pyassimp/4.1.3/

参考

  1. 用PyOpenGL叩开3D的心扉——OpenGL全解析
  2. OpenGL学习脚印:模型加载初步-加载obj模型(load obj model)
  3. Opengl学习之模型加载——Assimp
Compartir