原型的杂货铺首页

 
OpenGL编程(4)

 
发表新主题   回复主题    原型的杂货铺首页 -> 软件技术
阅读上一个主题 :: 阅读下一个主题  
作者 正文
klaaa
新手上路


加入时间: 2003/03/15
文章: 8

原币: 25

离线
文章时间: 2003-3-19 周三, 下午7:22    标题: OpenGL编程(4) 引用回复

OpenGL编程(4)

这次我们进入真正的三维世界,例子中将会展示如何使用模型变换来完成我们的三维变换。
这次我们开始解释什么是模型变换。
对于三维世界中的点,我们使用坐标来表示,通常使用三维坐标例如(x,y,z)来表示,不过在几乎所有的3D图形软件包中为了便于计算,使用的全是三维齐次坐标(x,y,z,w),当w不等于0的时候它表示(x/w,y/w,z/w),并且除了数学上的考虑之外w是不能等于零的。
对于一个三维齐次坐标,把它乘以一个4阶方阵,就等价于把它做了一些变换,通过这种变换,我们能够把一个点按一定的方法变换到任何一个地方。例如,我们首先获得了一条线段,然后我们可以通过变换得到任何一条线段,三角形等等也是如此。
通常,我们只需要三种变换:平移、旋转、放缩。OpenGL为这三种变换提供了简单的使用方式。
我们使用这些变换方式影响我们的模型变化矩阵,然后OpenGL就通过模型变换矩阵来给我们的点获得新的坐标。
同时,OpenGL为了保证我们的模型变换矩阵不至于变化之后无法恢复,提供了一个矩阵栈来保存矩阵。
大家还记得下列语句吗?现在我做些解释:
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
首先,指定操作矩阵类型为模型变换矩阵。然后,将这个矩阵置为单位矩阵。一个三维齐次坐标乘以一个单位矩阵,其结果不会产生任何改变,所以单位矩阵可以作为我们矩阵变换的基础。

下面,我们使用例子来演示。
现在,除非需要,否则不再给出完整的源代码而只给出关键的部分了:
void DrawMyLine(void)
{
glBegin(GL_LINES);
glVertex3f(0.0f,20.0f,0.0f);
glVertex3f(20.0f,20.0f,0.0f);
glEnd();
}

void RenderScene(void)
{
glClearColor(0,0,1,1);
glClear(GL_COLOR_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);

glColor3f(1.0f,1.0,1.0f);
glBegin(GL_POINTS);
glVertex3f(0.0f,0.0f,0.0f);
glEnd();

glColor3f(1.0f,1.0f,0.0f);
DrawMyLine();

glPushMatrix();
glTranslatef(30.0f,0.0f,0.0f);
glColor3f(1.0f,0.0f,0.0f);
DrawMyLine();
glPopMatrix();

glPushMatrix();
glTranslatef(-30.0f,-20.0f,0.0f);
glColor3f(0.0f,1.0f,0.0f);
DrawMyLine();
glPopMatrix();

glPushMatrix();
glRotatef(45.0f,0.0f,0.0f,1.0f);
glColor3f(0.0f,0.0f,0.0f);
DrawMyLine();
glTranslatef(-30.0f,0.0f,0.0f);
DrawMyLine();
glPopMatrix();

glPushMatrix();
glTranslatef(0.0f,-50.0f,0.0f);
glScalef(2.0f,1.0f,1.0f);
glColor3f(0.53f,0.5f,0.6f);
DrawMyLine();
glPopMatrix();

glFinish();
glutSwapBuffers();
}

在函数RenderScene中:
glMatrixMode(GL_MODELVIEW);
指定操作矩阵类型为模型变换矩阵。

glPushMatrix();
......
glPopMatrix();
保存矩阵以及恢复矩阵。

glTranslatef(30.0f,0.0f,0.0f);
将变换矩阵施加一个平移,参数表示xyz三个方向的平移量。

glRotatef(45.0f,0.0f,0.0f,1.0f);
将变换矩阵施加一个旋转,第一个参数表示旋转角度,后三个参数表示一个矢量,它是旋转轴。

glScalef(2.0f,1.0f,1.0f);
将变换矩阵施加一个放缩,三项参数分别是xyz三个方向上的放缩倍数。

在这段函数中,每次绘图调用同一个函数DrawMyLine,由于模型变换矩阵的不同,每次回出来的结果也就不一样。

下面大家可以自己自由组合,看看效果吧。

有了一定的变换基础,下面让我们来通过变换来达到三维效果。
我们的方法是把一个旋转施加到所有的变换之上。
下面给出完整的源代码:
// OpenGL04.cpp

#include <windows.h>
#include <gl\gl.h>
#include <gl\glu.h>
#include <gl\glut.h>

void DrawMyLine(void)
{
glBegin(GL_LINES);
glVertex3f(0.0f,20.0f,0.0f);
glVertex3f(20.0f,20.0f,0.0f);
glEnd();
}

void RenderScene(void)
{
glClearColor(0,0,1,1);
glClear(GL_COLOR_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);

glColor3f(1.0f,1.0,1.0f);
glBegin(GL_POINTS);
glVertex3f(0.0f,0.0f,0.0f);
glEnd();

glColor3f(1.0f,1.0f,0.0f);
DrawMyLine();

glPushMatrix();
glTranslatef(30.0f,0.0f,0.0f);
glColor3f(1.0f,0.0f,0.0f);
DrawMyLine();
glPopMatrix();

glPushMatrix();
glTranslatef(-30.0f,-20.0f,0.0f);
glColor3f(0.0f,1.0f,0.0f);
DrawMyLine();
glPopMatrix();

glPushMatrix();
glRotatef(45.0f,0.0f,0.0f,1.0f);
glColor3f(0.0f,0.0f,0.0f);
DrawMyLine();
glTranslatef(-30.0f,0.0f,0.0f);
DrawMyLine();
glPopMatrix();

glPushMatrix();
glTranslatef(0.0f,-50.0f,0.0f);
glScalef(2.0f,1.0f,1.0f);
glColor3f(0.53f,0.5f,0.6f);
DrawMyLine();
glPopMatrix();

glPushMatrix();
glRotatef(45.0f,0.0f,1.0f,0.0f);
glColor3f(0.0f,0.8f,0.8f);
DrawMyLine();
glRotatef(45.0f,0.0f,0.0f,1.0f);
glColor3f(1.0f,0.75f,0.0f);
DrawMyLine();
glPopMatrix();

glFinish();
glutSwapBuffers();
}

void ResetViewport(GLsizei width,GLsizei height)
{
if(height==0)height=1;
if(width==0)width=1;
glViewport(0,0,width,height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-100.0f,100.0f,-100.0f,100.0f,-100.0f,100.0f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}

void RotateScene(int key,int x,int y)
{
static GLfloat xRot=0,yRot=0;
if(key==GLUT_KEY_LEFT)yRot-=3;
if(key==GLUT_KEY_RIGHT)yRot+=3;
if(key==GLUT_KEY_UP)xRot+=3;
if(key==GLUT_KEY_DOWN)xRot-=3;

glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glRotatef(xRot,1.0f,0.0f,0.0f);
glRotatef(yRot,0.0f,1.0f,0.0f);

glutPostRedisplay();
}

int main(void)
{
glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGBA);
glutCreateWindow("OpenGL04");
glutDisplayFunc(RenderScene);
glutReshapeFunc(ResetViewport);
glutSpecialFunc(RotateScene);
glutMainLoop();
return 0;
}

在函数main中,多了一句:
glutSpecialFunc(RotateScene);
这是设置glut的特殊响应函数,它对键盘上非字符键做响应,例如上下左右,F1等等。设置的函数对应格式为void (int key,int x,int y),glut调用它时会传递三个参数,分别是按下的键值,按键时的鼠标x坐标和y坐标。

在函数RotateScene中:
static GLfloat xRot=0,yRot=0;
if(key==GLUT_KEY_LEFT)yRot-=3;
if(key==GLUT_KEY_RIGHT)yRot+=3;
if(key==GLUT_KEY_UP)xRot+=3;
if(key==GLUT_KEY_DOWN)xRot-=3;
这里判断按下的键,并且施加响应的计算,增大或者减少对不同坐标轴的旋转角度。

glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glRotatef(xRot,1.0f,0.0f,0.0f);
glRotatef(yRot,0.0f,1.0f,0.0f);
这里操作模型变换矩阵,先置为单位矩阵,然后绕x轴旋转xRot角度,再绕y轴旋转yRot角度。这样将会使得模型变换矩阵已经旋转过了。

glutPostRedisplay();
通知glut库刷新窗口,即调用RenderScene重新绘图。

由于对模型变换矩阵的变换,所以所有RenderScene里的操作作为整体一开始就有变换,而作为整体之间的各个部分依然由RenderScene来决定。
这里造成的效果就是我们的显示看起来是3D的了。事实上,它们一开始就是3D的,而现在我们可以看出来了。

另外这段程序里有些地方做了一些改变,希望大家自己发现,不再一一叙述。

好,这次就到这里。

klaaa, 2003.03.19.
返回顶端
阅读会员资料 发送站内短信
显示文章:   
发表新主题   回复主题    原型的杂货铺首页 -> 软件技术 所有的时间均为 北京时间
1页,共1

 
论坛转跳:  
不能在本论坛发表新主题
不能在本论坛回复主题
不能在本论坛编辑自己的文章
不能在本论坛删除自己的文章
不能在本论坛发表投票
不能在这个论坛添加附件
可以在这个论坛下载文件


Powered by phpBB 2.0.3 © 2001, 2002 phpBB Group
中文phpBB开发小组提供技术支持