OpenGL的视图变换与OSG漫游器

在OpenGL固定管线内容中有一个过程是进行视图变换,主要目的是将世界坐标变换到相机坐标空间中,OpenGL的视图变换所处的位置如下图所示:

在OSG中通过重写漫游器的时候需要实现的4个虚函数与这个变换是一致的(详细参考另一篇文章  《osg中漫游器的原理(一)》

  • 相机视图变换

在OpenGL中初始位置场景的世界坐标与相机坐标是在一起的,视点的方向是Z轴的负方向,

相机位置经过变换之后可以处于世界坐标系中的任何位置,可以通过两个变换:旋转和平移将相机移动到场景中的任意位置,如下图所示:

在OSG中如果定义自己的漫游器,需要实现的4个纯虚函数如下:

virtual void setByMatrix(const osg::Matrixd& matrix) = 0;         //设置相机的位置姿态矩阵
virtual void setByInverseMatrix(const osg::Matrixd& matrix) = 0;  //设置相机的视图矩阵
virtual osg::Matrixd getMatrix() const = 0;                       //获取相机的姿态矩阵
virtual osg::Matrixd getInverseMatrix() const = 0;                //获取相机的视图矩阵  

对应着图中 getMatrix获取的位置姿态矩阵是 R*T [将相机系统中的坐标变换到世界坐标系统中的坐标的矩阵], getInverseMatrxi则是将世界坐标变换为相机坐标的矩阵(称为视图矩阵,对应着     (使用的是OSG中前乘的方式来描述,如果是OpenGL,那么应该是 T*R)

  • 视图变换 uvn系统的推导

对于视图矩阵的推导,一般比较常用的是使用uvn系统的方式进行的,它的推导如下:

如上图所示,相机坐标系统的三个轴向是 uvn,其中u是向右的方向,v是向上的方向,-n是向前的方向,推导的方式如下,首先可以计算n的方向,n = eye - look(n是向量),知道n的方向,接下来需要求出u和v,由于u是垂直于n和v,也就是u垂直于n和v的平面,于是我们一般假设一个向上的方向up,但是这个up方向不能与n平行,通过up和n的叉乘得到u方向,得到u方向之后,通过n叉乘u得到真正相机的向上方向v,概括来说,也就是:

	n = eye - look;
	u = up x n;
	v = n x u;

之后我们怎么进行变换计算出视图矩阵呢,相机在不同的坐标系统下的坐标是不同的,这不同的坐标值正是相机在不同基下的坐标,举个例子来说:

这里面 以及就是一个基,也就是最常见的(i,j,k)这种方式。

下面我们以这个理论来推导视图矩阵,在初始状态的时候世界坐标系xyz和相机坐标系u0v0n0的各个轴向的方向相同,有如下的关系:

这里面P是空间坐标系中的一个向量, u0,v0,n0是相机坐标系的基,x,y,z是世界坐标系的基,初始状态二者是重合的,于是有:

pu0 = px, pv0 = py, pn0 = pz

相机和向量P都旋转之后,有以下关系:

P‘ 是P同相机一起旋转后的向量, u,v,n是相机旋转后的基, Pu0,Pv0,Pn0是P’在它下面的坐标,因为P和相机是一起旋转的,所以坐标不变。x,y,z仍然是世界坐标的基,Px’,Py‘, Pz’是P‘在它下面的坐标,因为Px=Pu0, Py = Pv0, Pz = Pn0,所以有:

由于x,y,z是世界坐标系的基(单位矩阵),所以就有:

也就是说向量P(Px,Py,Pz)经过和相机一起旋转变成了坐标P’(Px‘,Py’,Pz‘),也是就

P* R = P’, 旋转矩阵就是R,也就是说 R正好等于:

写成4x4矩阵形式就是:

平移矩阵T很简单,

于是相机的位置姿态矩阵就是二者相乘, C = R * T = 

相机的位置姿态矩阵C是 将相机坐标系中点的坐标变换到世界坐标系统中      P‘ = P*C(P’是世界坐标系中的新的坐标),那么计算世界坐标系中的坐标在相机坐标系统下的坐标就应是  P = P‘ 乘以 C的逆矩阵,这样就得到了P’在相机坐标系统中的坐标,所以相机的视图矩阵是C的逆矩阵,也就是:

  • 备注

本文中使用的推导是采用的行主序的方式进行的,使用列主序方式的推导应该最后得到的矩阵是与文中结论是转置的关系,下面详细说明一下,关于行主序和列主序,左乘右乘以及对OpenGL计算产生的影响,请查看另一篇文章《OpenGL的列向量和OSG的行向量》

(1)行向量的方式(行主序)

使用行主序的方式,那么三个坐标轴的值应该是横向的去写,也就是说

写成矩阵的形式应该是:

假设正好是世界坐标系,那么这三个分量正好就是(1,0,0)(0,1,0)和(0,0,1),也就是说如果是三个基坐标写成行向量的方式(横向),那么该方式就是行主序的方式,对应着在OSG中的方式,最终的视图矩阵的结论如本文中一致,是:

(1)列向量的方式(列主序)

使用列主序的方式,矩阵会变成为:

也就是说如果是三个基坐标写成列向量的方式(纵向),那么该方式就是列主序的方式,对应着在OpenGL中的方式,最终的视图矩阵的结论是本文推导矩阵的转置矩阵,也就是

本文参考文献:

1.  Popy007的专栏《推导相机变换矩阵》

2.  《向量几何在游戏编程中的使用6》

3. 书籍《计算机图形学》(OpenGL版第3版)

时间: 2024-10-17 00:51:18

OpenGL的视图变换与OSG漫游器的相关文章

清华版CG 实验5 OpenGL模型视图变换

1.实验目的: 理解掌握OpenGL程序的模型视图变换. 2.实验内容: (1)阅读实验原理,运行示范实验代码,理解掌握OpenGL程序的模型视图变换: (2)根据示范代码,尝试完成实验作业: 3.实验原理: 在OpenGL程序中,视图变换必须出现在模型变换之前,但可以在绘图之前的任何时候执行投影变换和视口变换. 1.在指定的视图变换之前,应该使用glLoadIdentity()函数把当前矩阵设置为单位矩阵. 2.在载入单位矩阵之后,使用gluLookAt()函数指定视图变换.如果程序没有调用g

OpenGL的视图变换、模型变换、投影变换、视口变换

产生目标场景的过程类似于用照相机进行拍照: (1) 把照相机固定在三角架上,并让他对准场景从不同位置观察场景(视图变换) gluLookAt (2) 对场景进行安排,使各个物体在照片中的位置是我们所希望的 移动,旋转或者放大缩小场景中的物体(模型变换) glTranslate* ,glRotate* ,glScale* (3) 选择照相机镜头,并调整放大倍数(调焦) 显示物体时,可以选择物体是如何投影到屏幕上(投影变换) glFrustum , gluPerspective , glOrtho

[osg][osgEarth][原]基于OE自定义自由飞行漫游器(初级版)

由于受够了OE的漫游器,想搞个可以在全球飞行的漫游器,所以就做了一个: 请无视我的起名规则······ 类头文件:EarthWalkManipulator.h #pragma once //南水之源 20180101 #include <osgGA/CameraManipulator> #include <osgEarth/MapNode> #include <osgEarth/Viewpoint> #include <osgEarth/GeoData> c

[osg][osgEarth][原]基于OE自定义自由飞行漫游器(第二版)

在初级版上,进行新的漫游方式调整 头文件: #pragma once //南水之源 20180101 #include <osgGA/CameraManipulator> #include <osgEarth/MapNode> #include <osgEarth/Viewpoint> #include <osgEarth/GeoData> class EarthWalkManipulator :public osgGA::CameraManipulator

OSG漫游:实现按键控制的操作器

OSG提供了几种manipulator(操作器),已经能胜任很多场合了.但玩过射击类游戏的都比较熟悉使用按键的方式控制人物角色的移动,自己也想来实现一个,于是参考了OSG程序设计 一书,进行实现. 功能: W或者↑箭头:前进 S或者↓箭头:后退 A或者←箭头:向左 D或者→箭头:向右 Q:左旋转 E:右旋转 鼠标左键拖动:左右视角 鼠标右键拖动:上下视角 鼠标中键:放大或者缩小 +:加速移动 -:减速移动 关键点 1.视口矩阵的运算方式: osg::Matrixd CustomManipulat

OpenGl学习笔记3之模型变换、视图变换、投影变换、视口变换介绍

模型变换.视图变换.投影变换.视口变换介绍 opengl中存在四种变换,分别是模型变换,视图变换,投影变换,视口变换.这四种变换是图形渲染的基本操作,实质上这四种变换都是由矩阵乘法表示(这些操作都是由一个4*4的矩阵来完成的),通过变换,我们可以看到各种通的显示效果,最简单的效果就是让图元沿着某个方向变换(放大,缩小,翻转等)或者对所要显示的图元进行裁剪.接下来我们就详细介绍这四种变换以及相互之间的联系. 我们要在屏幕上显示一个具有三维坐标的物体,大致需要以下步骤: 1.     进行模型,视图

【GISER&amp;&amp;Painter】Chapter02:WebGL中的模型视图变换

上一节我们提到了如何在一张画布上画一个简单几何图形,通过创建画布,获取WebGLRendering上下文,创建一个简单的着色器,然后将一些顶点数据绑定到gl的Buffer中,最后通过绑定buffer数据,提供buffer中顶点数据的情况,执行渲染绘制方法,将数据结果从buffer中刷新到帧缓存中.整个流程十分清晰明了,可是通过对比原来OpenGL中的整个流程,我们会发现其中还缺少了一些很重要的处理步骤,虽然我们创建了属于自己的着色器,可并没有对顶点数据进行类似于顶点处理管线中的模型视图变换.透视

opengl中场景变换|2D与3D互转换(转)

opengl中场景变换|2D与3D互转换 我们生活在一个三维的世界——如果要观察一个物体,我们可以: 1.从不同的位置去观察它.(视图变换) 2.移动或者旋转它,当然了,如果它只是计算机里面的物体,我们还可以放大或缩小它.(模型变换) 3.如果把物体画下来,我们可以选择:是否需要一种“近大远小”的透视效果.另外,我们可能只希望看到物体的一部分,而不是全部(剪裁).(投影变换) 4.我们可能希望把整个看到的图形画下来,但它只占据纸张的一部分,而不是全部.(视口变换) 这些,都可以在OpenGL中实

对用OpenGL ES 2.0实现OpenGL ES 1.1的顶点着色器的研究

对用OpenGL ES 2.0实现OpenGL ES 1.1的顶点着色器的研究 想要彻底研究OpenGL ES 2.0与前一代OpenGL的区别,还是要费很大一番精力的.最近在仔细研读<OpenGL ES 2.0 Programming Guide>,虽然这本书最早出版日期是2008年,距今已经7年了,而著作的日期或许还要早上半年到1年,但是目前OpenGL ES 2.0是主流三维开发框架,因此这本书的知识直到现在,依然受用. OpenGL ES 2.0是桌面版OpenGL 2.0的一个子集,