本文转自:http://eyehere.net/2011/learn-opengl-3d-by-pyopengl-4/

图元

上一次,我们有了一个足够3D的程序了,虽然很漂亮,但是那个茶壶并不是我们画出来的,glut带给我们的便利而已。从现在开始我们就得自己动手丰衣足食了,为了达到这一点,我们得再了解一些OpenGL的一些知识。

如右图所示,你必须知道构成我们3D图像的最小单位,它们往往被称为图元。

  • 点,在OpenGL中,这是最基本的图元,比如说图中红色的那个点。
  • 线,比如左图中粉色的那根。我们可以看到,两个点定一条线,不过从一个点上可以发射出任意多的线,所以点和线的数量关系并不是确定的。
  • 多边形是最为复杂的图元,比如左图的黄色梯形。和数学中的多边形含义是一样的。

在标准OpenGL中,既然称为多边形,自然不一定是四个边,可以是任意,标准OpenGL中还有一个专门的矩形绘图函数glRect*,不过在OpenGL ES中,多边形就是指三角形,出于各种考虑,不支持更复杂的多边形。

观察左边的图像,这是一个球形,不过每一个小多边形都是平面,这么一个个的小平面,最终组成了球面。这是一个非常重要的概念,在计算机图像中,曲线和曲面是非常难表示的,真正的数学概念上的“圆”,相邻的三个点不在一条直线上,球也类似。但是如果在计算机上这么处理的话,代价太大了,所以我们总是把一个光滑的线和面分解成多个断线或小平面,就好像一个看台,远看是圆形的,但是实际上是由一块块的砖拼成的。当然这是比较一般的做法,OpenGL也有真正意义上的曲线曲面的表示方法,比如如雷贯耳的“贝塞尔曲线/面”,这个是比较高级的话题,再议。

如上图,一个球形由不同数量的平面组成时的状况,下面的数字标示围绕一周的多边形的数量,也就是上面和下面顶点发散出三角形的数量,如果给个名词的话,我们可以叫它“段”。我们可以看到,当段数为32的时候,很漂亮的球形;16的时候,还行,能分辨出这是球形;8的时候就有些丢人了;而没人会把段数为4的那个物体叫球体,叫水晶体才能接受。

绘制图元

因为点是最为基础的图元,我们得首先了解它:

glVertex(x, y[, z[, w]])

我们最多可以使用4个参数,一般2D的用两个,形式为glVertex2f(x, y);3D的用三个,自然就是glVertex3f(x, y, z);w在我们用到的时候再说。

那么画点是不是就调用这个函数就可以了呢?虽然差不多但可惜实际不完全是,这里有一个初学者感到很困惑的东西再里头,OpenGL所有的绘图指令,都必须包含在glBegin()和glEnd()之间!为什么要这样?glBegin()的参数告诉OpenGL这些点最终的绘制方法,如果单纯是画点GL_POINTS,这画三个点就是孤立的画出来,如果是其他的比如多边形GL_POLYGON,那么画三个点结果就是组成一个三角形。虽然绘制点的方法完全一样,因为给的参数不同而导致了不同的结果。glBegin()提供的图元绘图方式如下:

参数 含义
GL_POINTS 单个顶点集
GL_LINES 线段
GL_LINE_STRIP 不闭合的连续线段
GL_LINE_LOOP 闭合的线段
GL_POLYGON 多边形
GL_TRAINGLES 独立三角形
GL_TRAINGLE_STRIP 三角形串,线性连续
GL_TRAINGLE_FAN 三角形串,扇状连续
GL_QUADS 独立四边形
GL_QUAD_STRIP 四边形串

很明显,这样说,原来理解的人都要迷糊半天,所以“一图胜千言”来了,请参考下图理解,

如果还有有些疑惑,可以使用下面的程序,修改加深理解。

  1. from OpenGL.GL import *
  2. from OpenGL.GLU import *
  3. from OpenGL.GLUT import *
  4. def init():
  5. glClearColor(0.0, 0.0, 0.0, 1.0)
  6. gluOrtho2D(-1.0, 1.0, -1.0, 1.0)
  7. def drawFunc():
  8. glClear(GL_COLOR_BUFFER_BIT)
  9. glBegin(GL_LINES)
  10. glVertex2f(-1.0, 0.0)
  11. glVertex2f(1.0, 0.0)
  12. glVertex2f(0.0, 1.0)
  13. glVertex2f(0.0, -1.0)
  14. glEnd()
  15. glPointSize(5.0)
  16. glBegin(GL_POINTS)
  17. glColor3f(1.0, 0.0, 0.0)
  18. glVertex2f(0.3, 0.3)
  19. glColor3f(0.0, 1.0, 0.0)
  20. glVertex2f(0.6, 0.6)
  21. glColor3f(0.0, 0.0, 1.0)
  22. glVertex2f(0.9, 0.9)
  23. glEnd()
  24. glColor3f(1.0, 1.0, 0)
  25. glBegin(GL_QUADS)
  26. glVertex2f(-0.2, 0.2)
  27. glVertex2f(-0.2, 0.5)
  28. glVertex2f(-0.5, 0.5)
  29. glVertex2f(-0.5, 0.2)
  30. glEnd()
  31. glColor3f(0.0, 1.0, 1.0)
  32. glPolygonMode(GL_FRONT, GL_LINE)
  33. glPolygonMode(GL_BACK, GL_FILL)
  34. glBegin(GL_POLYGON)
  35. glVertex2f(-0.5, -0.1)
  36. glVertex2f(-0.8, -0.3)
  37. glVertex2f(-0.8, -0.6)
  38. glVertex2f(-0.5, -0.8)
  39. glVertex2f(-0.2, -0.6)
  40. glVertex2f(-0.2, -0.3)
  41. glEnd()
  42. glPolygonMode(GL_FRONT, GL_FILL)
  43. glPolygonMode(GL_BACK, GL_LINE)
  44. glBegin(GL_POLYGON)
  45. glVertex2f(0.5, -0.1)
  46. glVertex2f(0.2, -0.3)
  47. glVertex2f(0.2, -0.6)
  48. glVertex2f(0.5, -0.8)
  49. glVertex2f(0.8, -0.6)
  50. glVertex2f(0.8, -0.3)
  51. glEnd()
  52. glFlush()
  53. glutInit()
  54. glutInitDisplayMode(GLUT_RGBA|GLUT_SINGLE)
  55. glutInitWindowSize(400, 400)
  56. glutCreateWindow("Sencond")
  57. glutDisplayFunc(drawFunc)
  58. init()
  59. glutMainLoop()

运行结果如右图:

分割线:

由12~17行绘制的,这里我们没有指定颜色,所以使用OpenGL默认的颜色系统,即前景白色,背景黑色。

右上区域:

由19~27绘制,glPointSize(5.0)指明每个点的大小为5个像素(否则默认是一个像素看不清楚,当然不是必要的)。而glColor3f(R, G, B)指定了绘制的颜色,这里的RGB都是0~1之间的浮点数,注意这里的排布,glColorx是可以放在glBegin()和glEnd()里面的,而glPointSize()则不是。这里简单画了三个不同颜色的点。

左上区域:

我们使用GL_QUADS画了一个黄色的矩形,很简单,看起来没有什么特别要说明的。真的如此么?我们画了几个点,指定矩形,但是注意到了么,这个矩形是填充的。也就是说,OpenGL在默认情况下,会填充我们画出来的图形。如何不填充?

下区域:

下面两个图案请合起来看,这两个图形是完全一样的,代码分别为左(37~47)和右(49~58),坐标就是一个正一个负而已,唯一不同的是这里

  1. glPolygonMode(GL_FRONT, GL_LINE)
  2. glPolygonMode(GL_BACK, GL_FILL)

  1. glPolygonMode(GL_FRONT, GL_FILL)
  2. glPolygonMode(GL_BACK, GL_LINE)

这个是什么意思呢?

看看上面解释各种参数的图,我们可以看到这里面的箭头都是逆时针绘制的,这里面是有原因的——“这个世界上没有偶然,有的只有必然”,OpenGL中,每一个面都有正面和反面,这很容易理解,就好像硬币的两面一样。默认情况下,顶点逆时针的那一面,在OpenGL中为正面,当然我们可以更改这种设置,不过何必呢?

glPolygonMode()指定了如何绘制面的方式,GL_LINE为只画线,GL_FILL则是默认的填充。观察一下代码和结果,是否很不错呢?

不过这不是我想说的重点,我们把渲染理解成在面上涂油漆,那么,如果六个面组成了一个盒子,我们给这个盒子上色的时候,一般就是把外面涂一遍就好了,里面都刷岂不是浪费油漆浪费时间?这样一个朴素的道理,在OpenGL里也是适用的,立体的物体都是由面组成的,很多情况下是封闭的,小到球、盒子,大到人体,就是由面组成的闭合物体。

我们可以告诉OpenGL,反面就不要渲染了 ,这叫“剔除(Cull)”使用glCullFace()可以做到这一点,接受的参数为GL_FRONT, GL_BACK, GL_FRONT_AND_BACK,意义的话,一目了然。这里先建立一个概念,具体不过必须要先启用glEnable(GL_CULL_FACE),我们会在用到的时候再详细说明。

PyOpenGL的安装

这里才讲述PyOpenGL的安装有些不应该了,我原以为使用这个东西的人应该会很容易装上,不过既然是“入门教程”,应该想到还是有不少刚刚入门的朋友在,讲一下比较好。

首先PyOpenGL的官方网站,是依附于sourceforge的(好穷啊),网址是http://pyopengl.sourceforge.net/,上面有最新的下载的地址,举个例子http://pypi.python.org/pypi/PyOpenGL/3.0.1,这里面有三个文件PyOpenGL-3.0.1.tar.gz和PyOpenGL-3.0.1.zip是一回事,都是源码,如果你不是Windows,那么就需要下载这个编译安装,如果是的话,就下载PyOpenGL-3.0.1.win32.exe安装,注意这个是32位的。

虽然我的Windows是64位的,Python也有64位的版本,但是Python很多库都是32位的,所以我安装的Python也是32位的,减少了很多麻烦,否则很多时候就是装上能用,也会出现莫名其妙的问题。

至于Linux等,easy_install是个安装Python库很不错的选择,当然直接下载源代码python setup.py也很简单有效,这些通用的方法,我就不多讲了,不明白的请自己google一下。

PyOpenGL之3D界面详解(四)相关推荐

  1. PyOpenGL之3D界面详解(三)

    本文转自:http://eyehere.net/2011/learn-opengl-3d-by-pyopengl-3/ 第一个PyOpenGL程序 说实话我们OpenGL的基础还远远没有学完,不过我在 ...

  2. PyOpenGL之3D界面详解(五)

    本文转自:http://eyehere.net/2013/learn-opengl-3d-by-pyopengl-5/ 我不得不演示几个例子来加深一下之前学习的东西(时隔这么久了,有点难以为继的感觉啊 ...

  3. PyOpenGL之3D界面详解(一)

    本文转自:http://eyehere.net/2011/learn-opengl-3d-by-pyopengl-1/ 承 从pygame的系列教程里3D部分,本想好好说一下OpenGL的,但是感觉这 ...

  4. PyOpenGL之3D界面详解(二)

    本文转自:http://eyehere.net/2011/learn-opengl-3d-by-pyopengl-2/ 每个人都有做3D的潜质 看看这张图片(选自"一秒钟看穿统计陷阱&quo ...

  5. 圆形界面 开启相机_「基础篇三」手机摄影拍照界面详解

    ​[基础篇三]手机摄影拍照界面详解 手机拍照对我们来说已习以为常,每天我们都会用手机相机功能或多或少的拍出几张照片.故手机拍照界面对我们来说也不陌生,但手机拍照界面上的那些按钮,那些功能你都用过吗?你 ...

  6. App Widgets 详解四 RemoteViews、RemoteViewsService和RemoteViewsFactory

    导读 本篇文章将介绍"集合视图",App Widget 复杂布局的实现 App Widget 小部件系列其他文章链接 App Widgets 详解一 简单使用 App Widget ...

  7. Symbian操作系统及操作平台界面详解

    Symbian操作系统及操作平台界面详解 作者:佚名 文章来源:本站原创 点击数: <script src="/Article/GetHits.asp?ArticleID=715&qu ...

  8. java实现标准化考试系统详解(四)-----初始化操作实现

    (一)初始化操作实现 如上图所示当管理员需要更改适用工程.试题数量.考试时间时直接在文本中更改就好我们只需要每次在用户打开程序时初始化这些参数就可以 1.初始化试题模型,这里需要实现随机抽题,方法是用 ...

  9. fifa15服务器维护,菜单界面详解:游戏设置界面_FIFA15系统教程图文攻略(完结)_FIFA15图文全攻略_单机攻略_跑跑车单机游戏网...

    第 4 页 菜单界面详解:游戏设置界面 游戏设置界面 赛事设置 赛事时长:选择3.4.5.6.7.8.9.10.15.20分钟作为比赛半场时间; 赛事难度:基于玩家的FIFA级数选择玩家的AI对手难度 ...

最新文章

  1. [emuch.net]MatrixComputations(1-6)
  2. Codeforces Global Round 13 E. Fib-tree
  3. 在ctex环境下利用Metapost作图
  4. CenterNet2:比强更强的二阶段网络,COCO成绩最高达到56.4mPA
  5. ACM ICPC 2017 Warmup Contest 2[菜鸡选手的成长]
  6. jq 自动滑动轮换(向后插入小块)
  7. Druid:数据库连接池实现技术,由阿里巴巴提供的
  8. GC详解及Minor GC和Full GC触发条件
  9. mysql 记录更新时间_MySQL表内更新时,自动记录时间
  10. react for循环_5个很棒的 React.js 库,值得你亲手试试!
  11. PHP高并发场景的三种解决方案
  12. html面试信息登记表
  13. 计算机考试反思1000,高一期中考试反思1000字,高一学生期中考试总结
  14. 使用mosquitto库命令与腾讯云通信
  15. 开机 服务 自动 bat regedi_android实现通话自动录音服务_Android
  16. BH1750 传感器实战教学 —— 硬件设计篇
  17. 海洋cms宝塔定时linux,海洋CMS使用计划任务实现自动采集/宝塔计划任务自动采集...
  18. #586 – 冒泡事件和隧道事件通常是成对出现(Bubbling and Tunneling Events Are Typically Paired)
  19. 入门GTD时间管理系统必读(链接必读--很完整的一个GTD系统)
  20. matlab 年积日与年月日转换,空间大地测量与GPS导航定位时间系统相互转换,格里高利时通用时儒略日,GPS时,年积日相互转换的源代码程序...

热门文章

  1. STM32F4设置系统时钟源为内部HSI
  2. 201312-2_ISBN号码
  3. 百度统计:网站统计实时访客报告
  4. js时间戳(代码合集)获取(年月日,秒戳,毫秒戳,) - 综合篇
  5. phpcms注入漏洞之文件poster.php
  6. php nginx 实时输出,phpnginx实时输出实现方法分享
  7. 计算机并行处理专业,分布式计算机并行处理技术(论文).doc
  8. java excel导出2007_java操作excel文件,实现批量导出,和导入
  9. 原来如此?修改浏览器滚动条样式
  10. 社区开源版本,基于Springboot精简了代码,改变为单体,方便大家一键启动