用PyOpenGL叩开3D的心扉——OpenGL全解析(3)

By | 2011/10/20

第一个PyOpenGL程序

说实话我们OpenGL的基础还远远没有学完,不过我在说下去大概就不会有人看了,所以,虽然稍稍有些早,开始我们的第一个程序吧。

from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL.GLUT import *

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

glutInit()
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGBA)
glutInitWindowSize(400, 400)
glutCreateWindow("First")
glutDisplayFunc(drawFunc)
#glutIdleFunc(drawFunc)
glutMainLoop()

结果如上图,虽然很短,相信这里面很多函数大家会觉得陌生,不要紧,这些代码是每个程序中都需要的,基本看两个就OK了,下面来详细说明一下。

先把注释的两个函数给无视了,看看一开始三行的导入,OpenGL一开始是以C写成的,所以OpenGL的程序中绘图的代码也是一大堆的函数,没有什么对象类的,所以我们把相关函数全部倒入,虽然这有些污染环境的感觉和Python的设计机理有些不符,不过这么多年都过来了:),而且OpenGL中的函数都是有前缀的,问题也不大。

OpenGL函数的命名规则

一般的函数命名如下:

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

前缀有gl、glu、aux、glut、wgl、glx、agl等等,分别表示该函数属于OpenGL那个开发库等。所谓开发库,要知道原生的OpenGL是跨平台的,跨平台意味着很多功能是无法实现的,比如说Windows和X-Window的窗口实现机制是不同的,OpenGL并不关心这些东西,只管画图。所以,OpenGL并没有窗口函数,比如无法创建窗口,无法获得输入……这些东西都需要其他的函数库来实现。我们可以用我之前讲述的Pygame来创建窗口,然后用PyOpenGL来绘图,不过咱不能要求每个看PyOpenGL教程的朋友都先看一遍Pygame教程(这样就是强买强卖了不是),所以这里就用OpenGL常用的工具函数库来实现。

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

参数数和参数函数就很好理解了,有点像匈牙利命名法,f说明是个float,i说明是int等等。对Python来说可能不是很重要,不过还是要说明一下,OpenGL函数有d(double)的版本,C/C++语言一般默认浮点数就是double,使用d版本函数可能会显得比较简单,但是我们不推荐。因为OpenGL内部数据都是以float的形式存放的,如果使用double会对性能有一定的影响。

举个例子,glColor3f()表示了该函数属于gl库,参数是三个float型参数指针。类似的函数还有glColor3i,glColor4f等,我们用glColor*()来表示这一类函数。

初始化窗口

11~17行基本也是固定的,

glutInit()是用glut来初始化OpenGL的,所有的问题都交给这个函数吧,基本不用管,虽说可以接受参数的,基本无用。

glutInitDisplayMode(MODE)非常重要,这里告诉系统我们需要一个怎样显示模式。至于其参数GLUT_RGBA就是使用(red, green, blue)的颜色系统。有没有写错?这里有个A啊,不应该是(red, green, blue, alpha)么?大概是历史原因,GLUT_RGBA和GLUT_RGB是其实是等价的(坑爹啊),要想实现Alpha还得用其他的参数。而GLUT_SINGLE意味着所有的绘图操作都直接在显示的窗口执行,相对的,我们还有一个双缓冲的窗口,对于动画来说非常合适。看看用Python和Pygame写游戏-从入门到精通(3)有些说明。

glutInitWindowSize(400, 400)这个函数很容易理解,设置出现的窗口的大小。实际上还有个glutInitWindowPosition()也很常用,用来设置窗口出现的位置。

glutCreateWindow(“First”),一旦调用了,就出现一个窗口了,参数就是窗口的标题。

glutDisplayFunc(func)是glut非常讨人喜欢的一个功能,它注册了一个函数,用来绘制OpenGL窗口,这个函数里就写着很多OpenGL的绘图操作等命令,也就是我们主要要学习的东西。

glutMainLoop(),主循环,一旦调用了,我们的OpenGL就一直运行下去了。和很多程序中的主循环一样,不停的运行,画出即时的图像,处理输入等。

绘图

看看drawFunc里的几句话,这里是实际绘图的函数。

glClear(GL_COLOR_BUFFER_BIT)是把先前的画面给清除,这基本是定律,每次重绘之前都要把原来的画面擦除,否则叠加起来什么都看不出了。glClear一看就知道是OpenGL原生的命令,而参数就是指明要清除的buffer。大家一定会有疑问,我们清除,不就是清除屏幕上的画面么,为什么还要指定?OpenGL的博大精深这里就体现出来了,buffer不仅仅有我们看到的那个GL_COLOR_BUFFER_BIT,OpenGL中还有其他的buffer类型,我们会在后面的章节讲到。

glutWireTeapot(0.5)是glut提供的绘制犹他茶壶的工具函数,茶壶还是相当复杂的一个几何体,用这个函数一下子就画出来了,不过基本也就演示用用。这里是用的线模型,因为没有说光照和材质,如果glutSolidTeapot()画出来就成纸片儿了。

glFlush()似乎不用多说,画了那么多,自然要刷新一下显示。不过,这里的刷新不仅仅是屏幕上的更新,实际上,它是处理OpenGL的渲染流水线,让所有排队中的命令得到执行。OpenGL的渲染流水线是一个很重要的概念,不过这里暂时还不打算多说明,否则对初学者来说,未免有些麻烦了。但是这并不意味着可以无视这些基础,知道怎么做只能让你优秀,知道为什么这么做才能让你卓越

小惊喜

现在你可以把注释的两个语句打开了,执行以下看到什么?旋转的茶壶!不得不说帅多了~

glutIdleFunc(Func)又是一个激动人心的函数,可以让OpenGL在闲暇之余,调用一下注册的函数,这是是产生动画的绝好方法。

glRotatef(1, 0, 1, 0)是一个我们以后会详细讲的函数,简单来说四个参数第一个是角度,后三个是一个向量,意义就是绕着这个向量旋转,这里是绕着Y轴旋转1°。这一度一度的累加,最后使得茶壶围绕Y轴不停的旋转。从这里我们也能看出来,我们指定了一个旋转的角度后,重新绘制并不会复位,而是在上一次旋转的结果上继续旋转。这是一个非常重要的概念,OpenGL是一个状态机,一旦你指定了某种状态,知道再指定位置,它会保持那种状态。不仅仅是旋转,包括以后的光照贴图等等,都遵循这样的规律。

好了,我们有了第一个PyOpenGL程序了,虽然离我们详细中的五光十色的立体世界还有些差距,不过毕竟画了点东西出来了(要知道,犹他茶壶在3D技术发展之初,是里程碑一般的作品)。慢慢的,我们会充实自己的知识,绘制出更靓丽的画面。

16 thoughts on “用PyOpenGL叩开3D的心扉——OpenGL全解析(3)

  1. Zhu

    能不能麻烦详细介绍下python的opengl编译环境设置?? 最常见的都是C++调用opengl的,不知道python如何连接opengl库

    Reply
    1. xishui Post author

      嗯,您说的很对,下一章节追加这个内容。

      Reply
  2. 李昭南

    你好:
    (1)我现在用的python是3.2(win7系统)的在PyOpenGL的官网下了一个PyOpenGL3.0.1.exe的那种包,但好像python3.x的语法有很多与以前的不同了,尤其是try-except那,所以只能一个一个改except Exception, erro—>except Exception as erro
    想问一下,哪里有较新的用于新python的PyOpenGL包?
    (2)我想用python做3D动画电影,你认为这合适吗?说实话我不太清楚现在流行用什么做3D动画电影,一直不知道在哪能找到关于这方面的专业资料。
    (3)还有一个小白的问题哈:我听说有个第三方模块叫“PythonMayavi”就制作3D动画来讲,你认为它和PyOpenGL哪一个更合适新手入门?若往深了做PythonMayavi是否比PyOpenGL更适合制作3D动画电影?
    非常感谢!

    Reply
    1. xishui Post author

      1) 抱歉不知道诶,我不得已一直使用的是2.6~2.7的Python;
      2,3) 如果您想制作3D电影,首先需要了解一些3D或者3Dmax软件的知识,然后好好学习Maya软件,OpenGL是主要用来编程制作游戏或者3D工具的,如果想直接进行3D动画的制作,应该使用专业的软件比较合适。
      不成熟的意见,仅供参考~

      Reply
  3. aaa

    在PyOpenGL3.0.2中什么用不了(我配在python2.6中,是PyOpenGL函数变动还是我的配置的问题?)?在PyOpenGL3.0.1(+python2.7)能使用。

    Reply
  4. aaa

    原因找到了,Python官网下载的PyOpenGL3.0.2里面没有dll文件,我把PyOpenGL3.0.1里的dll文件复制到PyOpenGL3.0.2里,问题解决了。

    Reply
  5. aaaaaaaaaaaaaaaaa

    为什么无法执行呀,本人菜鸟一个,不胜感激!!
    Traceback (most recent call last):
    File “C:UsersYanKunDesktopuntitled-1.py”, line 12, in
    glutInit()
    File “C:Python27libsite-packagesOpenGLGLUTspecial.py”, line 324, in glutInit
    _base_glutInit( ctypes.byref(count), holder )
    TypeError: ‘NoneType’ object is not callable

    Reply
  6. 背景是白的

    执行之后背景是白色的,然后没有看到teapot
    这可能是什么原因的? 我用的是python 2.6 + PyOpenGL 3.0.2

    刚开始也出现了楼上的问题,后来重复安装了Pyopengl 3.0.1之后解决了

    但是一直没有刷出图像来,在drawfunc里面print了下, 每一条都命令都执行过

    请问,可能是什么原因呢?

    Reply
  7. Tacey

    您好,请问pythongl有什么参考书可以看吗(中文和英文的,不懂其他语言),非常感谢。(pygame部分写的很棒,我曾经试着翻译了几章,后来就放弃了(考试挂科了:())

    Reply
    1. xishui Post author

      说句打击我们大家的话,我最近感觉,Python固然是门很优秀的语言,OpenGL也是跨平台的3D事实标准,但是这两者的结合未必就相得益彰。还是要用最合适的语言最做合适的事情,不要迁就P眼OpenGL了吧?要想研究OpenGL,还是看红宝书之类比较好。我也在考虑换个专题和大家聊聊,有推荐话题不:)

      Reply
  8. 失败了!我是个菜鸟,完了卡住了,没法接着学了!
    D:\>python 1.py
    Traceback (most recent call last):
    File “1.py”, line 12, in
    glutInit()
    File “C:\Users\Administrator\AppData\Local\Programs\Python\Python37\lib\site-p
    ackages\OpenGL\GLUT\special.py”, line 333, in glutInit
    _base_glutInit( ctypes.byref(count), holder )
    File “C:\Users\Administrator\AppData\Local\Programs\Python\Python37\lib\site-p
    ackages\OpenGL\platform\baseplatform.py”, line 407, in __call__
    self.__name__, self.__name__,
    OpenGL.error.NullFunctionError: Attempt to call an undefined function glutInit,
    check for bool(glutInit) before calling

    Reply
    1. stone.li

      好消息,使用Python3的同学们也依照这本10年前的教程了!
      使用Python3.x的同学们请如下操作 (搬运自https://stackoverflow.com/questions/39181192/attempt-to-call-an-undefined-function-glutinit, 使用关键字 “python3 pyopengl glut setup ” google 搜索到的结果 )
      1. 首先:卸载PyPi的官方包
      pip uninstall pyopengl-accelerate
      pip uninstall pyopengl
      2. 然后在这个un-official site下载对应版本的包,比如我是Python3.7 64bit (打开终端运行python 首行提示有64bit就为64位),下载PyOpenGL_accelerate-3.1.5-cp37-cp37m-win_amd64.whl 和 PyOpenGL‑3.1.5‑cp37‑cp37m‑win_amd64.whl
      浏览器打开 https://www.lfd.uci.edu/~gohlke/pythonlibs/#pyopengl 下载
      3.安装离线whl (文件地址换成自己的本地文件)
      pip install c:/downloads/PyOpenGL‑3.1.5‑cp37‑cp37m‑win_amd64.whl
      pip install c:/downloads/PyOpenGL_accelerate-3.1.5-cp37-cp37m-win_amd64.whl
      4. Enjoy !

      Reply
  9. run_walker

    写的很详细,帮助很大,成功地转动了茶壶,Thanks。

    Reply

发表评论

您的电子邮箱地址不会被公开。