OpenGL.坐标系统的介绍与坐标变换的实现

  • 坐标变换其实一直是一个比较让人着迷的内容,嘿嘿嘿
  • 从中也可以看到矩阵的魅力
  • 记得一篇文章讲,矩阵就是记录一个向量到另一个向量的运动,一个点可以用一个向量来表示,乘上一个矩阵就变成了另一个向量,对应着另一个点。所以说矩阵就是记录向量空间中向量的运动,记录向量之间的转换规则。

齐次坐标

只讲三维的情况啊

  • 向量空间中,只有标量和向量

    • 向量 + 向量 = 向量
    • 标量 * 向量 = 向量
    • 三维向量空间中,可以视任意一组线性无关的向量为基
      • 基 V = [ v1 , v2 , v3 ]
    • 其他向量可以用一个三维的元组来表示
      • 向量 a = [ A1 , A2 , A3 ]
    • 于是 向量 a = A1 * v2 + A2 * v2 + A3 * v3
  • 仅有向量是无法表示几何的,至少要有点吧
    • 一般认为点的表示也是一个三维的元组

      • 点 b = [ B1 , B2 , B3 ]
    • 这样就无法区分点和向量了,咋办?
  • 仿射空间
    • 仿射空间中,基称为标架,由三个向量和一个点组成

      • 标架 V = [ v1 , v2 , v3 , p ]
    • 仿射空间的运算
      • 向量+ 向量 = 向量
      • 标量 * 向量 = 向量
      • 点 + 向量 = 点
    • PS:可以看到,点与向量的和为另一个点,其实也可以认为向量记录的是点的运动,记录着一个点转换到另一个点的信息
    • 于是
      • 向量 a = [ a1 , a2 , a3 , 0 ]
      • 点 b = [ b1 , b2 , b3 , 1 ]
      • a = a1 * v1 + a2 * v2 + a3 * v3 , 确实是向量
      • b = b1 * v1 + b2 * v2 + b3 * v3 + p
      • b = 向量 + p = 点
    • 勉强区分开了哈
  • 还有问题
    • 点p和向量v1v2v3怎么确定?它们的值又是在那种标架或基下的?

      • 所以讨论了再多,这个标架其实还是对应我们普通的三维坐标系才显得平易近人,即

        • 点p为原点
        • v1 v2 v3 分别对应三个坐标轴 [1,0,0]、[0,1,0]、[0,0,1]
      • 只不过我还告诉你,对于任意一个点和任意三个线性无关的向量v1 v2 v3,其都可以当作一个标架。因为三个线性无关的向量就可以表示出任意一个向量,再有一个点为基础,就可以表示任意一个点
  • 所以想OpenGL中就默认,其世界坐标系对应的仿射空间,p为原点,v1v2v3为坐标轴
  • 但是相机坐标系就不是了,因为啥?因为相机可以移动啊,可以改变朝向和正向,这些都影响着相机坐标系。单就移动来说:
    • 相机的默认位置是在世界坐标系的原点,移动了之后就不是了啊
    • 那么你在相机的位置看世界坐标系上的点,那些点的坐标表示就应该转换到相机坐标系上来,才对应着我们真正应该看到的点的位置
  • 还是写写坐标系比较实在

坐标系

  • 世界坐标系

    • 世界坐标系的标架
      • p为原点(0,0,0)
      • v1为x轴 [ 1 , 0 , 0 ]
      • v2为y轴 [ 0 , 1 , 0 ]
      • v3为z轴 [ 0 , 0 , 1 ]
    • 对于输入的顶点数据,如点 a = ( a1 , a2 , a3 )
      • 在OpenGL内用四维来表示
      • a = [ a1 , a2 , a3 , 1 ]
      • 理解起来的话就是
        • a = a1 * v1 + a2 * v2 + a3 * v2 + p
        • a = [ a1 , 0 , 0 ] + [ 0 , a2 , 0 ] + [ 0 , 0 , a3 ] + ( 0 , 0 , 0 )
        • a = ( a1 , a2 , a3 )//也就是这个点嘛
  • 相机坐标系
    • 相机默认的位置为世界坐标系原点,朝向是Z轴的负方向,正向是Y轴的正方向
    • 考虑相机
      • 位置就是相机的位置,也就是从哪里去观察这个世界
      • 朝向就是相机对准的方向
      • 正向就是相机该放在这个位置、对准了方向后,该怎么摆。比如一般我们拍照,竖着摆拍出来的就是竖着的照片,横着摆就是横着的照片。
      • 而这些参数其实也是在世界坐标系下表示的
    • 默认的相机坐标系
    • 移动相机之后,相机的位置、朝向、正向就改变了
    • 但顶点的数据还是对应着的世界坐标系,而我们要生成图片是依赖于相机的,所以我们要把顶点转换到相机坐标系下才行,这就是视图的转换。
    • 视图转换后顶点的表示就是相对于相机坐标系,但其标架在逻辑上依然是 原点+三个坐标轴
  • 裁剪坐标系
    • 这还只是相机的外部参数,我们还需要确定

      • 那一块的三维区域内的点,我才会拍下来,才会用来生成图像,即我需要规定一块“视景体”来确定拍照的范围
      • 是否需要透视效果等等其他
  • 还是讲坐标变换比较实在

坐标变换

OpenGL主要有两个矩阵,模型视图矩阵和投影矩阵

  • 模型视图矩阵

    • 对世界坐标系下顶点的变化操作,如平移、旋转、缩放(模型)都是对顶点的变化,而相机的位置、朝向、正向的改变(视图)也需要顶点从相对于世界坐标系下转换到相对于相机坐标系,这两种虽然是不同的改变但都是对顶点的操作,所以可以用一个矩阵来记录
    • 对于一个点

      a=∣∣∣∣∣∣x1y1z11∣∣∣∣∣∣
    • 平移,就是在原坐标的基础上加上某个值
      • 有平移矩阵

        T=∣∣∣∣∣∣100001000100dxdydz1∣∣∣∣∣∣
      • 使得

        T?a=∣∣∣∣∣∣x1+dxy1+dyz1+dz1∣∣∣∣∣∣
      • 就是说只要在原先点的基础上左乘平移矩阵,就可以把点的坐标进行平移变换
      • 记平移矩阵 T 为 T(dx,dy,dz),
    • 旋转
      • 先考虑绕Z轴旋转的情况,正向的旋转为右手大拇指朝向Z轴正向时,其余手指的朝向(逆时针)
      • 绕Z轴旋转至改变X和Y坐标
      • x1=r?cos(a)y1=r?sin(a)x2=r?cos(a+b)y2=r?sin(a+b)

      • 所以就有

        x2=x1?cos(b)?y1?sin(b)y2=x1?sin(b)+y?cos(b)

      • 所以绕Z轴旋转θ角度的旋转矩阵就是

        Rz(θ)=∣∣∣∣∣∣cos(θ)sin(θ)00?sin(θ)cos(θ)0000100001∣∣∣∣∣∣

      • 显然有

        Rz(θ)?a=∣∣∣∣∣∣x1?cos(θ)?y1?sin(θ)x1?sin(θ)+y1?cos(θ)z11∣∣∣∣∣∣

      • 同理
      • 绕X轴旋转θ角度的矩阵

        Rx(θ)=∣∣∣∣∣∣10000cos(θ)sin(θ)00?sin(θ)cos(θ)00001∣∣∣∣∣∣

      • 绕Y轴旋转θ角度的矩阵

        Ry(θ)=∣∣∣∣∣∣cos(θ)0?sin(θ)00100sin(θ)0cos(θ)00001∣∣∣∣∣∣

    • 缩放,就是在原坐标的基础上乘以某个倍数
      • 缩放矩阵

        S(Sx,Sy,Sz)=∣∣∣∣∣∣Sx0000Sy0000Sz00001∣∣∣∣∣∣

    • 视图矩阵,将以世界坐标系原点为(0,0,0)点的世界坐标系下的顶点转换到以相机位置为(0,0,0)的相机坐标系下。
      • 顶点和相机之间真正相对位置是不变的,只不过我们原先顶点的坐标表示是在世界坐标系下,而我们需要的是相机坐标系下的坐标表示。所以这里只是做坐标变换,即同一个顶点在不同坐标系下其坐标表示是不同的。
      • 从默认的相机位置可以看到,默认的相机坐标系和世界坐标系是重合的,即不需要转换,其实也就是相当于视图矩阵是单位矩阵而已
      • 而改变了相机的位置、朝向和正向之后,视图矩阵才会真正的发挥作用,乘上的效果就是让世界坐标系下的顶点转换到相机坐标系下
      • OnenGL通过gluLookAt函数来改变相机的外部参数
      • gluLookAt( Tx , Ty , Tz , Ox , Oy , Oz , Vx , Vy , Vz )
        • Tx Ty Tz 为相机的位置
        • Ox Oy Oz 为相机朝向的点
        • Vx Vy Vz 为相机的正向
      • 考虑相机的三个向量

        n=∣∣∣∣NxNyNz∣∣∣∣=∣∣∣∣Ox?TxOy?TyOz?Tz∣∣∣∣v=∣∣∣∣VxVyVz∣∣∣∣u=v×n=∣∣∣∣UxUyUz∣∣∣∣

      • n为相机朝向的方向向量
      • v为相机的正向向量
      • u为二者叉乘的向量
      • 要求:n和v为互相垂直,nuv三者均为单位向量(只表方向)
      • 那么可以看出这三个向量和相机坐标系的关系
      • 并且我们还知道相机的位置 Tx Ty Tz
      • 对于顶点

        a=∣∣∣∣∣∣x1y1z11∣∣∣∣∣∣
      • 首先我们把相机移动到世界坐标系的原点,但因为我们要对顶点的数据进行修改,所以就要对顶点乘上 T( -Tx , -Ty , -Tz )这样一个平移矩阵。这样以来顶点移动到了就是以相机位置为原点的坐标系下

        T(?Tx,?Ty,?Tz)=∣∣∣∣∣∣100001000010?Tx?Ty?Tz1∣∣∣∣∣∣

      • 再求这个顶点在相机坐标系下的三个坐标的值。借助我们得出的 u,v,n三个向量,这三个向量分别对应了相机坐标系的三个坐标轴,所以要求坐标的值也就是看以这个顶点为终点、相机位置为起点的向量和nuv这三个单位向量的点积,相当于乘上这样一个矩阵

        NUV=∣∣∣∣∣∣UxVxNx0UyVyNy0UzVzNz00001∣∣∣∣∣∣

      • 然后我们得到了坐标的值吗?还没有。因为 向量n和坐标轴z的正向是相反的,向量u和坐标轴x的正向是相反的,所以我们还需要再乘上一个矩阵来调整

        ∣∣∣∣∣∣?1000010000?100001∣∣∣∣∣∣

      • 于是我们最终用来把世界坐标系下的点转换到相机坐标系下的视图矩阵就是

        ∣∣∣∣∣∣?1000010000?100001∣∣∣∣∣∣?∣∣∣∣∣∣UxVxNx0UyVyNy0UzVzNz00001∣∣∣∣∣∣?∣∣∣∣∣∣100001000010?Tx?Ty?Tz1∣∣∣∣∣∣

    • 投影矩阵
      • 模型操作对顶点进行变换,其还是在世界坐标系下
      • 视图操作将顶点转换到相机坐标系下
      • 但这二者都是对顶点进行变换,所以只需要一个模型-视图矩阵来维护就可以了
      • 那么投影矩阵就需要另外一个内存空间来维护
      • 因为我们已经把顶点转换到了相机坐标系下,所以我们设置视景体就以相机坐标系来设置
      • 只会glOrtho的矩阵,即正交投影。其视景体是一个方形的区域。
        • glOrtho( left , right , bottom , top , near , far )

          • left,right分别对应了x=left和x=right这两个平面
          • bottom和top分别对应了y=bottom和y=top这两个平面
          • near和far分别对应了z=-near和z=-far两个平面
            • 这里取负,主要是因为相机的朝向是z的负方向,这样才会使视景体落在相机的前面
      • 投影矩阵要做的事情,就是一个“规范化”
      • 即根据视景体的范围,对顶点进行平移、放缩,使原先在视景体内的点都落在以原点为中心、边长为2的规范化正方体内
        • 这样做的好处就是规范,之后的裁剪、光照等等操作都在一个统一的规范下进行
      • 平移矩阵

        T(?left+right2,?bottom+top2,near+far2)

      • 放缩矩阵

        S(2right?left,2top?bottom,?2far?near)

      • 所以我们的投影矩阵就是

        S?T=∣∣∣∣∣∣∣∣∣∣2right?left00002top?bottom00002far?near0?right+leftright?left?top+bottomtop?bottom?far+nearfar?near1∣∣∣∣∣∣∣∣∣∣

    • 注意到我们放缩的时候,对于Z坐标的放缩多了一个负号,这也就意味着所有的点在规范化正方体内是Z坐标的负号是相反的
    • 这也就意味着,我们要去“看”规范化正方体内的物体的时候,应该从Z轴的负无穷远看向原点,即方向应该是Z的正向
  • 这一步得到的点的坐标,我们称其位于裁剪坐标系
时间: 2024-10-15 07:08:01

OpenGL.坐标系统的介绍与坐标变换的实现的相关文章

统一D3D与OpenGL坐标系统

作者:游蓝海(http://blog.csdn.net/you_lan_hai) DirectX 3D与OpenGL坐标系统的差异性,给我们带来很大的麻烦,让跨平台编程的新手很困惑.最近在做一个跨平台的游戏,仔细看了下两者的矩阵,发现并没有什么大区别,将d3d左手系的矩阵传递给opengl shader完全可以正常工作. 先说一下两者一些概念上的区别:         (1)坐标系统不同 d3d左手坐标系,opengl右手坐标系         (2)矩阵行序不同 d3d行优先,opengl列优

【转】OpenGL相关函数库介绍

原文:http://blog.chinaunix.net/uid-20638550-id-1909182.html OpenGL 函数库相关的API有核心库(gl).实用库(glu).辅助库(aux).实用工具库(glut).窗口库(glx.agl.wgl)和扩展函数库等. 从图1可以看出,gl是核心,glu是对gl的部分封装.glx.agl.wgl 是针对不同窗口系统的函数.glut是为跨平台的OpenGL程序的工具包,比aux功能强大.扩展函数库是硬件厂商为实现硬件更新利用OpenGL的扩

C#应用视频教程2.4 OPENGL虚拟仿真介绍

这一部分我们首先实现视图控制(包括了平移/旋转/缩放),前面我们已经讲过,通过lookat一个函数,或者通过translate+rotate两个函数,都能实现视图的控制(两个函数的方式比较简单,但是通用性不够,因为这个更像是画布就像去参观卖房子的模型,你可以把模型随便上下左右移动翻转看外面,但是如果要像第一人称视角到房子里面爬窗户,上房顶,钻地道,这种视角肯定是不够的.可以想象CS游戏中,整个地图场景必然是唯一的,每个游戏玩家都可以控制一组视角,视角的lookat九个参数不同导致了可以仰望,俯瞰

OpenGL坐标系统

一.坐标系统概述 本文类容见LearnOpenGL CN.直接copy过来留个存档. OpenGL希望每次顶点着色后,我们的可见顶点都为标准化设备坐标(Normalized Device Coordinate,NDC).也就是说每个顶点的\(z,y,z\)都应该在\(-1\)到\(1\)之间,超出这个范围的顶点将是不可见的.通常情况下我们会自己设定一个坐标范围,之后再在顶点着色器中将这些坐标变换为表转化设备坐标.然后这些标化设备坐标传入光栅器(Rasterizer),将它们变换为屏幕上的二维坐标

C#应用视频教程2.2 OPENGL虚拟仿真介绍

三维在理解了如何绘制2D元素之后,我们尝试绘制3D元素. 其实多个三角形也能够成四面体,多个长方形也能够成六面体,所以绘制3D元素的时候,只要顶点数量匹配就行了 ? 这里我们尤其注意,我把绘制之前的三个平移和三个旋转单独拿出来做成变量,如果你的TranslateZ默认值是0的话,你默认看到的是黄色面,如果把TranslateZ设置为负值,则看到了红色,且越来越小,如果把TranslateZ设置为正数,则啥也看不到了.这里读者还需要有一个额外的空间想象能力,就是你的观察视角在哪里.默认的时候你的观

opengl基本库介绍

开发基于OpenGL的应用程序,必须先了解OpenGL的库函数.它采用C语言风格,提供大量的函数来进行图形的处理和显示.OpenGL库函数的命名方式非常有规律.所有OpenGL函数采用了以下格式: <库前缀><根命令><可选的参数个数><可选的参数类型> 库前缀,有gl.glu.aux.glut.wgl.glx.agl等等,分别表示该函数属于OpenGL那个开发库.    从函数名后面中还可以看出需要多少个参数以及参数的类型.I代表int型,f代表float

C#应用视频教程2.1 OPENGL虚拟仿真介绍

OPENGL的虚拟仿真对于工控自动化的意义很大,虽然市面上有很多的第三方软件比如Solidworks,Mathlab,ProE等等软件可以做仿真,而且能够实现的功能包括了流体分析,力学分析,摩擦力分析等等,这些都是我们自己写一个简单仿真软件无法实现的,然而如果要做一个标准的软件,我们就只能使用C++,C#,JAVA这些软件自己写了. ???? 仿真的意义在于可以提高编程效率,在空间轨迹规划部分,如果不能可视化的数据,我们就无法快速定位到错误,也无法直观的看到自己写的控制程序是否合理(在我的另一个

C#应用视频教程2.3 OPENGL虚拟仿真介绍

本节最重要的一个内容,就是让视野可以平移+旋转+缩放(就像打CS游戏一样以第一人称视角去观察物体,如果可能的话W,S,A,D四个按键控制人物移动,还有鼠标控制视角),本节最重要的一个概念就是设置观察视角(gl.LookAt函数,这个函数一共有九个参数,我们可以分成三组,第一组XYZ表示了眼睛的位置,第二组XYZ表示了物体的XYZ,第三组代表人眼睛的朝向,正常为(0,1,0),如果不用眼睛而是用相机作比喻,相机正常安装放置,也可以倒180度安装放置,则对应参数为(0,-1,0),也可以斜着放置,总

Android OpenGL ES(十二):三维坐标系及坐标变换初步 .

OpenGL ES图形库最终的结果是在二维平面上显示3D物体(常称作模型Model)这是因为目前的打部分显示器还只能显示二维图形.但我们在构造3D模型时必须要有空间现象能力,所有对模型的描述还是使用三维坐标.也就是使用3D建模,而有OpenGL ES库来完成从3D模型到二维屏幕上的显示. 这个过程可以分成三个部分: 坐标变换,坐标变换通过使用变换矩阵来描述,因此学习3D绘图需要了解一些空间几何,矩阵运算的知识.三维坐标通常使用齐次坐标来定义.变换矩阵操作可以分为视角(Viewing),模型(Mo