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. |
|