计算机图形学 -- 变换之旋转一 [金字塔旋转] [各种详解哦]
来源:互联网 发布:知乎765心理学综合 编辑:程序博客网 时间:2024/05/22 07:02
OpenGL之变换
这一次用到的有双缓冲、双缓存技术,空闲调用函数,激活函数(启用功能),平移和旋转等
Code:
#include<GL/glut.h>#include<stdlib.h>#pragma comment(linker,"/subsystem:\"windows\" /entry:\"mainCRTStartup\"") GLfloat rtri;//金字塔旋转角度,==这个东西叫金字塔貌似不怎么样。。。只是因为底面没有填充。。void init(){glClearColor(0.0f,0.0f,0.0f,0.0f);glShadeModel(GL_SMOOTH);//GL_FLAT和GL_SMOOTH在这里的区别很明显哟glEnable(GL_DEPTH_TEST);/*激活深度测试,也就是,如果通过比较后深度值发生变化了,会进行更新深度缓冲区的操作。启动它,OpenGL就可以跟踪Z轴上的像素,这样,它只会在那个像素前方没有东西时,才会绘画这个像素。通俗的说,就是根据坐标的远近自动隐藏被遮住的图形(材料)*/ }void mydisplay(){glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);glLoadIdentity();glTranslatef(0.0f,0.2f,-4.0f);//平移,三个方向的偏移量,缩小一下glRotatef(rtri,0.0f,1.0f,0.0f);//旋转,沿各个不同方向glBegin(GL_TRIANGLES);glColor3f(1.0f,0.0f,0.0f);glVertex3f(0.0f,1.0f,0.0f);glColor3f(0.0f,1.0f,0.0f);glVertex3f(-1.0f,-1.0f,1.0f);glColor3f(0.0f,0.0f,1.0f);glVertex3f(1.0f,-1.0f,1.0f);glColor3f(1.0f,0.0f,0.0f);glVertex3f(0.0f,1.0f,0.0f);glColor3f(1.0f,0.0f,1.0f);glVertex3f(1.0f,-1.0f,1.0f);glColor3f(0.0f,1.0f,0.0f);glVertex3f(1.0f,-1.0f,-1.0f);glColor3f(1.0f,0.0f,0.0f);glVertex3f(0.0f,1.0f,0.0f);glColor3f(0.0f,1.0f,0.0f);glVertex3f(1.0f,-1.0f,-1.0f);glColor3f(0.0f,0.0f,1.0f);glVertex3f(-1.0f,-1.0f,-1.0f);glColor3f(1.0f,0.0f,0.0f);glVertex3f(0.0f,1.0f,0.0f);glColor3f(0.0f,0.0f,1.0f);glVertex3f(-1.0f,-1.0f,-1.0f);glColor3f(0.0f,1.0f,0.0f);glVertex3f(-1.0f,-1.0f,1.0f);glEnd();rtri += 0.1f;//这家伙可以控制旋转角度,也就是速度,单位时间内转过的角度,当然越大越快了glutSwapBuffers();}void reshape(int width,int height) { glViewport(0,0,width,height); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(45.0f,(GLfloat)width/(GLfloat)height,0.1f,100.0f);glMatrixMode(GL_MODELVIEW);glLoadIdentity(); } int main(int argc,char * argv[]){glutInit(&argc,argv);glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);glutInitWindowPosition(300,100);glutInitWindowSize(650,500);glutCreateWindow("change");init();glutDisplayFunc(mydisplay);glutReshapeFunc(reshape);glutIdleFunc(mydisplay);//设置空闲时调用的函数,idle就是空闲的、闲置的意思glutMainLoop();return 0;}
下面来说说以前没见过的函数的用法~
(各处总结来的,讲的都特别好~)
双缓冲技术
在计算机上的动画与实际的动画有些不同:实际的动画都是先画好了,播放的时候直接拿出来显示就行。
计算机动画则是画一张,就拿出来一张,再画下一张,再拿出来。
如果所需要绘制的图形很简单,那么这样也没什么问题。
但一旦图形比较复杂,绘制需要的时间较长,问题就会变得突出。
让我们把计算机想象成一个画图比较快的人,
假如他直接在屏幕上画图,而图形比较复杂,则有可能在他只画了某幅图的一半的时候就被观众看到。
而后面虽然他把画补全了,但观众的眼睛却又没有反应过来,还停留在原来那个残缺的画面上。
也就是说,有时候观众看到完整的图象,有时却又只看到残缺的图象,这样就造成了屏幕的闪烁。
如何解决这一问题呢?
我们设想有两块画板,画图的人在旁边画,画好以后把他手里的画板与挂在屏幕上的画板相交换。
这样以来,观众就不会看到残缺的画了。这一技术被应用到计算机图形中,称为双缓冲技术。
即:在存储器(很有可能是显存)中开辟两块区域,一块作为发送到显示器的数据,一块作为绘画的区域,
在适当的时候交换它们。由于交换两块内存区域实际上只需要交换两个指针,
这一方法效率非常高,所以被广泛的采用。
注意:虽然绝大多数平台都支持双缓冲技术,但这一技术并不是 OpenGL 标准中的内容。
OpenGL 为了保证更好的可移植性,允许在实现时不使用双缓冲技术。当然,我们常用
的 PC 都是支持双缓冲技术的。
要启动双缓冲功能,最简单的办法就是使用 GLUT 工具包。我们以前在 main 函数里面
写:glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE);
其中 GLUT_SINGLE 表示单缓冲,如果改成 GLUT_DOUBLE就是双缓冲了。
当然还有需要更改的地方——每次绘制完成时,我们需要交换两个缓冲区,把绘制好的
信息用于屏幕显示(否则无论怎么绘制,还是什么都看不到)。如果使用 GLUT 工具包,
也可以很轻松的完成这一工作,只要在绘制完成时简单的调用 glutSwapBuffers函数就可
以了。-- 交换双缓存函数
总之一句话,使用双缓存,以避免把计算机作图的过程都表现出来,或者为了平滑地实现动画。
GLUT_DEPTH 和 GL_DEPTH_TEST
在glutInitDisplayMode()参数说明GLUT_DEPTH,表明窗口使用深度缓存
在glEnable里激活GL_DEPTH_TEST,说明启用深度测试,也就是,如果通过比较后深度值发生变化了,会进行更新深度缓冲区的操作。启动它,OpenGL就可以跟踪Z轴上的像素,这样,它只会在那个像素前方没有东西时,才会绘画这个像素。通俗的说,就是根据坐标的远近自动隐藏被遮住的图形(材料)
在glutInitDisplayMode()里还有很多别的参数如下:
glEnable用于启用各种功能。具体功能由参数决定。意思就是我让你复活了!
与glDisable相对应。glDisable用以关闭各项功能,我又让你死了
在glEnable()里也有很多可以用,如下所示
启用图形切割管道。这里指六种缓存管道
反射要求由函数glColorMaterial进行设定。
根据坐标的远近自动隐藏被遮住的图形(材料)
例如距离越远越模糊
光源要求由函数glLight函数来完成
启用glEvalCoord1,glEvalMesh1,glEvalPoint1
生成RGBA曲线
启用glEvalCoord1,glEvalMesh1,glEvalPoint1
生成颜色索引曲线
启用glEvalCoord1,glEvalMesh1,glEvalPoint1
生成法线
启用glEvalCoord1,glEvalMesh1,glEvalPoint1
生成文理坐标
启用glEvalCoord1,glEvalMesh1,glEvalPoint1
生成文理坐标
启用glEvalCoord1,glEvalMesh1,glEvalPoint1
生成文理坐标
启用glEvalCoord1,glEvalMesh1,glEvalPoint1
生成文理坐标
启用glEvalCoord1,glEvalMesh1,glEvalPoint1
在三维空间里生成曲线
启用glEvalCoord1,glEvalMesh1,glEvalPoint1
在四维空间里生成法线
启用glEvalCoord2,glEvalMesh2,glEvalPoint2
生成RGBA曲线
启用glEvalCoord2,glEvalMesh2,glEvalPoint2
生成颜色索引
启用glEvalCoord2,glEvalMesh2,glEvalPoint2
生成法线
启用glEvalCoord2,glEvalMesh2,glEvalPoint2
生成纹理坐标
启用glEvalCoord2,glEvalMesh2,glEvalPoint2
生成纹理坐标
启用glEvalCoord2,glEvalMesh2,glEvalPoint2
生成纹理坐标
启用glEvalCoord2,glEvalMesh2,glEvalPoint2
生成纹理坐标
启用glEvalCoord2,glEvalMesh2,glEvalPoint2
在三维空间里生成曲线
启用glEvalCoord2,glEvalMesh2,glEvalPoint2
在三维空间里生成曲线
这里再说清楚一下glClear和glLoadIdentity这两个函数的作用
glClear函数的作用是用当前缓冲区清除值,也就是函数所指定的值来清除指定的缓冲区
可以使用 | 运算符组合不同的缓冲标志位,表明需要清除的缓冲,
例如glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)表示要清除颜色缓冲以及深度缓冲,可以使用以下标志位
GL_COLOR_BUFFER_BIT: 当前可写的颜色缓冲
GL_DEPTH_BUFFER_BIT: 深度缓冲
GL_ACCUM_BUFFER_BIT: 累积缓冲
GL_STENCIL_BUFFER_BIT: 模板缓冲
glLoadIdentity:
当调用glLoadIdentity()之后,实际上将当前的用户坐标系的原点移到了屏幕中心,
类似于一个复位操作,OpenGL屏幕中心的坐标值是X和Y轴上的0.0f点。
X坐标轴从左至右,Y坐标轴从下至上,Z坐标轴从里至外。
中心左面的坐标值是负值,右面是正值。
移向屏幕顶端是正值,移向屏幕底端是负值。
移入屏幕深处是负值,移出屏幕则是正值。
glTranslatef(x,y,z):使原点沿着 X, Y 和 Z 轴移动。
注意在glTranslatef(x, y, z)中,当您移动的时候,您并不是相对屏幕中心移动,而是相对与当前所在的屏幕位置。
其作用就是将你绘点坐标的原点在当前原点的基础上平移一个(x,y,z)向量。
glRotatef(angle, x, y, z)
与glTranslatef(x, y, z)类似,glRotatef(angle, x, y, z)也是对坐标系进行操作。
旋转轴经过原点,方向为(x,y,z),旋转角度为angle,方向满足右手定则。
当然,如果在旋转函数后面再加一句glLoadIdentity()抚慰函数,就等于撤销了旋转操作,图形就不会旋转了
还有要再说一下glMatrixMode()及其参数的作用:
glMatrixMode,这个函数其实就是对接下来要做什么进行一下声明,也就是在要做下一步之前告诉计算机我要对“什么”进行操作了,这个“什么”在glMatrixMode的“()”里的选项(参数)有,GL_PROJECTION,GL_MODELVIEW和GL_TEXTURE
如果参数是GL_PROJECTION,这个是投影的意思,就是要对投影相关进行操作,也就是把物体投影到一个平面上,就像我们照相一样,把3维物体投到2维的平面上。这样,接下来的语句可以是跟透视相关的函数,比如glFrustum()或gluPerspective();
如果参数是GL_MODELVIEW,这个是对模型视景的操作,接下来的语句描绘一个以模型为基础的适应,这样来设置参数,接下来用到的就是像gluLookAt()这样的函数;
若是GL_TEXTURE,就是对纹理相关进行操作;
顺便说下,OpenGL里面的操作,很多是基于对矩阵的操作的,比如位移,旋转,缩放,所以,这里其实说的规范一点就是glMatrixMode是用来指定哪一个矩阵是当前矩阵,而它的参数代表要操作的目标,GL_PROJECTION是对投影矩阵操作,GL_MODELVIEW是对模型视景矩阵操作,GL_TEXTURE是对纹理矩阵进行随后的操作。
gluPerspective(GLdouble fovy,GLdouble aspect,GLdouble zNear,GLdouble zFar)
fovy,这个最难理解,我的理解是,眼睛睁开的角度,即,视角的大小,如果设置为0,相当你闭上眼睛了,
所以什么也看不到,如果为180,那么可以认为你的视界很广阔,
aspect,这个好理解,就是实际窗口的纵横比,即x/y
zNear,表示你近处,的裁面,眼睛距离近处的距离,假设为10米远,请不要设置为负值,OpenGl就傻了,不知道怎么算了,
zFar表示远处的裁面,假设为1000米远,
首先假设我们现在距离物体有50个单位距离远的位置,在眼睛睁开角度设置为45时,我们可以看到,在远处一个球,,
现在我们将眼睛再张开点看,将"眼睛睁开的角度"设置为178(180度表示平角,那时候我们将什么也看不到,眼睛睁太大了,眼大无神)我们只看到一个点,,,,,,,,,,,,,,,,,,,,,,,,,,,
因为我们看的范围太大了,这个球本身大小没有改变,但是它在我们的"视界"内太小了,
在我们距离该物体3000距离远,"眼睛睁开的角度"为1时,我们似乎走进了这个球内,这个是不是类似于相机的焦距?
当我们将"透视角"设置为0时,我们相当于闭上双眼,这个世界清静了,
我们什么也看不到,,,,,,,,,
之前是在 main 函数里写:glutDisplayFunc(&myDisplay);
为什么我们不直接调用myDisplay,而要采用这种看似“舍近求远”的做法呢?
原因在于——我们自己的程序无法掌握究竟什么时候该绘制窗口。
假如你的程序窗口碰巧被别的窗口遮住了,后来用户又把原来遮住的窗口移开,这时你的窗口需要重新绘制。
很不幸的,你无法知道这一事件发生的具体时间。因此这一切只好委托操作系统来办了。
既然都可以交给操作系统来代办了,那让整个循环运行起来的工作是否也可以交给操作系统呢?
我的下载不能停下来吧?我的 mp3播放还不能给耽搁了。
总不能因为我们的动画,让其他的工作都停下来。
这里的“在 CPU 空闲的时间绘制”和“在需要绘制的时候绘制”有些共通,都是“在XX 时间做 XX 事”,
GLUT 工具包也提供了一个比较类似的函数:glutIdleFunc,表示在 CPU 空闲的时间调用某一函数。
其实 GLUT 还提供了一些别的函数,例如“在键盘按下时做某事”等
- 计算机图形学 -- 变换之旋转一 [金字塔旋转] [各种详解哦]
- 计算机图形学 -- 变换之旋转二 [鼠标操作]
- 计算机图形学,各种变换
- 计算机图形学实验-几何图形的比例和旋转变换
- 计算机图形学-旋转彩色正方体
- 计算机图形学-旋转四棱锥
- 计算机图形学基础(一) 三角形绘制旋转和迷宫算法
- 计算机图形学(四)_几何变换_1_基本的二维几何变换(二)_旋转
- 计算机图形学 学习笔记(七):二维图形变换:平移,比例,旋转,坐标变换等
- 计算机图形学之二维平移旋转缩放代码
- 计算机图形学 几何图形变换算法(缩放、旋转和平移) C语言编写
- 计算机图形学_矩形的旋转
- 计算机图形学10一一理解旋转矩阵
- 旋转变换(一)旋转矩阵
- 旋转变换(一)旋转矩阵
- 旋转变换(一)旋转矩阵
- 旋转变换(一)旋转矩阵
- 旋转变换(一)旋转矩阵
- 拷贝构造函数与赋值运算符的区别
- android:数据存储和访问
- 国内IT行业技术会
- poj 1753 解题报告
- 正则表达式(一)获得特定字符
- 计算机图形学 -- 变换之旋转一 [金字塔旋转] [各种详解哦]
- 自由派:甘愿被洋奴三炮绑架
- JavaScript jQuery (1) 入门
- 网页上播放flv
- Eclipse快捷键大全
- 深刻理解Python中的元类(metaclass)
- 怎么找到android系统input命令的实现代码
- 2011斯坦福大学iOS应用开发教程学习笔记(第七课)Pad和iPhone的通用程序
- Ojbect-C2 5、NSSet和NSMutableSet集合的使用