OpenGL

OpenGL简介

OpenGL为图形硬件提供软件接口,支持多种不同的硬件平台。OpenGL的客户端-服务器模式能够通过网络实现不同电脑之间的协同工作,客户端负责运行OpenGL程序,绘图任务则交给服务器端完成。
OpenGL的核心指令使用gl前缀,OpenGL Utility库的指令则使用glu前缀。所有的OpenGL常量均用以GL_开头的大写字母表示,此外,OpenGL函数调用时,用后缀制定参数个数和数据类型。

OpenGL渲染管道(Rendering Pipeline)

OpenGL管道包括一系列按次序执行的过程。顶点数据和像素数据这两种图形信息通过管道进行处理、融合并最终写入帧缓冲器。同时,OpenGL还能将处理后的数据回传给应用程序(如图中灰色虚线所示)。
OpenGL PipeLine

Display list(显示列表)

Display list是保存并编译好的一组OpenGL指令,这组指令将在后面执行。所有的几何(顶点)数据和像素数据都可以保存在display list中。

Vertex Operation(顶点操作)

每一个顶点和法向坐标均通过GL_MODELVIEW矩阵实现从物体坐标系(object coordinates)到视觉坐标系(eye coordinates)的转换。同时,如果使能了光照功能,每个顶点的光照值是通过转换后的顶点和法向数据计算得到的。光照值会更新顶点的颜色。

Primitive Assembly(图元装配)

顶点操作之后,图元(点、线和多边形等)经投影矩阵(projection matrix)作进一步转换,再被视体(viewing volume)裁剪平面进行裁剪,从而由视觉坐标系(eye coordinates)转换到裁剪坐标系(clip coordinates)。之后,通过除w的透视除法操作(perspective division by w)和视口转换(viewport transform),将3D场景转换到窗口空间坐标系中。最后,如果使能了筛选(culling)功能,就执行筛选测试(culling test)。

Pixel Transfer Operation(像素转移)

来自客户端内存的像素数据被读取后,将会执行一系列的尺度缩放、添加偏置、映射和钳位操作,这些操作即被称为像素转移。完成像素转移操作后的数据要么存储在纹理存储器中, 要么直接光栅化到段中。

Texture Memory(纹理存储器)

纹理图片先加载到纹理存储器中,然后应用到几何对象上。

Rasterization(光栅化)

光栅化是指从集合数据和像素数据到段的转换。段是包含了颜色、深度、线宽、点的尺寸和抗混叠计算(GL_POINT_SMOOTH, GL_LINE_SMOOTH, GL_POLYGON_SMOOTH)的一个矩形阵列。如果着色模式(shading mode)设置为GL_FULL,那么多边形的内部像素区域在这一阶段将被填充。 每个段定英语帧缓冲器的一个像素。

Fragment Operation(段操作)

渲染管道的最后阶段是将段转换到帧缓冲器。这一阶段的第一步是纹理生成,纹理存储器中生成的纹理元素应用到每个段中;下一步是雾计算(fog calculation),接下来是一组顺序执行的段测试,即剪刀测试⇒ α \alpha α测试⇒模板测试⇒深度测试。最后,经过纹理融合、抖动、逻辑操作和位掩码操作之后,真实的像素数据被保存到帧缓冲区中。

Feedback(反馈)

OpenGL提供的glGet*()和glIsEnabled()指令可以获取绝大多数的当前状态和信息。此外,glReadPixels()可以从帧缓冲区中读取一个矩形区域的像素数据, glRenderMode(GL_FEEDBACK)可以得到完全转换后的顶点数据,. glCopyPixels()不会将像素数据返回到特定的系统内存,但是可以将其复制到另一个帧缓冲区中,例如将首缓冲区的像素数据复制到尾缓冲区。

OpenGL变换

包括顶点位置和法向量的几何数据在执行光栅化之前,是通过OpenGL管道的顶点操作和图元装配进行变换的。
GL Transform

物体坐标系 Object Coordinates

物体坐标系是物体的局部坐标系,表示的只在进行各种变换之前物体在其局部坐标系下的初始位姿。可用glRotatef(), glTranslatef(), glScalef()等函数对物体进行变换。

视觉坐标系 Eye Coordinates

将物体坐标系左乘GL_MODELVIEW矩阵即得到视觉坐标系。OpenGL通过GL_MODELVIEW矩阵将物体从局部物体坐标系变换到视觉坐标系中。GL_MODELVIEW实际上是模型矩阵(Model Matrix)和视觉矩阵(View Matrix)的组合。模型矩阵将物体从局部物体坐标系变换到世界坐标系,视觉矩阵再将物体从世界坐标系变换到视觉坐标系。
[ x e y e y e y e z e y e ] = M m o d e l V i e w ⋅ [ x o b j y o b j z o b j ] = M v i e w ⋅ M m o d e l ⋅ [ x o b j y o b j z o b j ] \left[ \begin{matrix} x_{eye} \\ y_{eye} \\ z_{eye} \end{matrix} \right] = M_{modelView} \cdot { \left[ \begin{matrix} x_{obj} \\ y_{obj} \\ z_{obj} \end{matrix} \right] } = M_{view} \cdot {M_{model}} \cdot { \left[ \begin{matrix} x_{obj} \\ y_{obj} \\ z_{obj} \end{matrix} \right] } xeyeyeyezeye=MmodelViewxobjyobjzobj=MviewMmodelxobjyobjzobj
为了计算光照,法向量也从物体局部坐标系变换到视觉坐标系。注意,法向量的变换矩阵不是GL_MODELVIEW,而是它的逆的转置。
[ n x e y e n y e y e n z e y e ] = ( M m o d e l V i e w − 1 ) T ⋅ [ n x o b j n y o b j n z o b j ] \left[ \begin{matrix} nx_{eye} \\ ny_{eye} \\ nz_{eye} \end{matrix} \right] = {\left({M_{modelView}}^{-1}\right)}^T \cdot { \left[ \begin{matrix} nx_{obj} \\ ny_{obj} \\ nz_{obj} \end{matrix} \right] } nxeyenyeyenzeye=(MmodelView1)Tnxobjnyobjnzobj

裁剪坐标系 Clip Coordinates

视觉坐标系左乘投影矩阵GL_PROJECTION即可变换到裁剪坐标系。 GL_PROJECTION定义了一个视锥体,它体现了顶点数据是如何(通过透视投影或者正交投影)投影到屏幕上的。之所以称裁剪坐标系是因为投影之后的顶点(x, y, z)会进一步根据 ±w的大小作裁剪。
[ x c l i p y c l i p z c l i p ] = M p r o j e c t i o n ⋅ [ x e y e y e y e z e y e ] \left[ \begin{matrix} x_{clip} \\ y_{clip} \\ z_{clip} \end{matrix} \right] = M_{projection} \cdot { \left[ \begin{matrix} x_{eye} \\ y_{eye} \\ z_{eye} \end{matrix} \right] } xclipyclipzclip=Mprojectionxeyeyeyezeye

归一化设备坐标系 Normalized Device Coordinates (NDC)

将裁剪坐标系的坐标值除以w记得到归一化设备坐标系的坐标值,这一步又叫做透视除法。归一化设备坐标系更加类似窗口(屏幕)坐标系了,只是还没有平移和缩放到屏幕像素。三个坐标的坐标值都被归一化到-1和1之间。
[ x n d c y n d c z n d c ] = [ x c l i p / w c l i p y c l i p / w c l i p z c l i p / w c l i p ] \left[ \begin{matrix} x_{ndc} \\ y_{ndc} \\ z_{ndc} \end{matrix} \right] = \left[ \begin{matrix} x_{clip} / w_{clip} \\ y_{clip} / w_{clip} \\ z_{clip} / w_{clip} \end{matrix} \right] xndcyndczndc=xclip/wclipyclip/wclipzclip/wclip

窗口(屏幕)坐标系 Windows Coordinates (Screen Coordinates)

归一化设备坐标(NDC)经视口变换(viewport transformation)即得到窗口坐标。NDC坐标需经过缩放和平移以适应屏幕显示。窗口坐标最终经过OpenGL管道的光栅化过程变成一个段。glViewport()指令定义了最终图片映射到显示窗口的矩形区域,而glDepthRange()则确定了窗口坐标的z值。窗口坐标系的坐标值通过glViewport(x, y, w, h) 和glDepthRange(n, f)两个方程的给定参数计算得到。
[ x w y w z w ] = [ w 2 x n d c + ( x + w 2 ) h 2 y n d c + ( y + h 2 ) f − n 2 z n d c + f + n 2 ] \left[ \begin{matrix} x_{w} \\ y_{w} \\ z_{w} \end{matrix} \right] = \left[ \begin{matrix} \frac{w}{2} x_{ndc} + (x + \frac{w}{2}) \\ \frac{h}{2} y_{ndc} + (y + \frac{h}{2}) \\ \frac{f-n}{2} z_{ndc} + \frac{f+n}{2} \end{matrix} \right] xwywzw=2wxndc+(x+2w)2hyndc+(y+2h)2fnzndc+2f+n
视口变换(viewport transform)公式可简单地由NDC和窗口坐标系之间的关系给出:
{ − 1 → x 1 → x + w { − 1 → y 1 → y + h { − 1 → n 1 → f \begin{cases} -1 \rightarrow x & \\ 1 \rightarrow {x + w} \end{cases} \begin{cases} -1 \rightarrow y & \\ 1 \rightarrow {y + h} \end{cases} \begin{cases} -1 \rightarrow n & \\ 1 \rightarrow f \end{cases} {1x1x+w{1y1y+h{1n1f

OpenGL变换矩阵

OpenGL由4x4的矩阵来表示一个变换。值得注意的是,在OpenGL中,变换矩阵的16个元素是以列优先的1维数组形式存储的. 如果要转换成标准的行优先的矩阵形式,需要对其做转置。
[ m 0 m 4 m 8 m 12 m 1 m 5 m 9 m 13 m 2 m 6 m 10 m 14 m 3 m 7 m 11 m 15 ] \left[ \begin{matrix} m_0 & m_4 & m_8 & m_{12} \\ m_1 & m_5 & m_9 & m_{13} \\ m_2 & m_6 & m_{10} & m_{14} \\ m_3 & m_7 & m_{11} & m_{15} \end{matrix} \right] m0m1m2m3m4m5m6m7m8m9m10m11m12m13m14m15

OpenGL共有GL_MODELVIEW、GL_PROJECTION、GL_TEXTURE和GL_COLOR这四种不同的矩阵。在代码中通过使用glMatrixMode()函数来切换当前矩阵类型。例如,调用glMatrixMode(GL_MODELVIEW)即可选择GL_MODELVIEW矩阵。需要特别注意的是,OpenGL在对一个顶点做多个变换时,是按照与变换次序相反的次序进行矩阵相乘的。例如,如果对一个顶点先做 M A M_A MA变换,再做 M B M_B MB变换,那么OpenGL先做 M B × M A M_B \times M_A MB×MA,再与顶点相乘。因此在代码中后一个变换写在前面,前一个变换写在后面。

// Note that the object will be translated first then rotated
glRotatef(angle, 1, 0, 0);   // rotate object angle degree around X-axis
glTranslatef(x, y, z);       // move object to (x, y, z)
drawObject();

OpenGL投影矩阵

概述

因为计算机显示器是个2维平面,因此OpenGL产生的3维场景必须投影变换才能在2维屏幕上显示出来。投影矩阵GL_PROJECTION即是用来完成这一投影变换的。首先,它将顶点数据从视觉坐标系变换到裁剪坐标系,然后将裁剪坐标系坐标除以比例因子w变换到NDC坐标系。

投影变换

在投影变换中,视觉坐标系的椎体空间中的3D点被映射到NDC坐标系的立方体空间中,x坐标的范围从[l, r]映射到[-1, 1],y坐标的范围从[b, t]映射到[-1, 1],z坐标的范围从[-n, -f]映射到[-1, 1]。
GL Projection Matrix

透视投影矩阵 (GL_PROJECTION)

透视投影矩阵的一般形式如下:
M p r o j e c t i o n = [ 2 n r − l 0 r + l r − l 0 0 2 n t − b t + b t − b 0 0 0 − f + n f − n − 2 f n f − n 0 0 − 1 0 ] M_{projection} = \left[ \begin{matrix} \frac{2n}{r-l} & 0 & \frac{r+l}{r-l} & 0 \\ 0 & \frac{2n}{t-b} & \frac{t+b}{t-b} & 0 \\ 0 & 0 & -\frac{f+n}{f-n} & -\frac{2fn}{f-n} \\ 0 & 0 & -1 & 0 \end{matrix} \right] Mprojection=rl2n0000tb2n00rlr+ltbt+bfnf+n100fn2fn0
如果视体是对称的,透视投影矩阵可简化为以下形式:
M p r o j e c t i o n = [ n r 0 0 0 0 n t 0 0 0 0 − f + n f − n − 2 f n f − n 0 0 − 1 0 ] M_{projection} = \left[ \begin{matrix} \frac{n}{r} & 0 & 0 & 0 \\ 0 & \frac{n}{t} & 0 & 0 \\ 0 & 0 & -\frac{f+n}{f-n} & -\frac{2fn}{f-n} \\ 0 & 0 & -1 & 0 \end{matrix} \right] Mprojection=rn0000tn0000fnf+n100fn2fn0

参考链接

songho’s notes on OpenGL

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值