《视觉开发专题》之 OpenGL 3D动画绘制&图形学概念的理解

知识前导

计算机图形学的终极目标——讨好人类视觉系统

  最近在啃的书中有一本叫《计算机图形学 原理及实践》,这本书让我深有感触的是其绪论中对计算机构建真实感图像的理解:我们所致力的最终目标,是视觉形式的交流,而且主要都是与人的交流。 这句话的潜台词是:在求解图形学问题和构建模型时需考虑人类视觉系统的影响。 我个人还是深有启发的。

  比如视觉停留,60HZ刷新频率就不会感到卡顿;比如最小角分辨率约为1弧度,300ppi以上的屏幕就很难有颗粒感了;比如只能感受一定频率范围的可见光,红外紫外各种射线人类都看不到;比如人感光细胞每次接收光子的能量累积到一定量才会产生神经信号,微弱的光需要放大瞳孔注视良久才看得清;比如一幅平面素描画也能让人产生立体感,这不仅仅是光阴特效可以做到,其实任何刺激,只要能触发视觉系统大致正确的反应,都能被识别并在大脑中形成某种感知,也正是我们视觉系统的强大自适应能力,允许我们在很多计算做不到完全仿真(比如光照)的情况下,采取一种合理的近似,依然让结果看起来令人满意。

  正是人类视觉系统的特点,决定了当今所有可视设备从硬件到软件一切的设计和进化方向。建议大家在学习一门新知识时也可以尝试跳出来,俯瞰一下这个领域的知识版图和发展方向,了解一下“从哪里来,到哪里去的”的背景,说不定会让你有新发现,比如再看到某些复杂的设计,会豁然开朗。开胃菜就到这了,下面进入我们今天的正题。

案例&知识点一览

几种图元:

3D 动画:

上面两个效果的源码实现我都放在 这里了。如果你有收获,记得留个 star 以资鼓励~

这是 视觉专题 的第二篇,上面两个案例是使用固定管线实现的。之所以用固定管线实现,一是因为可以更快的实现效果,再者可以避免因不熟悉 GLSL 语法而干扰到对渲染流程的理解。 案例涉及到的知识点有:

  1. OpenGL 坐标系统
  2. OpenGL 矩阵变换
  3. OpenGL 基本图元
  4. OpenGL 渲染技巧
  5. OpenGL 纹理映射

结合提供的两个案例阅读完(还不够 需要你带着思考去实践、求证)本篇内容,你将收获:

  1. OpenGL 固定管线的使用
  2. OpenGL 基本图元的使用
  3. OpenGL 纹理的简单使用
  4. OpenGL 几种渲染技巧的优劣及使用
  5. OpenGL 矩阵变换与坐标转换的关系

  这里感谢一下 CC老师_HelloCoder (一只温柔的胖C) 提供的视觉课程和资源,为我快速入门图形编程找到了方向。

  强烈建议下载我为你准备好的 案例源码,先跑起来看看每一种效果,再结合文章和自己的理解,亲自尝试不同的参数带来的变化,然后改成你希望的样子。

注: 这不是一篇代码注释和API用法讲解的文章,该有的注释源码里都为你写好了,搜索引擎一次就能找到答案的问题也不需要我在这浪费篇幅来写。此篇的重点是:对各个知识模块有初步认识的基础上,进一步加深对重点知识点的理解。


一. OpenGL 坐标系

1. 为什么需要坐标系?

  In short, the real world we all, because of the presence of coordinate system can be abstracted into quantifiable values: location, length, speed, space and time. To the deep-speaking, this should wander Einstein's relativity theory, popular point that we recognize the coordinate system is the cornerstone of a multi-dimensional world, it can provide a visual description of the time and space for us. Of course, more than four-dimensional coordinate system and go from space to imagine if, at the current universal human cognition, is difficult to understand, for the time being they are seen as matrix strike, we believe that some bigwigs of linear algebra than I do.

2. What are the coordinates

Model / object space coordinate system : For convenience of calculation, the center will usually select the modeled object as the origin of the coordinate system, such that all the model points are located in the xyz coordinate between -0.5 and 0.5. For example, we will be modeled as a dice cube to cube center of origin (not specified, but to make it easier to calculate it), the establishment of a right-handed coordinate system , as the dice model space coordinate system . The coordinates for all vertices dice gives coordinate information.

Scene spatial coordinate system : all object models will be present in one or more of the scene (object model and a light source consisting of a series), the system comprising a coordinate space of a scene is the scene spatial coordinate system , particularly (open your imagination space): for the above dice, if it is currently on a table (assuming that the desktop is a regular rectangular), the table is located in the center of the room (assuming that room is rectangular), located in the center of the desktop of the dice, this time in the ground at the center of the room as the origin established right-handed coordinate system as the scene space coordinates , y coordinates of the desktop assumed 5, then the values of all the above model vertex coordinate y coordinate system dice plus 5, it is obtained with respect to coordinate this scenario spatial coordinate system.

相机空间坐标系:依然使用上述房间作为场景,如果我们需要显示(看到)桌面上的骰子,那么就一定要在房间中合适的位置放置相机(我们的眼睛),这个合适的位置(坐标)也是相对于场景坐标系的。现在以相机镜头(我们的眼睛)所在点为原点,新建立一个 右手坐标系(镜头朝向/眼睛直视的方向为 z 轴负方向),使得上述场景空间中的所有景物均可以表示为这一坐标系中的坐标,该坐标系我们称为相机空间坐标系

像素空间坐标系:上述场景中所有可见景物(落入平截椎体内的点)的相机坐标最后会被转换为规格化设备坐标 (NDC),在该坐标系中,可见景物的 x、y 坐标被表示成 -1 和 1 之间的浮点值,z 坐标为负值。( x、y超出[-1,1]范围的不在相机 (眼睛) 的视域内;z > 0 的景物在相机 (眼睛) 后面),然后这些可见的点会被变换为像素坐标,就是我们看得到的屏幕上的像素点(视网膜里对应的图像),屏幕上的像素点坐标系(通常(0,0)位于左上角)就是像素空间坐标系
  注意:在标准化设备坐标系中 OpenGL 使用的是左手坐标系(投影矩阵交换了左右手)。

3. 坐标系之间的变换关系

  上述坐标系在计算机图形学中,与图形数据到显示输出的几个步骤一一对应,仅凭这段描述肯定不足以完全理解它们之间的变换关系,这张图展示了整个流程以及各个变换过程做了什么:

  简单说明下坐标系变换的过程:

  1. 将 camera 移到准备拍摄的位置并调好方向(视图变换,view transform)
  2. 将准备拍摄的对象移到场景必要的位置上(模型变换,model transform)

第1、2步是同一件事的两种实现方式:物体不动相机动/相机不动物体动,所以通常将这两步合并为一步——视图模型变换(model-view transform),该过程的结果就是构建一个独立的、统一的空间系统,将场景中所有的物体都变换到场景空间坐标系中。

  1. 设置相机的焦距,或调整缩放比例(投影变换,projection transform)
  2. 对结果图像进行拉伸或挤压,将它变换到需要的大小(视口变换,viewport transform),与第3步不同的是,3是改变捕获场景的范围,而这里是对结果的变形。

  重点来了,敲黑板:第3步设置的焦距或缩放比例,其实是在设置相机取景时 视锥体(上图中的四角椎体) 的大小,图中阴影部分为平截椎体(frustum),在平截椎体以外的物体都会被去除,如果某个图元正好穿过平截体的某个面,OpenGL 将会对此图元进行剪切(clip),这是 OpenGL 的 特性,可以解决靠近相机的物体会无限大的问题,再者,不绘制过远或超出视域范围的物体,可以改善渲染的性能以及深度精度。此外,第3步还计算了用于透视投影(近大远小效果)的参数(齐次坐标(x,y,z,w)中的 w)。

4. 补充

补充(一):投影方式
  上述过程是透视投影的形式,还有一种叫正交投影/正射投影/正投影,主要用于保持物体真实大小以及相互之间角度的场景,比如建筑设计图和计算机辅助设计的领域,这里就不赘述了。它们投影方式的区别如下:

Supplementary (B): homogeneous coordinates
  the perspective projection mentioned above, we believe we near the far smaller no strangers effect, because the light of all the scenes with our pupil onto the retina into the final image, are perspective projection the result of. However, in the projected space, it will produce many results contrary to the inductive Euclidean space, such as two coplanar parallel lines intersect:

Two rails pitch becomes far as the line of sight is reduced, until intersecting the horizon (point at infinity).

  Perspective space geometrical distortions, if not combined matrix multiplication and addition operations, very complex calculations. To solve this problem, German mathematician (August Ferdinand Möbius) made homogeneous coordinates: using N + 1 to represent the amount of N-dimensional coordinates . For example, in a two-dimensional homogeneous coordinate system, we introduce a component w, a two-dimensional point (x, y) is represented as (X, Y, w) form, conversion relationship which is:

x = X/w
y = Y/w
复制代码

  In the homogeneous coordinates of the last component of 0 may represent the point at infinity: (x, y, 0) . Homogeneous coordinates are allowed to translation, rotation, scaling, and perspective projection and the like represented as a matrix vector multiplication general vector operation , which is an advantage not available in Cartesian coordinates. In short, its main importance is twofold: One is the distinction between vector and point; the other is easy affine transform (Affine Transformation).

Why can distinguish between vector and point? Why is it easier to affine transformation? This is a summary of your doubts: homogeneous coordinate transformation matrix . If you do not have permission to download the document, please leave a message in the comments section, I made a complete PDF private to you.

Two. OpenGL matrix transform

Pull so much, in the end is how the correspondence between the affine transformation matrix operations that the object of it, let's look at each dismantling.

1. Matrix Review

  The basic rules of matrix multiplication:

  From the chart rules is not difficult to draw the following conclusions:

  • m x n * n x k = m x k
  • 矩阵乘法的前提条件需满足 m x n * n x k 的形式, 即被乘矩阵的列数要等于相乘矩阵的维数,n维向量也可以看做 n x 1 的矩阵
  • 矩阵的乘法是不可交换的,即AB≠BA
  • 矩阵的乘法遵循结合律:C(BA)=(CB)A=CBA,所以多个变换矩阵可以直接按序相乘,得到最终的变换矩阵,进而减少计算次数来提升程序性能

2. 各种变换与矩阵的映射关系

平移

  上图所示的是一个4x4的单元矩阵,任何4维向量乘以该矩阵得到的仍然是其本身,类似的,如果我们希望将物体沿着 x 轴正方向平移1,而 y 和 z 保持不变,就将该物体的所有顶点 v:(x,y,z,1) 乘以该矩阵:
类似地,其他轴方向的平移以此类推。

缩放

  如果你理解了上面平移的计算过程,缩放的矩阵其实也很好推理,比如我们希望将一个物体变换为原来大小的3倍,就将该物体的所有顶点 v:(x,y,z,1) 乘以该矩阵:

  因为每个分量是单独控制的,你完全可以通过修改不同分量的值来达到不同方向不同缩放比例的效果。另外,如果缩放时物体中心不在 (0,0,0) 处,那么缩放也会使物体远离或者靠近 (0,0,0),如果不想改变物体距离原点的距离,可以用上面刚学过的平移矩阵先将物体中心移至原点处,然后再缩放,最后再用平移矩阵的逆矩阵将物体移回原位即可。

旋转

  假设你理解了上面提到的齐次坐标以及上述矩阵运算与线性变换的关系,那么将物体所有顶点坐标乘以下面这个矩阵,来猜猜是什么操作?

  The answer is that the object rotation around the z axis anticlockwise θ °. do not understand? Eyes closed, rotation about the z-axis is not to do all the vertices in the xy plane of rotation? It is not equivalent to its every point around the two-dimensional coordinate system origin counterclockwise θ °? A few questions to determine the unknown? This is actually a road of high school math: How to get the point p (x, y) to θ ° rotation about the origin (here, the counterclockwise rotation) coordinate point p` (s, t) is. Let's look at direct proof of it ... in fact, I froze for a long time to understand (╮ (╯ ▽ ╰) ╭ probably returned to high school math teacher math)
  The above-described calculation process of rotating around the z axis, if you find out, then around the x-axis, y-axis rotation also goes without saying. Combined with the above known binding law, while supporting a package around x, y, z specified number of degrees of rotation function is not difficult: sequentially by multiplying the three matrices. Further, similar to the scaling effects, if not at the origin center of the object rotation, has an effect of rotating the object while the overall position of rotation about the origin of:
Solution also: the center of the object to move to the origin, and then be moved back end of the rotation:

Perspective projection

  Compared to the previous translation, scaling and rotation, the conversion process is relatively complicated, but do not panic, we just need to determine a transformation matrix to the vertex, because the linear relationship is universal. Perspective projection There are two cases to consider:

  1. Central symmetrical frustum, z axial central position of the vertebral body.
  2. Asymmetrical frustum, similar we sat looking out the window of a train in the very center of the scenery, the windows are not positive for our eyes.

Let's consider the first case:

Our goal is to calculate the apparent cone points projected onto the near plane corresponding to the coordinates of the point. Suppose near plane width, height, Z values of width, height, Z near, far plane Z value Z FAR. Combined with spatial geometry knowledge can easily come to their correspondence is as follows:
  For the second case, in fact, based on the former location near the plane of the pan in the xy plane only, if the position of the near plane (a rectangle) with the top, left, right, bottom to represent in the xy plane, then the transformation matrix the third component of the x and y dimensions of z to make a corresponding adjustment of the position near plane:
If you understand this, you will thoroughly mastered frustum the use of family function. If you have not thoroughly understood completely without doubt yourself, my stupid brain is almost unfinished play a papyrus was clear - I believe you have the basis of linear algebra, these are a piece of cake.

3. The matrix of understanding

  Currently we are exposed to the most fundamental matrix graphics are simple applications, in-depth understanding of matrices, linear algebra class university is not fraught I would not be here (in catching up ...), there is little to be learned experience to share with everyone. Meng Yan recommend you first read the teacher wrote understand matrix . (A total of three, a recommendation from the beginning to see, bloggers through intuition rather than abstract way, the very thorough relationship vector coordinate matrix set forth: essential feature space that houses the movement, the nature of the matrix is a linear space a linear transformation is described in a linear space, as long as we select a set of base, then for any linear transformation, are able to be described by a matrix determined.) in short, a selected linear space after group, vectors characterize the object, the object transformation matrix characterization, matrix multiplication of the vector to complete the conversion. Of course, understanding and thinking, not necessarily entirely correct, or that there must be some place is not rigorous, but it can still provide a lot of valuable reference for us to better understand the matrix.

PS: the original really burning brain can have the pleasure ... emmm Do not ask how I know.

Three. OpenGL rendering rule base primitive &

In front of the hoe are Kenwan, slow to learn we relaxed a slow ~

1. What is primitive

  Since OpenGL role is primarily to frame buffer graphics rendering them, it needs complex object into smaller base unit, the unit is small primitive . It comprises three forms: points, lines, and triangles . When the distribution density thereof is sufficiently high, it can be expressed in the form of 2D and 3D objects. OpenGL rendering function is included in many of these primitives, these functions allow us to determine the primitive layout in memory, rendering and rendering taken the form of the number, or even the same set of primitive copied in a function call quantity.

  Points, lines and triangles are most graphics hardware (GPU) support base element type direct rasterization operation, OpenGL supports other types of elements, e.g. Patch and the adjacent elements, but these are not directly raster oriented, introduced here this front three primitive types today.

2. What are ways to draw

point

  A point is a four-dimensional homogeneous coordinates. Thus, the area of the point does not actually exist, it is in OpenGL simulated by a quadrangular region on a display screen (or draw cache). When rendering primitives time point, OpenGL will be determined by a series of rasterization rule point pixel positions covered, to simulate this point quadrilateral side length, by glPointSize()setting the default size 1.0, may be colored by changing a value of the write vessel.

Line, the strip line and the circulation line

  Separate line expressed by pair of vertices, a plurality of vertices can be represented by a series link connection, the called end-closed circulation line (line loop), called the open end to end strip lines (line strip). And point Similarly, there is no line area In principle, it is also required special rules to determine the value of the pixel which will affect the rasterization. Can glLineWidth()be set to the line width, the default value is 1.0. Suppose the width of the line is n (n> 1), then the line segment will be replicated n times horizontally or vertically, depending on the direction of the copy is the main extension direction of line X (horizontal) or Y (vertical).

  简单概括线段光栅化的规则diamond exit):假设每个像素在屏幕上的方形区域中都存在一个菱形,当对一条从点 A 到点 B 的线段进行光栅化时,若该线段穿过了菱形的假想边,那么这个像素就应当被影响——除非菱形中包含的正好是点B(即线段的末端点位于菱形内)。所以,此时继续绘制另一条从点 B 到点 C 的线段,B点所在的像素也只会更新一次。该规则也是边缘产生锯齿的本质原因——非水平非垂直的斜线段会有一些像素点的菱形假想边未被连线穿过,这些像素点就不会参与光栅化,进而出现一些像素的缺失,就是我们看到的锯齿。关于如何抗锯齿后面再详细说。

三角形、条带与扇面

  三角形之于 OpenGL 初学者而言,就像是每个程序员最初接触程序时的 hello world一样。它是构成一切复杂3D图形的基本结构,当我们渲染多个三角形时,每个三角形与其他三角形完全独立。三角形的渲染是通过三个顶点到屏幕的投影的连线来完成的,如果屏幕像素的采样值位于投影连线的三角形边的内侧半空间内,那么它才会受到光栅化处理,这意味着:

  • 两个三角形共享了一条边(即共享了一对顶点),那么不存在任何采样值能同时位于这两个三角形内。
  • 三角形共享边的光栅化过程不会产生任何裂缝,也不会重复进行绘制。(重复绘制会导致诸如颜色混合计算结果错误等问题)

  这对于三角形条带(triangle strip)或扇面(triangle fan)的光栅化过程非常重要。三角形条带从第四个顶点开始,会与上一个三角形的后两个顶点构成新的三角形,以此类推:

  渲染 扇面时,第一个顶点会作为一个共享点存在(比如画圆它就是圆心),它将作为每一个后继三角形的组成部分,之后每两个顶点都会与这个共享点组成新的三角形:
  三角形条带与扇面可以表达任何复杂程度的凸多边形性状。

总结如下:

  图中 GL_POLYGONGL_QUADS 分别是多边形和四边形的链接方式。赶紧结合提供的 案例 ,亲自体验一下每种图元的使用和适用场景吧。

四. OpenGL 渲染技巧

1. z-fighting

  在渲染立体图形时,都会开启深度测试glEnable(GL_DEPTH_TEST),深度 z 的大小决定了物体距离观察者的远近,进而影响其在近平面上的投影。对于不透明的物体而言,当投射路径上有多个表面叠加时,最近的表面才会被看见。但深度不同的表面之间也并不是永远都是这么相安无事。

  由于硬件的浮点数精度支持是有限的,因此当投射到同一个点的两个顶点的 z 值非常接近时,虽然在数学上深度值是不同的,但在计算机中可能认为是相同的,特别是透视变换之后 z 值的精度可能会变低,这个现象对多个像素都有影响,所以会导致显示结果闪烁交叠的情况。尽管并不常见,但如果遇到也要记得排查这种可能。

  其实投影变换对每个方向的坐标都会在一定程度上降低精度:距离近平面越远则精度则越低。举个通俗的例子:越远的物体你越看不清细节。

2. 正背面剔除

  在基本图元的绘制方式中,每个多边形都有两个面:正面和背面,OpenGL 默认多边形正面的顶点方向是逆时针排列的:glFrontFace(GL_CW)。你也可以通过glFrontFace(GL_CW)来设置顺时针为正面,你要清楚这一设置的代价。

  像球、环形体和茶壶等都是由方向一致的多边形组成的,即完全是逆时针,或者完全顺时针的。而莫比乌斯带克莱因瓶则不是。假设现在有一个不透明的正方体,构成它表面的多边形顶点方向都是逆时针的,经过透视投影到近平面上之后,有一部分顶点的方向变成了顺时针:没错,就是这部分顶点构成了你看不见的那部分——背面,它们永远都会被正面所遮挡:

  看不见的顶点可用通过设置剔除背面glCullFace(GL_BACK)+开启面剔除glEnable(GL_CULL_FACE)直接抛弃掉,这可以极大的提高绘制性能。当然,你完全可以剔除正面:GL_FRONT 或者所有多边形:GL_FRONT_AND_BACK。必要的时候通过glDisable(GL_CULL_FACE)来关闭面剔除,比如绘制透明的物体。

  更多通过glEnable()glDisable()来开启和关闭的可选参数类型参考这篇

  从更专业的角度来讲,判断多边形的面是正面还是背面,是依赖这个多边形在窗口系统下的面积计算。计算公式及其说明(了解即可):

3. 颜色混合

颜色理论

  买过显示器的你多半见过这个参数:色数,标值通常是 1677万 或 10.7亿,那这个数字代表什么又是怎么来的呢?这与计算机图形学有什么关系呢?

  绝大多数显示器使用的都是组合三原色(红、蓝、绿)的方法来构成颜色值,它们构成了显示器的整个颜色域,我们称其为 RGB 颜色空间,并且使用这三种颜色的组合来表达每一种颜色。我们能只使用这三种颜色来表达如此庞大范围的可见光谱的理由是,这三种颜色非常接近于人眼光锥细胞的响应曲线的中心区域。这一点与本篇开篇提到的思想完全一致。

  OpenGL 中在 RGB 三个分量之外增加了第四个分量 alpha ,即 RGBA 颜色空间。作为补充 OpenGL 还支持 sRGB 颜色空间。

Answer a few questions in front of . In the real physical world, the frequency and intensity of light is continuously changed, so that the number of color values which is equal to infinity. But for the computer, its frame buffer resources are limited, so only continuously varying intensities of quantized to limit the number of colors that can be displayed. Assigned to each component used to represent the size of the range of intensity called pixel depth ( 'bit depth) . For example, each color component with 8bit ([0,255]) to preserve its strength, the three color components (except the alpha component) total number of colors that can be represented is 2 ^ 2 ^ 8 * 8 * 8 = 2 ^ 2 ^ 24 = 16777216 ≈ 1677 million and the number of colors corresponding 10bit is 1.07 billion a. Now the mainstream of the displays are 8bit.
  This means that each pixel of at least three bytes of data storage, any specific type of color buffer to the total amount of recording data of each pixel on the screen is always the same.

Be melt-mixed
  If an input tile by tile all relevant testing, then it may be combined with the color values currently in the cache of some algorithm. The simplest is the default way is to directly overwrite the existing value (in the case of opaque or open depth testing, which can not be regarded merger). If we are to achieve transparency effects pieces of colored glass overlay, you must first enable glEnable(GL_BLEND)color mixing, and then specify a color mixing algorithms, such as: glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)available values of the parameters are as follows:

Be melt-mixed using an API associated description herein describes the parameters and not carried out, and then explained in detail in the following section relates to. First combined case to understand simple to use.

V. texture

  The basic concept and use on textured This section explains the sufficient detailed and easy to understand, and I would always kind of forced to write something superfluous taste - so here it is a direct reference to it. Of course, the best source is recommended that bind to look at the specific case of realization, and then modify it to read yourself to verify their understanding is correct.

VI. Summary

  Cipian provided two cases are more related to knowledge, thorough grasp every point is not easy, just started learning are often the most taboo headlong into a dead drill point, it is easy to get stuck halfway difficulty then. Therefore, the main purpose of this post is that they get to know what and how to use . I try to put them together into the actual scene to describe, first, hoping to promote your understanding, and secondly to be able to string together various knowledge, then help you have a basic overall view of the entire graphics.

  Knowledge really is blind everywhere in the new field. Honestly, in the course of writing this article, my mind is filled with this expression ~

Although the speed of updating the article and therefore a lot slower, but the bottom line is responsible for the reader must adhere to, the feeling of pain and happiness it is probably the case. But the level is really limited, or it is inevitable there will be expressed in the text is not clear enough even understand the question errors and typos, I hope you can forgive me and point out the problem, very grateful ~

Willing to help you gain a little more.

The picture below last year I went on vacation Yulong Snow Mountain in Yunnan, a landscape along the way, to show you once again the issue of "parallel lines intersect at infinity" of ... ha ha ha ~

Reproduced in: https: //juejin.im/post/5ce4a8cef265da1bca51b159

Guess you like

Origin blog.csdn.net/weixin_34290352/article/details/93172149