opengl中的坐标变换
来源:互联网 发布:面向对象编程思维 编辑:程序博客网 时间:2024/04/30 15:28
原文地址:http://thatax.blog.163.com/blog/static/208926802008711115558846/
opengl 中使用的是右手坐标系。
以下部分来自http://www.v-galaxy.com/neo6/tut/tut5.html
OpenGL入门(五):坐标变换
========================
neo6
坐标变换是OpenGL最基本功能之一,然而却不容易讲清楚,网上已有的教程好象都没有做到这一点。
其实弄懂坐标变换的关键是理解什么是“眼睛坐标系”(eye coordinate system) 和“目标坐标系”(object coordinate system),以及各个API函数使用的是哪套坐标:是“眼睛坐标”还是“目标坐标”。
所谓“眼睛坐标系”就是“全局坐标系”,可以这样设想:以窗口中心为原点,水平向右为+x轴,竖直向上为+y轴,垂直于屏幕指向我们为+z轴。长度单位这样来定:
窗口范围按此单位恰好是(-1,-1)-(1,1)。
所谓“目标坐标系”就是“局部坐标系”。在下面我们简称眼睛坐标系为ECS,目标
坐标系为OCS。点的“眼睛坐标”为EC, “目标坐标”为OC。
任何时候OpenGL都保存着一个当前的OCS,在初始条件下,OCS与ECS是重合的,但
我们可以对“目标坐标系”作各种变换: 平移、伸缩、旋转。经过这些变换之后, OCS与ECS不再重合。
非常重要的一点:glVertex3f所用的坐标是OC而不是EC。
为什么要这样设计API呢?因为我们一般习惯于在一个合适的局部坐标系中作图, 然后把它通过坐标变换放到合适的位置或者转到合适的角度。
比如我们要在(xc,yc)-(xc+dx,yc+dy)这样一个框子里画一条正弦曲线,我们更喜欢先在(0,0)-(1,1)范围内画这条曲线, 然后把它先伸缩到(0,0)-(dx,dy)的范围, 再平移(xc,yc)。这个过程如果用ECS和OCS的观点来看,平移和伸缩的顺序正好反过来:
(1)开始时,调用glLoadIdentity(),OCS0与ECS重合
(2)调用glTranslatef(xc,yc,0),OCS0平移,变成OCS1
(3)调用glScalef(dx,dy,0),OCS1伸缩,变成OCS2
(4)调用glBegin(),glVertex3f(),glEnd(),在OCS2中作图
现在我们考虑同一个点在OCS0,OCS1,OCS2中的坐标:(x0,y0,z0),(x1,y1,z1)和(x2,y2,z2)。
x0=x1+xc
y0=y1+yc
z0=z1
用矩阵和向量的形式,可以写成v0=T1*v1
x1=x2*dx
y1=y2*dy
z1=z2
用矩阵和向量的形式,可以写成v1=T2*v2 因此,v0=T1*T2*v2=T*v2
OpenGL只保存关于当前OCS到ECS变换所需的矩阵,记它为T。那么上述过程中T的变
化是:
(1)glLoadIdentity(),T=I(单位矩阵)
(2)glTranslatef(xc,yc,0),T=I*T1=T1
(3)glScalef(dx,dy,0),T=T*T2
(4)glVertex3f() 利用T把各点的OC变换成EC再作图
当OpenGL计算出点的EC之后,它要用投影变换把三维坐标变成两维坐标。有两种投影
方式:平行投影,用glOrtho()来设置;透视投影,用glFrustum()或者gluPerspective()来设置。
下面的这个例子利用坐标变换在不同的位置作四个正弦曲线。
//tut5.cpp
#include <math.h>
#include <gl/glut.h>
#define PI 3.1415926
#define N 100
float x[N];
float y[N];
void prepare_curve()
//在x[N]和y[N]里填入正弦曲线的x坐标和y坐标
{
for(int i=0;i<N;i++)
{
x[i]=(float)i/N;
y[i]=(sin(x[i]*2*PI)+1)/2;
}
}
void plot(int n, float x[], float y[], float color[])
//在z=0的平面上先作一黑色方框(0,0)-(1,1),
//然后作x[]和y[]所表示的曲线
//曲线的范围最好不要超出(0,0)-(1,1),不然会很难看
{
glBegin(GL_LINE_LOOP); //draw a box (0,0)-(1,1)
glColor3f(0,0,0);
glVertex2f(0,0);
glVertex2f(0,1);
glVertex2f(1,1);
glVertex2f(1,0);
glEnd();
glBegin(GL_LINE_STRIP);
glColor3fv(color);
for(int i=0;i<n;i++)
{
glVertex2f(x[i],y[i]);
}
glEnd();
}
void display()
{
float red[3]={1,0,0};
float blue[3]={0,1,0};
float green[3]={0,0,1};
float yellow[3]={1,1,0};
glClearColor(1,1,1,1);
//设置刷新背景色
glClear(GL_COLOR_BUFFER_BIT);
//刷新背景
glMatrixMode (GL_PROJECTION); //设置矩阵模式为投影矩阵
glLoadIdentity(); //初始化投影矩阵
glOrtho(-1,1,-1,1,-1,1); //设置平行投影的投影矩阵
glMatrixMode(GL_MODELVIEW); //设置矩阵模式为modelview矩阵
glLoadIdentity();
plot(N,x,y,red);
glTranslatef(-1,0,0);
plot(N,x,y,green);
glTranslatef(0,-1,0);
plot(N,x,y,blue);
glTranslatef(1,0,0);
glScalef(0.5,0.5,1);
plot(N,x,y,yellow);
glFlush();
//更新窗口
}
int main(int argc, char** argv)
{
prepare_curve();
//生成一条正弦曲线
glutInit(&argc, argv);
glutInitDisplayMode (GLUT_SINGLE | GLUT_RGBA);
//设置显示模式:单缓冲区, RGBA颜色模式
glutInitWindowSize (200, 200);
//设置窗口宽度、高度
glutInitWindowPosition(100,100);
//设置窗口位置
glutCreateWindow (argv[0]);
//弹出窗口
glutDisplayFunc (display);
//设置窗口刷新的回调函数
glutMainLoop();
//开始主循环
return 0;
}
注意我们对上一个例子中的plot()加了一个颜色参数,用来控制曲线的颜色。
glColor3fv(color)的参数是一个数组float color[3];
里面是RGB颜色值。v的意思是vector。
glMatrixMode(GL_MODELVIEW)把当前矩阵模式设置为ModelView Matrix,因为
OpenGL中还有用于其他用途的Perspective Matrix和Texture Matrix。
glMatrixMode(GL_PERSPECTIVE)设置当前矩阵模式为Perspective Matrix。随后先调用
glLoadIdentity()初始化投影矩阵(perspective matrix),然后调用glOrtho(left,right,bottom,top,znear,zfar)
设置投影矩阵。由此生成的投影矩阵的作用相当于在ECS中取以(left,bottom,-znear)~(right,top,-zfar)
为对角线的立方体为clipping volume,眼睛从z = -znear的位置向z = -zfar 的位置看,像成在 z = -znear 的
平面上。注意眼睛看的方向很重要,因为这决定什么东西会被遮住。在这个程序里
我们用:
glOrtho(-1,1,-1,1,-1,1)
znear = -1, zfar = 1
所以我们从 -znear = 1 向 -zfar = -1 的方向看,即向 -z 方向看。所以在这里我们可以
把ECS 的 z 轴想象成是指向我们的。
通常情况下我们在调用glOrtho时总是取znear 小于 zfar,这时候我们总是朝 -z 方向看的。
另外http://www.chinaai.org/Article_Show.asp?ArticleID=294
有一篇比较理论性的说明。
- opengl中的坐标变换
- OpenGL 中的坐标变换
- OpenGL ES中的坐标变换
- OpenGL中的坐标变换、矩阵变换
- OpenGL中的坐标变换和矩阵
- 03 - OpenGL 坐标变换中的各种矩阵
- 【OpenGL】03 - OpenGL 坐标变换中的各种矩阵
- OpenGL坐标变换详解
- OpenGL坐标变换详解
- openGL坐标变换
- OpenGL坐标变换复习
- OpenGL坐标变换
- opengl坐标变换
- OpenGL坐标变换
- OpenGL坐标变换
- OpenGL坐标变换专题
- opengl坐标变换
- OpenGL 之 坐标变换
- Tween动画介绍
- Ubuntu 系统清理
- c++builder 中调用WebService的例子
- DSP代码优化方法(2)
- PHP性能优化总结
- opengl中的坐标变换
- NSNotificationCenter的作用
- 回溯法原理及应用
- 用事务一次处理多条SQL语句
- ubuntu su进入root权限
- java socket 网络
- 设计模式——简单工厂模式
- poj 2420
- QNX学习者,向ARM汇编进发!