标题: [技术讨论] [图形/游戏开发]PyOpenGL的实现 [打印本页]
作者: 523066680 时间: 2012-2-16 21:18 标题: [图形/游戏开发]PyOpenGL的实现
本帖最后由 523066680 于 2012-3-8 23:37 编辑
关于OPENGL ,http://zh.wikipedia.org/wiki/OpenGL
OpenGL(全写Open Graphics Library)是个定义了一个跨编程语言、跨平台的编程接口(Application programming interface)的规格,
它用于生成二维、三维图像。这个接口由近三百五十个不同的函数调用组成,用来从简单的图元绘制复杂的三维景象。
而另一种编程接口系统是仅用于Microsoft Windows上的Direct3D。OpenGL常用于CAD、虚拟实境、科学视觉化程式和电子游戏开发。
本人环境 WIN32 Python2.7
以下页面提供了 模块下载、相关文档、GL函数介绍以及对应实例 链接
http://pyopengl.sourceforge.net/
模块(接口)以及源码包下载:
http://pypi.python.org/pypi/PyOpenGL/3.0.1
当然也可以在,开始菜单打开 Python2.7\Module docs 搜索OpenGL并选择安装
实例下载: http://pypi.python.org/pypi/PyOpenGL-Demo
实例中包括了 OPENGL红皮书、NeHe教程、 GLUT库演示 的各种教材对应C语言版本的实例。
图片为demo之一
作者: find 时间: 2012-2-16 21:22
怎样在Windows里面搭建Python环境啊?
作者: find 时间: 2012-2-16 22:22
本帖最后由 523066680 于 2012-2-16 22:34 编辑
http://www.python.org/这个吗?E文不是每个人都看得懂啊
听说有2.x和3.x,初学者应该选择哪个呀?
作者: applba 时间: 2012-2-17 02:11
如果英文好的话,直接从3开始学。
否则从2x学吧,中文的教程相对多一些。
作者: 523066680 时间: 2012-2-19 22:14 标题: Sample.py
本帖最后由 523066680 于 2012-3-8 11:08 编辑
- from OpenGL.GLUT import *
- from OpenGL.GL import *
- import sys
-
- def display():
- glClearColor(0.0,0.0,0.0,0.0) #R,G,B=(0,0,0)=black , Alpha=0
- glClear(GL_COLOR_BUFFER_BIT)
- glColor3f(0.0,1.0,0.0); #R,G,B=(0,1,0)=Green
- glRectf(-0.5,-0.5,0.5,0.5) #Draw a green Rectangle
- glFlush() #将以上的图形绘制到窗口上
-
- glutInit(sys.argv)
- glutInitDisplayMode(GLUT_SINGLE|GLUT_RGBA) #绘图模式,单缓冲,RGBA颜色模式
- glutInitWindowSize(500,500) # size
- glutInitWindowPosition(100,100) # position 位置
- glutCreateWindow("simple") # 建立视窗(并返回一个ID)
- glutDisplayFunc(display) # 注册用于绘图的回调函数
- glutMainLoop() #进入主循环,期间将运行注册的回调函数
复制代码
一个比较简单的opengl程序
有很多的配置过程并没有写出,GL系统会采用隐含的设置。
例如,默认的二维窗口坐标系是[-1,-1] 到 [1,1] ,也就是绘制一个(-1,-1)到 (1,1)的矩形将占据整个窗口
(当然,实际有更多的东西,z轴坐标这里也没有用上,默认区间为0->1 , 绘图默认在z=0的位置)
b 8位整数 signed char GLbyte
s 16位整数 short GLshort
i 32位整数 long GLint, GLsizei
f 32位浮点数 float GLfloat, GLclampf
d 64位浮点数 double GLdouble, GLclampd
ub 8位无符号整数 unsigned char GLubyte, GLboolean
us 16位无符号整数 unsigned short GLushort
ui 32位无符号整数 unsigned long GLuint, GLenum, GLbitfield
作者: 523066680 时间: 2012-2-20 08:43 标题: 概览
本帖最后由 523066680 于 2012-2-20 09:03 编辑
OK,连载不能没了纲领,下面对将要介绍的内容、实例,列一个表单:
基本的视图矩阵设置 (glutDisplayMode 以及空间坐标矩阵配置)
点、线、面,几何形状的描绘
色彩
空间
基本的鼠标、键盘响应函数
显示列表
变换函数(glRotate glTranslate glScale)
视图矩阵堆栈函数
光照
立体图形、曲面 绘制函数
纹理映射
抗锯齿效果
颜色混合(透明效果)
动态模糊
大部分内容我会做一些实例和注释,但是更详细的更多的函数使用以及原理,请参考书籍:
《计算机图形学》 第三版,opengl版
《OpenGL编程指南》现在出到第七版,中文
在第一个sample中,出现了gl打头的函数,以及glut打头的函数,区分在于,gl是opengl的基本函数
完成基本渲染功能,但是它的窗口操作并不是很完整,glut是一个实用工具库,提供了更多的函数扩展,使操作和配置变得简单。
所有的pyopengl函数列表,上面也提供了对应函数的大量的实例
http://pyopengl.sourceforge.net/ ... -3.0/index.xhtml#GL
作者: 523066680 时间: 2012-2-20 22:07 标题: 视口设置、坐标空间定义
编辑:523066680
(这部分不好讲呐。。。 要描述的东西多。按书上的话又有较多的篇幅)
从sample实例中我们看到一个注册回调函数的函数:
glutDisplayFunc(display)
此后每次绘图、重绘,系统都会调用display函数。GL的渲染并不是一下就结束的,他是一个循环
允许你动态的改变场景、物体,实现一些动画效果以及人机交互。
所以它也定义了一系列回调函数,下面先介绍一部分常用的,为了方便描述,用C语言方式:
glutReshapeFunc(void (*func)(int width,int height)) 当人为改变窗口大小时自动调用的函数
glutKeyboardFunc(void (*func)(unsigned char key,int x,int y)) 用户按下按键时调用的函数。
glutMouseFunc(void (*func)(int button,int sate,int x,int y)) 用户按下鼠标时,自动调用的函数
glutIdleFunc(void(*func)(void)); OGL红皮书释义:
当没有其他事件处理时,就调用这个函数,它对于连续的动画或其他背景过程非常有用
这些函数具体做什么,由编写者定义。除了命名是相对自由的,调用参数需要遵照约定,
例如对应窗口修改事件的函数 reshape() 在定义时必须有两个参数,(宽度,高度)
可以是(x,y)也可以是(foo,bar) ,系统会将窗口的像素大小传递给这两个参数,
你可以根据获取的参数对图像做相应改变。例如,窗口缩小时,图像可能应该成比例缩放。
python中就不用显式定义类型了。
还是写个实例+注释吧:
测试了一下,在脚本中添加了中文注释貌似不能直接双击执行,但是可以在IDLE中按F5执行。- from OpenGL.GLUT import *
- from OpenGL.GL import *
- import sys
-
- blue=(0.0,0.0,1.0)
- green=(0.0,1.0,0.0)
- red=(1.0,0.0,0.0)
- color=blue
-
- def display():
- glClearColor(0.0,0.0,0.0,0.0) #背景色=黑色,RGBA全为0
- glClear(GL_COLOR_BUFFER_BIT) #清除颜色缓冲区
- glColor3fv(color) #设置下面绘制物体的颜色
- #f表示参数类型为浮点类型,v表示接受的参数为数组形式
- glRectf(-2.0,-2.0,2.0,2.0)
- glFlush()
-
- def reshape(winx,winy):
- glViewport(0,0,winx,winy) #定义相对视窗大小(像素范围)
- glMatrixMode(GL_PROJECTION) #选择投影矩阵
- glLoadIdentity() #读取规范化的单位矩阵
- glOrtho(-100.0,100.0, -100.0,100.0, 0.0,100.0)
- #定义空间坐标系范围
- glMatrixMode(GL_MODELVIEW) #选择模型视图矩阵
- glLoadIdentity()
-
- def hitkey(key,mousex,mousey):
- global color
- if (key=='q'): #按下q按键时
- glutDestroyWindow(winid) #根据ID结束窗口
- sys.exit()
- elif (key=='b'):
- color=blue
- glutPostRedisplay() #重绘,将调用display
- elif (key=='g'):
- color=green
- glutPostRedisplay()
- elif (key=='r'):
- color=red
- glutPostRedisplay()
-
- def mouse(button,state,x,y):
- pass
-
- glutInit(sys.argv)
- glutInitDisplayMode(GLUT_SINGLE|GLUT_RGBA)
- glutInitWindowSize(500,500)
- glutInitWindowPosition(100,100)
- winid=glutCreateWindow("hitkeytest") #建立窗口的ID返回到winid
- glutDisplayFunc(display)
- glutReshapeFunc(reshape)
- glutKeyboardFunc(hitkey)
- glutMainLoop()
复制代码
按下q退出窗口,r,g,b按键,简单的改变绘制物体的颜色。glutPostRedisplay函数将会调用
glutDisplayFunc注册的绘图函数
关于reshape中的内容注释(暂且可以这么注释):
glViewport(GLint x,GLint y,GLsizei width,GLsizei height)
设定视窗绘图的像素范围,例如glutInitWindowSize(500,500)定义了窗口大小,500X500 的像素平面
坐标形式:左下角起点为0,0 ,右上角顶点为500,500。则:
viewport(250,250,100,100) 将会选择从窗口中间(250,250)到 (250+100,250+100)的像素区域
即 : (250,250)->(350,350) 具体请自己实践一下,不用谢。
glClearColor(0.0,0.0,0.0,0.0)+glClear(GL_COLOR_BUFFER_BIT) 清理所得到的背景颜色,并不仅
限于viewport区域,而是整个500X500。但是你绘图的内容,会在这个像素区域之内。
可以参考这个尝试的结果 http://blog.csdn.net/paktc/article/details/7269049
glOrtho(GLdouble left,GLdouble right, GLdouble bottom,GLdouble top, GLdouble near,GLdouble far)
官方说法:定义了一个正交平行的视景体
其实我一直纠结这个该怎么描述,大概就是这样,glOrtho定义一个矩形空间,同时定义好的是空间坐标
范围。你可以依据这个空间坐标绘制任何物体,可以说是与平台无关的,但是超出空间的部分将被截去。
然后,图像终究是要显示在屏幕上的,这个空间将通过一定的形式映射到viewport定义的像素区域。
成为眼前的画面。所以,假如你定义了一个
left=-500,right=500,bottom=-500,top=500,near=0,far=500 的空间,其精细度虽然可以是任意的,
但正面图像最终会被映射到{这里的实例是 (250,250)->(350,350) 也就是100X100的}像素区间上。
这时绘制一个-500,-500->500,500的矩形,映射过来,刚好占领100X100像素区间。
Z轴的事情,一拖再拖,以后再说,我是IF_EXIST兼523066680
下面附参考图:
作者: 523066680 时间: 2012-2-20 22:40 标题: TRIANGLES and COLOR
本帖最后由 523066680 于 2012-2-21 22:49 编辑
图例中DISPLAY部分的代码,
def display():
glClearColor(0.0,0.0,0.0,0.0)
glClear(GL_COLOR_BUFFER_BIT)
glBegin(GL_TRIANGLES) #绘制几何形状的一个起始标志,GL_TRIANGLES是众多几何形状的常量之一
glColor3f(1.0,0.0,0.0) #定义顶点的颜色
glVertex3f(-50.0,0.0,0.0) #定义顶点坐标
glColor3f(0.0,1.0,0.0)
glVertex3f(50.0,0.0,0.0)
glColor3f(0.0,0.0,1.0)
glVertex3f(0.0,80.0,0.0)
glEnd()
glFlush()
这个例子中为了同时说明颜色,在三个顶点前面都设置了不同的颜色。
gl中的颜色设置是这样的,设置了一个颜色后,接下来的所有几何都将采用这种颜色
直到设置了下一个颜色。
这里使用的是RGB混合搭配的方式,(另一种是颜色索引模式),RGB比较直观,
可以自己预定需要的颜色(通过不同颜色的分量分配)。 其R,G,B取值范围为0.0-1.0之间。
0.0,0.0,0.0为黑色 1.0,1.0,1.0为白色 0.5,0.5,0.5为灰色。。。。
然后,如果一个几何形状,一条直线的两个、多个顶点设置了不同的颜色,
GL默认采用平滑(线性)过渡的方式进行渲染,得到一个比较柔和的效果。
是否手工设置着色方式,可以通过这个函数定义:glShadeModel(mode) mode为常量 :
GL_FLAT 、 GL_SMOOTH
如果在绘制三角形的例子中采用了GL_FLAT,将得到一个蓝色三角形。因为最后的颜色为蓝色
具体参考 http://pyopengl.sourceforge.net/ ... /glShadeModel.xhtml
绘制基本形状的过程:
由glBegin(mode)开始,
glVertex函数负责设置几何的顶点
由glEnd()结束。 glBegin的参数决定了绘制的几何类型。其参数mode选项如下:
GL_POINTS
GL_LINES
GL_LINE_STRIP
GL_LINE_LOOP
GL_TRIANGLES
GL_TRIANGLE_STRIP
GL_TRIANGLE_FAN
GL_QUADS
GL_POLYGON
glVertex 的C版本函数定义:
void glVertex[234]{sifd}(TYPE coords);
void glVertex[234]{sifd}v(const TYPE* coords);
[此部分待编辑]
绘制形状对应类型如下图(引用OPENGL红皮书英文版第七版):
作者: 523066680 时间: 2012-3-8 22:52 标题: 旋转变换以及平移
本帖最后由 523066680 于 2012-3-8 23:16 编辑
- from OpenGL.GLUT import *
- from OpenGL.GL import *
- from OpenGL.GLU import gluLookAt
- import time
- from math import sqrt,tan
- import sys
-
- import math
- winid=0
- Rx,Ry,Rz=(0.0,0.0,0.0)
-
- def init():
- glClearColor(0.0,0.0,0.0,0.0)
- glEnable(GL_DEPTH_TEST)
-
- def display():
- global Rx,Ry,Rz
- length=300.0
- y=length*sqrt(3.0)/2.0
- x=length/2.0
- movex=x/sqrt(3.0)
- glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)
-
- glPushMatrix()
- glRotatef(Rx,1.0,0.0,0.0)
- glRotatef(Ry,0.0,1.0,0.0)
- glRotatef(Rz,0.0,0.0,1.0)
- glTranslatef(0.0,-movex,0.0)
- glBegin(GL_TRIANGLES)
- glColor3f(1.0,0.0,0.0);glVertex3f(-x,0.0,-1.0)
- glColor3f(0.0,1.0,0.0);glVertex3f(0.0,y,-1.0)
- glColor3f(0.0,0.0,1.0);glVertex3f(x,0.0,-1.0)
- glEnd()
-
- glPopMatrix()
-
- glutSwapBuffers()
-
- def free():
- global Rx,Ry,Rz
- if Rx<360:
- Rx+=1.0
- elif Ry<360:
- Ry+=1.0
- elif Rz<360:
- Rz+=1.0
- else:
- Rx,Ry,Rz=(0.0,0.0,0.0)
- time.sleep(0.01)
- glutPostRedisplay()
-
-
- def hitkey(key,mousex,mousey):
- print key,mousex,mousey
- if key=='q':
- glutDestroyWindow(winid)
- sys.exit()
-
- def reshape(winx,winy):
- fa=500.0;
- glMatrixMode(GL_PROJECTION)
- glLoadIdentity()
- glOrtho(-500,500,-500,500,-10.0,fa)
- glMatrixMode(GL_MODELVIEW)
- glLoadIdentity()
- gluLookAt(0.0,0.0,200.0, 0.0,0.0,0.0, 0.0,1.0,200.0)
-
- glutInit(sys.argv)
- glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGBA|GLUT_DEPTH)
- glutInitWindowSize(500,500)
- glutInitWindowPosition(100,100)
- winid=glutCreateWindow("1")
- init()
- glutDisplayFunc(display)
- glutIdleFunc(free)
- glutKeyboardFunc(hitkey)
- glutReshapeFunc(reshape)
- glutMainLoop()
复制代码
作者: 523066680 时间: 2012-3-8 22:56
据说新版本的OPENGL会除去 ROTATEF 函数,一些转换算法将由手工实现……
不过入门嘛,捡着简单的先用着,以后再深入。
作者: 523066680 时间: 2012-4-3 22:20 标题: 题外篇:正二十面体的坐标取值:
本帖最后由 523066680 于 2012-4-3 23:29 编辑
题外篇:正二十面体的坐标取值:
资料收集/整理:[email]523066680@163.com[/email]
红皮书中举了个绘制正二十面体的例子,部分代码如下
(参见“2.10 创建多边形表面模型的一些提示”)- #define X .525731112119133606
- #define Z .850650808352039932
-
- static GLfloat vdata[12][3] = {
- {-X, 0.0, Z}, {X, 0.0, Z}, {-X, 0.0, -Z}, {X, 0.0, -Z},
- {0.0, Z, X}, {0.0, Z, -X}, {0.0, -Z, X}, {0.0, -Z, -X},
- {Z, X, 0.0}, {-Z, X, 0.0}, {Z, -X, 0.0}, {-Z, -X, 0.0}
- };
-
- static GLuint tindices[20][3] = {
- {1,4,0}, {4,9,0}, {4,5,9}, {8,5,4}, {1,8,4},
- {1,10,8}, {10,3,8}, {8,3,5}, {3,2,5}, {3,7,2},
- {3,10,7}, {10,6,7}, {6,11,7}, {6,0,11}, {6,1,0},
- {10,1,6}, {11,0,9}, {2,11,9}, {5,2,9}, {11,2,7}
- };
-
- int i;
- glBegin(GL_TRIANGLES);
- for (i = 0; i < 20; i++) {
- /* color information here */
- glVertex3fv(&vdata[tindices[i][0]][0]);
- glVertex3fv(&vdata[tindices[i][1]][0]);
- glVertex3fv(&vdata[tindices[i][2]][0]);
- }
- glEnd();
复制代码
上面引用了两个常量
#define X .525731112119133606
#define Z .850650808352039932
原书的解释是
我们为X 和Y 选择了两个似乎很奇怪的数,其用意在于使原点到这二十面体的每个顶点的距离均为1.0。
具体的由来我进行了一番探索
英文页面 http://en.wikipedia.org/wiki/Icosahedron
若以正二十面体的中心为原点,
各顶点的坐标分别为
(0,±1,±Φ)
(±1,±Φ,0)
(±Φ,0,±1)
此Φ = (1+√5)/2,即黄金分割数。
这些顶点能组成一些黄金矩形。
也就是说 正二十面体由三个正交黄金矩形顶点连结而成,现在坐标好找了。
至于为什么。。。。。 暂未找到理论
用正二十面体细分,来绘制球体,为了使“球体”的半径为一,需要对
(0,±1,±Φ)
(±1,±Φ,0)
(±Φ,0,±1)
进行规范化
欢迎光临 批处理之家 (http://bbs.bathome.net/) |
Powered by Discuz! 7.2 |