发信人: yxy (田丝丝#冬眠的小肥鹰), 信区: GAME_Designer 
标  题: OPENGL(3) 
发信站: BBS 水木清华站 (Tue Jan 13 08:39:45 1998) 
 
上回书说道有个reshape需要进一步讲解 
这个函数功能是对用户改变窗口大小的操作进行一些重绘 
的动作(类似VC中的OnResize)。其中用到了一些变换的概念 
我希望大家已经具备初步的计算机图形学的知识,这将有利于 
这部分的理解。如果还没有,也没关系,我尽量讲解的通俗一些 
对于3D绘图,把其中3D坐标写成齐次坐标系后,是4*4的矩阵形式(详细 
            ………………………………………………………… 
可以参阅相关文献,后面也会讲到。)任何投影、旋转...操作都可以看 
成是矩阵相乘的操作。矩阵操作----这个概念一定要形成!! 
例如在2D中普通的旋转变换,可以写成: 
                  |cosθ  sinθ 0 | 
[x' y' 1]=[x y 1] |-sinθ cosθ 0 | 
                  |0      0     1 | 
3D中道理完全一样,一个3D图形的显示包括下面步骤: 
1.视点变换(将相机放在合适的地方对准3D景物) 
2.模型变换(将3D物体放在合适的地方) 
3.投影变换(将相机镜头调整,使3D景物投影在2D胶片上) 
4.视口变换(决定胶片大小) 
其中1、2并没有本质区别。 
 
 
里面有几个关键性函数: 
 
一 几何变换 
1. 
void glTranslated(  
GLdouble x,  
GLdouble y,  
GLdouble z  
);  
void glTranslatef(  
GLfloat x,  
GLfloat y,  
GLfloat z  
); 
目标沿X Y Z轴平移 x y z 
 
2. 
void glRotated(  
GLdouble angle,  
GLdouble x,  
GLdouble y,  
GLdouble z  
);  
void glRotatef(  
GLfloat angle,  
GLfloat x,  
GLfloat y,  
GLfloat z  
);   
目标分别以X Y Z轴为轴逆时针旋转 x y z 
 
3. 
void glScaled(  
GLdouble x,  
GLdouble y,  
GLdouble z  
);  
void glScalef(  
GLfloat x,  
GLfloat y,  
GLfloat z  
);  
目标在X Y Z 方向缩放,缩放因子为 x y z 
 
二 投影变换 
 
1.正射投影(即没有“近大远小”) 
void glOrtho(GLdouble left,GLdouble right,GLdouble bottom,GLdouble top, 
GLdouble near,GLdouble far) 
创建一个平行视景体(的矩阵),即投射线是平行线,把第一个矩形 
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 
视景投影到第二个矩形视景上。并用这个矩阵乘以当前矩阵,以完成变换。 
近景第一个矩形的左上角三维空间坐标(left,bottom,-near),右下角的三维 
空间坐标(right,top,-near); 
远景第二个矩形左上角三维空间坐标(left,bottom,-far),右下角的三维空间 
坐标(right,top,-far); 
 
2.透射投影(“近大远小”) 
void glFrustum(  
GLdouble left,  
GLdouble right,  
GLdouble bottom,  
GLdouble top,  
GLdouble znear,  
GLdouble zfar  
);  
创建一个型如棱台的视景体,其近截取面由left right bottom top znear 
确定,远截取面由从视点投影近截取面到Z轴zfar位置决定 
 
三 视口变换 
void glViewport(GLint x,GLint y,GLsize width,GLsize height); 
这个函数定义一个视口,x和y是视口在屏幕窗口坐标系中左上坐标 
缺省是(0,0)。width height是宽和高。 
注意使用中视口长宽比例的调整会导致图象变形。因此reshape()中 
要检测窗口尺寸,修正视口大小,保证图象不变形。 
 
附: 
void glMatrixMode(GLenum mode );  
把当前矩阵转换为指定的矩阵类型 
 
这三个函数的利用见例子中的中文说明: 
//////////////////////////////////////////////////////////// 
//sample.cpp 
#include "glos.h" 
#include <GL/gl.h> 
#include <GL/glaux.h> 
#include "windows.h" 
void myinit(void); 
void CALLBACK  display(void); 
void CALLBACK  reshape(GLsizei w,GLsizei h); 
///////////////////////////////////////////////////////////// 
void myinit(void) 

        /*初始化:*/ 
    auxInitDisplayMode(AUX_SINGLE|AUX_RGBA); 
        //窗口显示单缓存和RGB(彩色)模式 
        auxInitPosition(0,0,500,500); 
        //大小x=500 y=500 (0,0)是屏幕左上点 
        auxInitWindow("sample1"); 
        //窗口初始化,参数是标题 
        glClearColor(0.0,0.0,0.0,0.0); 
    //将窗口清为黑色 
        glClear(GL_COLOR_BUFFER_BIT); 
    //将颜色缓存清为glClearColor命令所设置的颜色 
        //即背景色 

////////////////////////////////////////////////// 
void CALLBACK reshape(GLsizei w,GLsizei h) 

//设定视口X Y方向不要大于500单位 
if(w<=500&&h<=500) 
glViewport(0,0,w,h); 
if(w>500&&h<=500) 
glViewport(0,0,500,h); 
if(w<=500&&h>500) 
glViewport(0,0,w,500); 
if(w>500&&h>500) 
glViewport(0,0,500,500); 
 
//进入世界坐标系,准备变换 
//必要的步骤,初始化变换矩阵步骤: 1确定类型 2清成单位阵 
glMatrixMode(GL_PROJECTION); 
glLoadIdentity(); 
 
//定义一个合适的视景体 
if(w<=h) 
 glOrtho(-20.0,20.0,-20.0*(GLfloat)h/(GLfloat)w, 
         20.0*(GLfloat)h/(GLfloat)w,-50.0,50.0); 
else 
  glOrtho(-20.0*(GLfloat)h/(GLfloat)w, 
         20.0*(GLfloat)h/(GLfloat)w,-20.0,20.0,-50.0,50.0); 
 
//把变换结果返回视点坐标系 
glMatrixMode(GL_MODELVIEW); 
glLoadIdentity(); 

////////////////////////////////////// 
//画三棱锥,功能同上一讲 
void draw(void) 

glBegin(GL_TRIANGLE_STRIP); 
glColor3f(1.0,0.0,0.0); 
glVertex3f(15.0,0.0,0.0); 
glColor3f(0.0,1.0,0.0); 
glVertex3f(-15.0,0.0,0.0); 
glColor3f(0.0,0.0,1.0); 
glVertex3f(0.0,15.0,15.0); 
// 
glColor3f(0.0,1.0,1.0); 
glVertex3f(10.0,15.0,-15.0); 
// 
glColor3f(1.0,1.0,0.0); 
glVertex3f(15.0,0.0,0.0); 
// 
glEnd(); 

//////////////////////////////////////// 
void CALLBACK display(void) 

//按上个例子中方法画第一个三棱锥 
glClearColor(0.0,0.0,0.0,1.0); 
glClear(GL_COLOR_BUFFER_BIT); 
glLoadIdentity(); 
glTranslatef(0.0,0.0,-25.0); 
draw(); 
 
//开始画第二个三棱锥 
//变换开始,清变换矩阵为单位阵 
glLoadIdentity(); 
//先沿X Y Z平移-5 -10 -4,屏幕上看就是向左下移动 
//Z方向由于是平行投影,没有“近大远小”所以看不出效果 
glTranslatef(-5.0,-10.0,-4.0); 
//再沿Z轴转90度 
glRotatef(90,0.0,0.0,1.0); 
draw(); 
 
//绘图工作完成,强制绘图结束 
glFlush(); 

 
void main(void) 

    myinit(); 
    auxReshapeFunc(reshape); 
    auxMainLoop(display); 

 
//sample ends here 
///////////////////// 
如果大家运行一下就知道上述函数的作用,无非是把物体移动、转动、变形 
缩放、透视... 
我想有了前3讲,OPENGL的基本原理已经如此了 
它就是提供了一个标准的计算机图形学所使用的数学模型到显示的接口, 
只要具备图形学知识,掌握OPENGL API函数使用,绘图很EASY啦 
基础部分已经完毕,慢慢再来谈高级一些的绘图功能如: 
纹理、光源、动画... 
真诚希望大家提提意见和高论 :) 
 
-- 
※ 来源:·BBS 水木清华站 bbs.net.tsinghua.edu.cn·[FROM: 166.111.74.90]