OpenGL-坐标系

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了OpenGL-坐标系相关的知识,希望对你有一定的参考价值。

参考技术A

在显示器的屏幕窗口上定义一个对齐的矩形的视口,OpenGL会自动建立 世界窗口 视口 的变换(包括缩放和平移)。当世界窗口中所有对象都被绘制时,对象在世界窗口中的部分会被 自动地映射 到视口中————换句话说,被 映射 到屏幕坐标中,即 像素在显示器上的坐标。

视口就是窗口内部用于绘制裁剪区域的客户区域

坐标系统从笛卡尔坐标到物理屏幕像素的映射是通过视口(viewport)的设置来指定

视口一般和窗口是等比的

正投影(Orthographics Projection)或平行投影

透视投影

OpenGL里 每个顶点的z,y,z都应该在−1到1之间,超出这个范围的顶点将是不可见

顶点坐标在转换为屏幕坐标之前会变换多个坐标系统( Coordinate System ),之所以引入 过渡坐标系 是为了更加方便操作和运算

共有5中比较重要的坐标系系统

将顶点从一个坐标系转换到另一个坐标系需要用到几个变换矩阵,其中几个比较重要的是 模型(Model)、观察(View)、投影(Projection)三个矩阵

物体顶点 的起始坐标按序经过上述5个坐标系系统最终转换为 屏幕坐标

图形学中的几个比较重要的坐标系:

1.世界坐标系
它是一个特殊的坐标系,它建立了描述其他坐标系所需要的参考系。也就是说,可以用世界坐标系去描述其他所有坐标系或者物体的位置。所以有很多人定义世界坐标系是“我们所关心的最大坐标系”,通过这个坐标系可以去描述和刻画所有想刻画的实体。

世界坐标系又称 全局坐标系 或者 宇宙坐标系 。

2.物体坐标系
物体坐标系与特定的物体关联,每个物体都有自己特定的坐标系。不同物体之间的坐标系相互独立,可以相同,可以不同,没有任何联系。同时,物体坐标系与物体绑定,绑定的意思就是物体发生移动或者旋转,物体坐标系发生相同的平移或者旋转,物体坐标系和物体之间运动同步,相互绑定。

举例说明一下物体坐标系:我们每个人都有自己的物体坐标系,当我们决定要往前走的时候,每个人实际前行的绝对方向都不一样,可能是向北,也可能向南,或者其他方向。这里前后左右是物体坐标系中的概念。当告诉张三往前走,就是张三同学沿着自己物体坐标系的前方运动。至于张三往前走是往东还是向北,这是张三的运动在世界坐标系下的描述。

这个立方体的物体坐标系如图所示,不论该立方体位于世界坐标系的任何位置,处于什么角度,物体坐标系与物体都是绑定在一起。
物体坐标系又称模型坐标系

3.摄像机坐标系

4.惯性坐标系
惯性坐标系是为了简化世界坐标系到惯性坐标系的转化而产生的。惯性坐标系的原点与物体坐标系的原点重合,惯性坐标系的轴平行于世界坐标系的轴。引入了惯性坐标系之后,物体坐标系转换到惯性坐标系 只需旋转 ,从惯性坐标系转换到世界坐标系 只需平移 。
从惯性坐标系转换到世界坐标系只需要平移

物体坐标/对象坐标(Object Space)
|
模型变换(transformation)
|
世界坐标(World Space)
|
视变换(Viewing)
|
观察者坐标/摄像机坐标(Eye Space)
|
投影变换(Projection transformation)
|
裁剪坐标(Clip Space)
|
透视除法(Perspective divide)
|
规范化设备坐标(NDC Space)
|
视口变换(ViewPort mapping)
|
屏幕坐标(Screen space)

用户自定义变换(在 顶点着色器 中完成)
Attribute -> Vertex -> 模型变换(Model Space) -> World Space > Camera Space -> Clip Space
|
OpenGL变换( 顶点着色器处理后 的阶段完成)
透视除法(Clipping) -> NDC Space -> Window Space -> Render

视口变换:
使用 glViewPort 内部的参数来将标准化设备坐标映射到屏幕坐标,每个坐标关联一个屏幕上的点的过程

Android--OpenGL坐标系

Android 手机中的坐标系(竖屏与横屏):

  

OpenGL 顶点坐标系(竖屏与横屏):

 

OpenGL 纹理坐标系(竖屏与横屏): 

 

一、世界坐标系(World Coordinates)

学名:右手笛卡尔坐标系统。

在OpenGL中,世界坐标系是以屏幕中心为原点(0, 0, 0),且是始终不变的。x轴正方向为屏幕从左向右,y轴正方向为屏幕从下向上,z轴正方向为屏幕从里向外。长度单位这样来定:窗口范围按此单位恰好是(-1,-1)到(1,1),即屏幕左下角坐标为(-1,-1),右上角 坐标为(1,1)。

进行旋转操作时需要指定的角度θ的方向则由右手法则来决定,即右手握拳,大拇指直向某个坐标轴的正方向,那么其余四指指向的方向即为该坐标轴上的θ角的正方向(即θ角增加的方向),在上图中用圆弧形箭头标出。

坐标变换矩阵栈:

用来存储一系列的变换矩阵,栈顶就是当前坐标的变换矩阵,进入OpenGL管道的每个坐标(齐次坐标)都会先乘上这个矩阵,结果才是对应点在场景中的世界坐标。OpenGL中的坐标变换都是通过矩阵运算完成的。 
如图: 

对象坐标系(乘以模型视图矩阵)--->眼睛坐标系(乘以投影矩阵)--->裁剪坐标系(除以w)--->标准设备坐标系(视口变换)--->设备坐标系

二、对象/模型/局部/绘图坐标系(object coordinate)

这是对象在被应用任何变换之前的初始位置和方向所在的坐标系,也就是当前绘图坐标系。该坐标系不是固定的,且仅对该对象适用。在默认情况下,该坐标系与世界坐标系重合。这里能用到的函数有glTranslatef(),glScalef(), glRotatef(),当用这些函数对当前绘图坐标系进行平移、伸缩、旋转变换之后, 世界坐标系和当前绘图坐标系不再重合。改变以后,再用glVertex3f()等绘图函数绘图时,都是在当前绘图坐标系进行绘图,所有的函数参数也都是相对当前绘图坐标系来讲的。如图则是对物体进行变换后,对象坐标系与世界坐标系的相对位置。

三、眼/照相机坐标系(eye coordinate)

模型变换:对象坐标系-->世界坐标系

视图变换:世界坐标系-->眼睛坐标系

GL_MODELVIEW矩阵是模型变换和试图变换矩阵的组合(view*model),因为没有单独的模型变换和视图变化,所以使用GL_MODELVIEW矩阵可以使对象直接从对象坐标系转换到眼睛坐标系。

为什么要转换到眼睛坐标系?

因为我们的观察位置没定,如果我们的眼睛(照相机)的位置不同,那么观察物体的角度则不同,看到的样子也不同,所有要有这一步,把场景与我们的观察位置对应起来。

默认情况下,眼睛坐标系与世界坐标系也是重合的。使用gluLookAt()则可以指定眼睛(相机)的位置和眼睛看的方向。该函数的原型如下:

1 void gluLookAt(GLdouble eyex, GLdouble eyey, GLdouble eyez, 
2                         GLdouble centerx, GLdouble centery, GLdouble centerz,
3                         GLdouble upx, GLdouble upy, GLdouble upz);

函数参数中,点(eyex, eyey, eyez)代表眼睛所在位置;
点(centerx, centery,centerz)代表眼睛看向的位置;
向量(upx, upy, upz)代表视线向上方向,其中视点和物体的连线与视线向上方向要保持。

注:

使用glTranslatef(),glScalef(), glRotatef()这些函数是对对象坐标系进行变动;使用void gluLookAt()是对眼坐标系进行变动,两者可以达到相同的变换效果。相当于对象不动移动相机,和相机不动移动对象。比如场景向x轴正方向移动1个单位(相机不动),相当于相机向x轴负方向移动一个单位(对象不动),glTranslatef(1.0, 0.0, 0.0) <=> gluLookAt(-1.0, 0.0, 0.0, ..., ... )。

四、裁剪坐标系(clip coordinate)

眼坐标到裁剪坐标是通过投影完成的。眼坐标通过乘以GL_PROJECTION矩阵变成了裁剪坐标。

投影分为透视投影(perspective projection)和正交投影(orthographic projection)

1>透视投影

类似日常生活看到的场景,远大近小。透视投影函数有两个:gluPerspective()和glFrustum()

1 void glFrustum(GLdouble left, GLdouble right,
2       GLdouble bottom, GLdouble top, 
3       GLdouble near, GLdouble far)
1 void gluPerspective(GLdouble fovy,  GLdouble aspect,
2           GLdouble near, GLdouble far) 

far, near是指近裁剪面(),远剪裁面离视点的距离(>0),fovy视角(通常为45),aspect = w/h

这个投影矩阵将给定的平截头体范围映射到裁剪空间,除此之外还修改了每个顶点坐标的w值,从而使得离观察者越远的顶点坐标w分量越大。被变换到裁剪空间的坐标都会在-w到w的范围之间(任何大于这个范围的坐标都会被裁剪掉)。OpenGL要求所有可见的坐标都落在-1.0到1.0范围内,作为顶点着色器最后的输出,因此,一旦坐标在裁剪空间内之后,透视除法就会被应用到裁剪空间坐标上:

 out=(x/wy/wz/w)

顶点坐标的每个分量都会除以它的w分量,距离观察者越远顶点坐标就会越小。这是也是w分量非常重要的另一个原因,它能够帮助我们进行透视投影。

2>正投影

1 void glOrtho(GLdouble left, GLdouble right,
2            GLdouble bottom, GLdouble top, 
3            GLdouble near, GLdouble far);

把物体直接映射到屏幕上,不影响它的相对大小。也就是图像反映物体的实际大小。

五、归一化设备坐标系(normalized device coordinate)

在裁剪坐标系下通过除以w分量得到,这个操作称为透视除法。得到的坐标值均为[-1,1]

Vclip=Mprojection⋅Mview⋅Mmodel⋅Vlocal。最后的顶点应该被赋值到顶点着色器中的gl_Position,OpenGL将会自动进行透视除法和裁剪。

六、屏幕坐标(screen coordinate)

屏幕坐标的x轴向右为正,y轴向下为正,坐标原点位于窗口的左上角。是归一化设备坐标系通过视口变换得到(viewport)

几何变换

OpenGL中可以使用的几何变换有平移、旋转、缩放三种。

glTranslatef(x, y, z);

该函数可以实现平移变换,x、y、z为各坐标轴上的平移量。

glRotatef(θ, x, y, z);

该函数实现旋转变换。θ为旋转角度,x、y、z为旋转轴。旋转方向由右手法则决定(参见第一节“坐标系”)。

glScalef(x, y, z);

该函数实现缩放变换。x、y、z为各轴方向的扩大量。若为负值,则沿着坐标轴的反方向进行缩放。

 

以上是关于OpenGL-坐标系的主要内容,如果未能解决你的问题,请参考以下文章

我的OpenGL学习进阶之旅OpenGL的坐标系的学习笔记

Android--OpenGL坐标系

Android--OpenGL坐标系

Android--OpenGL坐标系

OpenGL - 003坐标系简单理解

OpenGL ES总结OpenGL坐标变换之平移及旋转