发信人: rhine (有雨无风), 信区: BorlandDev
标 题: OpenGL在C++Builder中的应用(6)
发信站: 哈工大紫丁香 (Sun Aug 27 06:42:37 2000), 转信
发信人: jinchao (Sonic), 信区: BCB
发信站: BBS 水木清华站 (Fri Jul 30 09:11:27 1999) WWW-POST
(六)坐标变换
从三维几何图元到最终的二维图象,OpenGL要做一系列的变换和处理,其中基本过程
如下:
物体坐标系
| 模视变换
V
眼坐标系
| 投影变换
V
剪裁坐标系
| 透视变换
V
归一化设备坐标系
| 视口变换
V
窗口坐标系
对于OpenGL开发人员,需重点理解的是物体坐标系和模视变换,OpenGL的物体坐
标系使用标准的右手坐标系,点的坐标表示为(x,y,z)或(X,Y,Z,w),这在前面已介绍过,
这几种变换都是通过矩阵运算来完成的,大家最好看看计算机图形学以理解这部分内容,
不过一般的OpenGL程序并不需要给出具体的变换矩阵,请大家回忆一下例一中的
FormResize()函数:
void __fastcall TForm1::FormResize(TObject *Sender)
{
HDC hDC;
hDC=GetDC(this->Handle);
wglMakeCurrent(hDC,m_hRC);
glViewport(0,0,this->ClientWidth,this->ClientHeight);//定义视口范围
glMatrixMode(GL_PROJECTION);//定义当前矩阵为投影变换矩阵
glLoadIdentity(); //装入单位矩阵
glOrtho(0.0f,4.0f,0.0f,4.0f,0.0f,4.0f); //定义裁剪范围
glMatrixMode(GL_MODELVIEW); //定义当前矩阵为模视变换矩阵
glLoadIdentity();
wglMakeCurrent(NULL,NULL);
ReleaseDC(this->Handle,hDC);
}
该函数定义了模视变换矩阵和投影变换矩阵,其中void glMatrixMode(GLenum mode)
用于指定当前变换矩阵,mode取值为:GL_MODELVIEW(模视变换矩阵),GL_PROJECTION(投
影变换矩阵),GL_TEXTURE(纹理坐标变换矩阵),指定当前矩阵后所有操作都针对该矩阵,
函数void glLoadIdentity(void)用于装入标准的4X4单位矩阵(主对角线上元素为1,其
他为0),这是对矩阵必要的初始化。
具体的模视变换由以下几个函数完成:
1. void glTranslate{fd}(TYPE x,TYPE y,TYPE z);
平移变换,x,y,z为在三个方向上的平移距离
2. void glTranslate{fd}(TYPE angle,TYPE x,TYPE y,TYPE z);
旋转变换,angle的单位为度,例如glTranslatef(45.0, 0.0, 0.0,1.0)表示
坐标系绕Z轴旋转45度
3. glScale{fd}(TYPE sx,TYPE sy,TYPE sz);
sx,sy,sz为缩放比例,当是负值时会产生镜象操作
需注意的是,这几种变换是对坐标系操作的,如果对单个对象进行变换,应用函数
void glPushMatrix(void)将当前矩阵入栈,等完成变换后用函数 void
glPopMatrix(void)将矩阵弹出
下面是综合利用这几种变换的一个例子,显示一不断旋转、缩放、平移的立方体,点击
鼠标控制动画的开停,仍以例一为基础,修改如下:
1. 加入全局变量:
//立方体顶点坐标
GLfloat P1[3]={1.0f,-1.0f,-1.0f},P2[3]={1.0f,1.0f,-1.0f},
P3[3]={1.0f,1.0f,1.0f},P4[3]={1.0f,-1.0f,1.0f},
P5[3]={-1.0f,-1.0f,1.0f},P6[3]={-1.0f,1.0f,1.0f},
P7[3]={-1.0f,1.0f,-1.0f},P8[3]={-1.0f,-1.0f,-1.0f};
//顶点的颜色
GLfloat C1[3]={1.0f,1.0f,1.0f},C2[3]={0.0f,0.0f,1.0f},
C3[3]={0.0f,1.0f,0.0f},C4[3]={0.0f,1.0f,1.0f},
C5[3]={1.0f,0.0f,0.0f},C6[3]={1.0f,0.0f,1.0f},
C7[3]={1.0f,1.0f,0.0f},C8[3]={1.0f,1.0f,1.0f};
static GLint AnimationMode=1;//动画开关
2. 修改DrawWithOpenGL()如下:
void TForm1::DrawWithOpenGL()
{
HDC hDC;
hDC = wglGetCurrentDC();
glClearColor(0.0f,0.0f,0.0f,1.0f);
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
glPushMatrix();//当前矩阵入栈
glEnable(GL_DEPTH_TEST);//打开深度检测开关,以进行消隐计算
static GLfloat trans=0.00f,dt=0.01f;
trans+=dt;
if(trans>=1.0)dt=-0.01f;
if(trans<=-1.0f)dt=0.01f;
glTranslatef(trans,trans,0.0f);//平移变换
static GLfloat scale=0.01f,ds=0.01f;
scale+=ds;
if(scale>=1.00f)ds=-0.01f;
if(scale<=0.01f)ds=0.01f;
glScalef(scale,scale,scale);//缩放变换
static GLfloat angle=0.00f,da=2.0f;
angle+=da;
if(angle>=360.0f)angle-=360.0f;
glRotatef(angle,1.0f,0.0f,0.0f);//旋转变换
glRotatef(angle,0.0f,1.0f,0.0f);
glRotatef(angle,1.0f,0.0f,1.0f);
glBegin(GL_QUADS);//以下是绘制立方体的六个面
glColor3fv(C1);glVertex3fv(P1);glColor3fv(C2);glVertex3fv(P2);
glColor3fv(C3);glVertex3fv(P3);glColor3fv(C4);glVertex3fv(P4);
glColor3fv(C5);glVertex3fv(P5);glColor3fv(C6);glVertex3fv(P6);
glColor3fv(C7);glVertex3fv(P7);glColor3fv(C8);glVertex3fv(P8);
glColor3fv(C5);glVertex3fv(P5);glColor3fv(C6);glVertex3fv(P6);
glColor3fv(C3);glVertex3fv(P3);glColor3fv(C4);glVertex3fv(P4);
glColor3fv(C1);glVertex3fv(P1);glColor3fv(C2);glVertex3fv(P2);
glColor3fv(C7);glVertex3fv(P7);glColor3fv(C8);glVertex3fv(P8);
glColor3fv(C2);glVertex3fv(P2);glColor3fv(C3);glVertex3fv(P3);
glColor3fv(C6);glVertex3fv(P6);glColor3fv(C7);glVertex3fv(P7);
glColor3fv(C1);glVertex3fv(P1);glColor3fv(C4);glVertex3fv(P4);
glColor3fv(C5);glVertex3fv(P5);glColor3fv(C8);glVertex3fv(P8);
glEnd();
glPopMatrix();
glFlush();
SwapBuffers(hDC);
}
3.将函数FormResize()中定义裁减范围的一句改为:
glOrtho(-3.0f,3.0f,-3.0f,3.0f,-3.0f,3.0f);
4.加入Timer控件,该其Interval属性为100,并加入如下函数:
//--------------------------------------------------------------------------
void __fastcall TForm1::FormMouseDown(TObject *Sender, TMouseButton Button,
TShiftState Shift, int X, int Y)
{
AnimationMode=!AnimationMode;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Timer1Timer(TObject *Sender)
{
MSG msg;
if(AnimationMode&&!PeekMessage(&msg,this->Handle,
0,0,PM_NOREMOVE)) //如果允许动画而且消息堆栈中没有消息
FormPaint(Sender);
}
--
念天地之悠悠,
独沧然而泪下,
知我者谓我心忧,
不知我者谓我何求......
--
☆ 来源:.哈工大紫丁香 bbs.hit.edu.cn.[FROM: rhine.bbs@smth.org]
Powered by KBS BBS 2.0 (http://dev.kcn.cn)
页面执行时间:4.227毫秒