OpenGL入门学习

  • 顶点数组对象:Vertex Array Object,VAO
  • 顶点缓冲对象:Vertex Buffer Object,VBO
  • 元素缓冲对象:Element Buffer Object,EBO 或 索引缓冲对象 Index Buffer Object,IBO

在这里插入图片描述请添加图片描述

在这里插入图片描述

  • 顶点缓冲对象(Vertex Buffer Objects, VBO),相当于某一类演员(如GL_ARRAY_BUFFER):管理顶点数据所在的内存,它会在GPU内存(通常被称为显存)中储存大量顶点。
  • 顶点数组对象(Vertex Array Object, VAO),相当于导演的角色,不需要告诉他为谁服务
    • 可以像顶点缓冲对象那样被绑定,任何随后的顶点属性调用都会储存在这个VAO中
    • 作用:
      • 当配置顶点属性指针时,你只需要将那些调用执行一次,之后再绘制物体的时候只需要绑定相应的VAO就行了。
      • 不同顶点数据和属性配置之间切换变得非常简单,只需要绑定不同的VAO就行了。刚刚设置的所有状态都将存储在VAO中
  • 元素缓冲对象:Element Buffer ObjectEBO 或 索引缓冲对象 Index Buffer Object,IBO
    • EBO是一个缓冲区,就像一个顶点缓冲区对象一样,它存储 OpenGL 用来决定要绘制哪些顶点的索引
  • 3D坐标转为2D坐标的处理过程是由OpenGL的图形渲染管线(Graphics Pipeline,大多译为管线,实际上指的是一堆原始图形数据途经一个输送管道,期间经过各种变化处理最终出现在屏幕的过程)管理的。
  • 所有这些阶段都是高度专门化的(它们都有一个特定的函数),并且很容易并行执行。正是由于它们具有并行执行的特性,当今大多数显卡都有成千上万的小处理核心,它们在GPU上为每一个(渲染管线)阶段运行各自的小程序,从而在图形渲染管线中快速处理你的数据。这些小程序叫做着色器(Shader)
  • OpenGL着色器是用OpenGL着色器语言(OpenGL Shading Language, GLSL)写成的

请添加图片描述

  • 每个阶段将会把前一个阶段的输出作为输入

  • 首先,我们以数组的形式传递3个3D坐标作为图形渲染管线的输入,用来表示一个三角形,这个数组叫做顶点数据(Vertex Data);顶点数据是一系列顶点的集合。

    • 一个**顶点(Vertex)是一个3D坐标的数据的集合。而顶点数据是用顶点属性(Vertex Attribute)**表示的,它可以包含任何我们想用的数据
    • 顶点着色器(Vertex Shader):一个顶点作为输入in。主要的目的是把3D坐标转为另一种3D坐标(后面会解释),同时允许我们对顶点属性进行一些基本处理。
  • 图元装配(Primitive Assembly)阶段将顶点着色器输出的所有顶点作为输入(如果是GL_POINTS,那么就是一个顶点),并所有的点装配成指定图元的形状;本节例子中是一个三角形。

  • 图元装配阶段的输出会传递给几何着色器(Geometry Shader):把图元形式的一系列顶点的集合作为输入,它可以通过产生新顶点构造出新的(或是其它的)图元来生成其他形状

  • 几何着色器的输出会被传入光栅化阶段(Rasterization Stage):把图元映射为最终屏幕上相应的像素,生成供**片段着色器(Fragment Shader)**使用的片段(Fragment)。在片段着色器运行之前会执行裁切(Clipping)。裁切会丢弃超出你的视图以外的所有像素,用来提升执行效率。

  • 片段着色器:主要目的是计算一个像素的最终颜色,这也是所有OpenGL高级效果产生的地方。通常,片段着色器包含3D场景的数据(比如光照、阴影、光的颜色等等),这些数据可以被用来计算最终像素的颜色。完成后通过out输出给下一个步骤

  • 在所有对应颜色值确定以后,最终的对象将会被传到最后一个阶段,我们叫做Alpha测试和混合(Blending)阶段

    • 这个阶段检测片段的对应的深度(和模板(Stencil))值(后面会讲),用它们来判断这个像素是其它物体的前面还是后面,决定是否应该丢弃。
    • 这个阶段也会检查alpha值(alpha值定义了一个物体的透明度)并对物体进行混合(Blend)。所以,即使在片段着色器中计算出来了一个像素输出的颜色,在渲染多个三角形的时候最后的像素颜色也可能完全不同。
  • 对于大多数场合,我们只需要配置顶点和片段着色器就行了。几何着色器是可选的,通常使用它默认的着色器就行了。

  • 元素缓冲对象(Element Buffer Object,EBO),也叫索引缓冲对象(Index Buffer Object,IBO):是一个缓冲区,就像一个顶点缓冲区对象一样,它存储 OpenGL 用来决定要绘制哪些顶点的索引。

void glShaderSource(	
	GLuint shader,
	GLsizei count,
	const GLchar **string,
	const GLint *length
);
  • 一级指针形参不能改变一级指针指向实例:
void fun(char * pa)
{
    printf("pa的值:%d\n",pa);
    pa = "bb";
    printf("pa的值:%d\n",pa);
}

int main(void)
{
     char * p = 0;
     printf("p的值:%d\n",p);
     fun(p);

     if(p != 0)
     {
          printf("改变后输出p = ");
          puts(p)
     }
     else
     {
          printf("p值未改变!\n");
     }
    
     return 0;
}
  • 二级指针改变一级指针指向
#include"stdio.h"

void fun(char** pa)
{
    printf("pa的值:%d\n", pa);
    char tmp[] = "hello";
    *pa = tmp;
    printf("pa的值:%d\n", pa);
}

int main(void)
{
    char* p = 0;
    printf("p的值:%d\n", p);
    fun(&p);

    if (p != 0)
    {
        printf("改变后输出*p = ");
        puts(p);
    }
    else
    {
        printf("p值未改变!\n");
    }

    return 0;
}

引用文章来源:http://t.csdn.cn/Id21s

着色器

  • 着色器是使用一种叫GLSL的类C语言写成的。
    • GLSL是为图形计算量身定制的,它包含一些针对向量和矩阵操作的有用特性。
    • GLSL中包含C等其它语言大部分的默认基础数据类型:int、float、double、uint和bool。
    • GLSL有两种容器类型,分别是向量(Vector)和矩阵(Matrix)

在这里插入图片描述

  • 着色器(Shader)是运行在GPU上的小程序。这些小程序为图形渲染管线的某个特定部分而运行。着色器只是一种把输入转化为输出的程序。着色器也是一种非常独立的程序,因为它们之间不能相互通信;它们之间唯一的沟通只有通过输入和输出

  • 当我们特别谈论到顶点着色器的时候,每个输入变量也叫顶点属性(Vertex Attribute)。我们能声明的顶点属性是有上限的,它一般由硬件来决定。OpenGL确保至少有16个包含4分量的顶点属性可用

  • 向量这一数据类型也允许一些有趣而灵活的分量选择方式,叫做重组(Swizzling)。重组允许这样的语法:

vec2 someVec;
vec4 differentVec = someVec.xyxx;
vec3 anotherVec = differentVec.zyw;
vec4 otherVec = someVec.xxxx + anotherVec.yxzy;

in & out

  • 每个着色器都有输入和输出,这样才能进行数据交流和传递。

    • GLSL定义了in和out关键字专门来实现这个目的。
    • 每个着色器使用这两个关键字设定输入和输出,只要一个输出变量与下一个着色器阶段的输入匹配,它就会传递下去。但在顶点和片段着色器中会有点不同。
  • 为了定义顶点数据该如何管理,我们使用location这一元数据指定输入变量,这样我们才可以在CPU上配置顶点属性。我们已经在前面的教程看过这个了,layout (location = 0)

    • 顶点着色器需要为它的输入提供一个额外的layout标识,这样我们才能把它链接到顶点数据。
  • 顶点着色器

    #version 330 core
    layout (location = 0) in vec3 aPos; // 位置变量的属性位置值为0
    
    out vec4 vertexColor; // 为片段着色器指定一个颜色输出
    
    void main()
    {
        gl_Position = vec4(aPos, 1.0); // 注意我们如何把一个vec3作为vec4的构造器的参数
        vertexColor = vec4(0.5, 0.0, 0.0, 1.0); // 把输出变量设置为暗红色
    }
    
  • 片段着色器

    #version 330 core
    out vec4 FragColor;
    
    in vec4 vertexColor; // 从顶点着色器传来的输入变量(名称相同、类型相同)
    
    void main()
    {
        FragColor = vertexColor;
    }
    

Uniform

  • Uniform是一种从CPU中的应用向GPU中的着色器发送数据的方式,但uniform和顶点属性有些不同。

    • 首先,uniform是全局的(Global)。全局意味着uniform变量必须在每个着色器程序对象中都是独一无二的,而且它可以被着色器程序的任意着色器在任意阶段访问。
    • 第二,无论你把uniform值设置成什么,uniform会一直保存它们的数据,直到它们被重置或更新。
  • 注意:如果你声明了一个uniform却在GLSL代码中没用过,编译器会静默移除这个变量,导致最后编译出的版本中并不会包含它,这可能导致几个非常麻烦的错误

  • glGetUniformLocation查询uniform ourColor的位置值。我们为查询函数提供着色器程序和uniform的名字(这是我们希望获得的位置值的来源)。

    • 如果glGetUniformLocation返回-1就代表没有找到这个位置值。
    • 最后,我们可以通过glUniform4f函数设置uniform值。
    // ...
    int vertexColorLocation = glGetUniformLocation(shaderProgram, "ourColor");
    glUseProgram(shaderProgram);
    glUniform4f(vertexColorLocation, 0.0f, greenValue, 0.0f, 1.0f);
    
  • 因为OpenGL在其核心是一个C库,所以它不支持类型重载,在函数参数不同的时候就要为其定义新的函数;glUniform是一个典型例子。这个函数有一个特定的后缀,标识设定的uniform的类型。可能的后缀有:

后缀含义
f函数需要一个float作为它的值
i函数需要一个int作为它的值
ui函数需要一个unsigned int作为它的值
3f函数需要3个float作为它的值
fv函数需要一个float向量/数组作为它的值
  • 每当你打算配置一个OpenGL的选项时就可以简单地根据这些规则选择适合你的数据类型的重载函数。

纹理

为了能够把纹理映射(Map)到三角形上,我们需要指定三角形的每个顶点各自对应纹理的哪个部分。这样每个顶点就会关联着一个纹理坐标(Texture Coordinate),用来标明该从纹理图像的哪个部分采样(译注:采集片段颜色)。之后在图形的其它片段上进行片段插值(Fragment Interpolation)。

纹理坐标在x和y轴上,范围为0到1之间(注意我们使用的是2D纹理图像)。使用纹理坐标获取纹理颜色叫做采样(Sampling)。纹理坐标起始于(0, 0),也就是纹理图片的左下角,终始于(1, 1),即纹理图片的右上角。下面的图片展示了我们是如何把纹理坐标映射到三角形上的请添加图片描述

纹理环绕方式

  • 纹理坐标的范围通常是从(0, 0)到(1, 1),纹理坐标设置在范围之外的处理方式
环绕方式描述
GL_REPEAT对纹理的默认行为。重复纹理图像。
GL_MIRRORED_REPEAT和GL_REPEAT一样,但每次重复图片是镜像放置的。
GL_CLAMP_TO_EDGE纹理坐标会被约束在0到1之间,超出的部分会重复纹理坐标的边缘,产生一种边缘被拉伸的效果。
GL_CLAMP_TO_BORDER超出的坐标为用户指定的边缘颜色。

请添加图片描述

纹理过滤

  • 纹理坐标不依赖于分辨率(Resolution),它可以是任意浮点值,所以OpenGL需要知道怎样将纹理像素(Texture Pixel,也叫Texel,译注1)映射到纹理坐标。当你有一个很大的物体但是纹理的分辨率很低的时候这就变得很重要了。

  • GL_NEAREST(也叫邻近过滤,Nearest Neighbor Filtering)是OpenGL默认的纹理过滤方式。当设置为GL_NEAREST的时候,OpenGL会选择中心点最接近纹理坐标的那个像素。

请添加图片描述

  • GL_LINEAR(也叫线性过滤,(Bi)linear Filtering)它会基于纹理坐标附近的纹理像素,计算出一个插值,近似出这些纹理像素之间的颜色。一个纹理像素的中心距离纹理坐标越近,那么这个纹理像素的颜色对最终的样本颜色的贡献越大。请添加图片描述
    请添加图片描述
  • 当进行放大(Magnify)和缩小(Minify)操作的时候可以设置纹理过滤的选项,比如你可以在纹理被缩小的时候使用邻近过滤,被放大时使用线性过滤。

多级渐远纹理

  • 有些物体会很远,但其纹理会拥有与近处物体同样高的分辨率。由于远处的物体可能只产生很少的片段,OpenGL从高分辨率纹理中为这些片段获取正确的颜色值就很困难,因为它需要对一个跨过纹理很大部分的片段只拾取一个纹理颜色。在小物体上这会产生不真实的感觉,更不用说对它们使用高分辨率纹理浪费内存的问题了。

  • OpenGL使用一种叫做多级渐远纹理(Mipmap)的概念来解决这个问题,它简单来说就是一系列的纹理图像,后一个纹理图像是前一个的二分之一。多级渐远纹理背后的理念很简单:距观察者的距离超过一定的阈值,OpenGL会使用不同的多级渐远纹理,即最适合物体的距离的那个。由于距离远,解析度不高也不会被用户注意到。同时,多级渐远纹理另一加分之处是它的性能非常好。让我们看一下多级渐远纹理是什么样子的:
    请添加图片描述
    指定不同多级渐远纹理级别之间的过滤方式,你可以使用下面四个选项中的一个代替原有的过滤方式:

过滤方式描述
GL_NEAREST_MIPMAP_NEAREST使用最邻近的多级渐远纹理来匹配像素大小,并使用邻近插值进行纹理采样
GL_LINEAR_MIPMAP_NEAREST使用最邻近的多级渐远纹理级别,并使用线性插值进行采样
GL_NEAREST_MIPMAP_LINEAR在两个最匹配像素大小的多级渐远纹理之间进行线性插值,使用邻近插值进行采样
GL_LINEAR_MIPMAP_LINEAR在两个邻近的多级渐远纹理之间使用线性插值,并使用线性插值进行采样
  • 多级渐远纹理主要是使用在纹理被缩小的情况下的:纹理放大不会使用多级渐远纹理,为放大过滤设置多级渐远纹理的选项会产生一个GL_INVALID_ENUM错误代码。

纹理单元

  • 一个纹理的位置值通常称为一个纹理单元(Texture Unit)。一个纹理的默认纹理单元是0,它是默认的激活纹理单元
  • 纹理单元的主要目的是让我们在着色器中可以使用多于一个的纹理。通过把纹理单元赋值给采样器,我们可以一次绑定多个纹理,只要我们首先激活对应的纹理单元
  • OpenGL至少保证有16个纹理单元供你使用,也就是说你可以激活从GL_TEXTURE0到GL_TEXTRUE15。它们都是按顺序定义的,所以我们也可以通过GL_TEXTURE0 + 8的方式获得GL_TEXTURE8,这在当我们需要循环一些纹理单元的时候会很有用。

变换

向量

  • 向量最基本的定义就是一个方向。或者更正式的说,向量有一个方向(Direction)和大小(Magnitude,也叫做强度或长度)。由于向量表示的是方向,起始于何处并不会改变它的值。下图我们可以看到向量v¯ 和w¯ 是相等的,尽管他们的起始点不同:
  • 请添加图片描述

向量与标量运算

  • 标量(Scalar)只是一个数字(或者说是仅有一个分量的向量)。当把一个向量加/减/乘/除一个标量,我们可以简单的把向量的每个分量分别进行该运算。对于加法来说会像这样:
  • 在这里插入图片描述
  • 其中的+可以是+,-,·或÷,其中·是乘号。注意-和÷运算时不能颠倒(标量-/÷向量),因为颠倒的运算是没有定义的。

向量取反

  • 对一个向量取反(Negate)会将其方向逆转。一个指向东北的向量取反后就指向西南方向了。我们在一个向量的每个分量前加负号就可以实现取反了(或者说用-1数乘该向量):
  • 在这里插入图片描述

向量加减

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

长度

  • 使用勾股定理(Pythagoras Theorem)来获取向量的长度(Length)/大小(Magnitude)。如果你把向量的x与y分量画出来,该向量会和x与y分量为边形成一个三角形:
    在这里插入图片描述
  • ||向量v|| 表示向量v 的长度
    • 在这里插入图片描述
  • 有一个特殊类型的向量叫做单位向量(Unit Vector)。单位向量有一个特别的性质——它的长度是1。我们可以用任意向量的每个分量除以向量的长度得到它的单位向量n^:
    • 在这里插入图片描述
    • 我们把这种方法叫做一个向量的标准化(Normalizing)。单位向量头上有一个^样子的记号。通常单位向量会变得很有用,特别是在我们只关心方向不关心长度的时候(如果改变向量的长度,它的方向并不会改变)。

向量相乘

  • 普通的乘法在向量上是没有定义的,因为它在视觉上是没有意义的。但是在相乘的时候我们有两种特定情况可以选择:
    • 一个是点乘(Dot Product),记作v¯⋅k¯
    • 另一个是叉乘(Cross Product),记作v¯×k¯

点乘:

  • 两个向量的点乘等于它们的数乘结果乘以两个向量之间夹角的余弦值。
  • 它们之间的夹角记作θ。为什么这很有用?
    • 想象如果v¯和k¯都是单位向量,它们的长度会等于1。这样公式会有效简化成:v¯⋅k¯=1⋅1⋅cosθ=cosθ。
      • 现在点积只定义了两个向量的夹角。
      • 使用点乘可以很容易测试两个向量是否正交(Orthogonal)平行(正交意味着两个向量互为直角)。

叉乘

  • 叉乘只在3D空间中有定义,它需要两个不平行向量作为输入,生成一个正交于两个输入向量的第三个向量。如果输入的两个向量也是正交的,那么叉乘之后将会产生3个互相正交的向量。
    • 请添加图片描述

矩阵

  • 简单来说矩阵就是一个矩形的数字、符号或表达式数组。矩阵中每一项叫做矩阵的元素(Element)。
    • 矩阵可以通过(i, j)进行索引,i是行,j是列,这就是上面的矩阵叫做2×3矩阵的原因(3列2行,也叫做矩阵的维度(Dimension))。

矩阵运算

  • 矩阵与标量之间的加减定义:
    • 标量值要加到矩阵的每一个元素上。矩阵与标量的减法也相似
    • 矩阵与矩阵之间的加减就是两个矩阵对应元素的加减运算,所以总体的规则和与标量运算是差不多的,只不过在相同索引下的元素才能进行运算
  • 矩阵的数乘
    • 和矩阵与标量的加减一样,矩阵与标量之间的乘法也是矩阵的每一个元素分别乘以该标量。
    • 现在我们也就能明白为什么这些单独的数字要叫做标量(Scalar)了。简单来说,标量就是用它的值缩放(Scale)矩阵的所有元素(译注:注意Scalar是由Scale + -ar演变过来的)。
  • 矩阵相乘
    • 限制:
      • 只有当左侧矩阵的列数与右侧矩阵的行数相等,两个矩阵才能相乘。
      • 矩阵相乘不遵守交换律(Commutative),也就是说A⋅B≠B⋅A
  • 单位矩阵
    • 在OpenGL中,由于某些原因我们通常使用4×4的变换矩阵,而其中最重要的原因就是大部分的向量都是4分量的。我们能想到的最简单的变换矩阵就是单位矩阵(Identity Matrix)。单位矩阵是一个除了对角线以外都是0的N×N矩阵。

缩放

  • 每个轴的缩放因子(Scaling Factor)都不一样的缩放操作是不均匀(Non-uniform)缩放。如果每个轴的缩放因子都一样那么就叫均匀缩放(Uniform Scale)。
  • 如果我们把缩放变量表示为(S1, S2, S3)我们可以为任意向量(x, y, z)定义一个缩放矩阵:
    在这里插入图片描述
  • 注意,第四个缩放向量仍然是1,因为在3D空间中缩放w分量是无意义的。w分量另有其他用途,在后面我们会看到。

位移

  • 位移(Translation)是在原始向量的基础上加上另一个向量,获得一个在不同位置的新向量的过程,从而在位移向量基础上移动了原始向量。
  • 和缩放矩阵一样,在4×4矩阵上有几个特别的位置用来执行特定的操作,对于位移来说它们是第四列最上面的3个值。如果我们把位移向量表示为(Tx, Ty, Tz),我们就能把位移矩阵定义为:
    在这里插入图片描述
  • 所有的位移值都要乘以向量的w行,所以位移值会加到向量的原始值上(想想矩阵乘法法则)。而如果用3x3矩阵位移值就没地方放也没地方乘了,所以是不行的。
  • 齐次坐标(Homogeneous Coordinates):向量的w分量也叫齐次坐标。想要从齐次向量得到3D向量,我们可以把x、y和z坐标分别除以w坐标。
  • 如果一个向量的齐次坐标是0,这个坐标就是方向向量(Direction Vector),因为w坐标是0,这个向量就不能位移(译注:这也就是我们说的不能位移一个方向)。

旋转

  • 首先我们来定义一个向量的旋转到底是什么。 2D或3D空间中的旋转用角(Angle)来表示。角可以是角度制或弧度制的,周角是360角度或2 PI弧度。
    • 大多数旋转函数需要用弧度制的角,但幸运的是角度制的角也可以很容易地转化为弧度制的:
      • 弧度转角度:角度 = 弧度 * (180.0f / PI)
      • 角度转弧度:弧度 = 角度 * (PI / 180.0f)
        • PI约等于3.14159265359。
        • 转半圈会旋转360/2 = 180度,向右旋转1/5圈表示向右旋转360/5 = 72度。下图中展示的2D向量v¯是由k¯向右旋转72度所得的:
          • 请添加图片描述
  • 在3D空间中旋转需要定义一个和一个旋转轴(Rotation Axis)。物体会沿着给定的旋转轴旋转特定角度。
  • 使用三角学,给定一个角度,可以把一个向量变换为一个经过旋转的新向量。这通常是使用一系列正弦和余弦函数(一般简称sin和cos)各种巧妙的组合得到的。
  • 旋转矩阵在3D空间中每个单位轴都有不同定义,旋转角度用θ表示:
    在这里插入图片描述

矩阵的组合

  • 使用矩阵进行变换的真正力量在于,根据矩阵之间的乘法,我们可以把多个变换组合到一个矩阵中。
  • 假设我们有一个顶点(x, y, z),我们希望将其缩放2倍,然后位移(1, 2, 3)个单位。我们需要一个位移和缩放矩阵来完成这些变换。结果的变换矩阵看起来像这样:
    在这里插入图片描述
  • 注意,当矩阵相乘时我们先写位移再写缩放变换的。矩阵乘法是不遵守交换律的,这意味着它们的顺序很重要。当矩阵相乘时,在最右边的矩阵是第一个与向量相乘的,所以你应该从右向左读这个乘法。
    • 建议您在组合矩阵时,先进行缩放操作,然后是旋转,最后才是位移,否则它们会(消极地)互相影响。
      • 比如,如果你先位移再缩放,位移的向量也会同样被缩放(译注:比如向某方向移动2米,2米也许会被缩放成1米)!
        在这里插入图片描述
  • 向量先缩放2倍,然后位移了(1, 2, 3)个单位。

坐标系统(Coordinate Systems)

  • 将坐标变换为标准化设备坐标,接着再转化为屏幕坐标的过程通常是分步进行的,也就是类似于流水线那样子。在流水线中,物体的顶点在最终转化为屏幕坐标之前还会被变换到多个坐标系统(Coordinate System)。将物体的坐标变换到几个过渡坐标系(Intermediate Coordinate System)的优点在于,在这些特定的坐标系统中,一些操作或运算更加方便和容易,这一点很快就会变得很明显。对我们来说比较重要的总共有5个不同的坐标系统:
    • 局部空间(Local Space,或者称为物体空间(Object Space))
    • 世界空间(World Space)
    • 观察空间(View Space,或者称为视觉空间(Eye Space))
    • 裁剪空间(Clip Space)
    • 屏幕空间(Screen Space)

概述

  • 为了将坐标从一个坐标系变换到另一个坐标系,我们需要用到几个变换矩阵,最重要的几个分别是模型(Model)观察(View)投影(Projection)三个矩阵。我们的顶点坐标起始于局部空间(Local Space),在这里它称为局部坐标(Local Coordinate),它在之后会变为世界坐标(World Coordinate)观察坐标(View Coordinate)裁剪坐标(Clip Coordinate),并最后以屏幕坐标(Screen Coordinate)的形式结束。下面的这张图展示了整个流程以及各个变换过程做了什么:
    请添加图片描述
  1. 局部坐标是对象相对于局部原点的坐标,也是物体起始的坐标。
  2. 下一步是将局部坐标变换为世界空间坐标,世界空间坐标是处于一个更大的空间范围的。这些坐标相对于世界的全局原点,它们会和其它物体一起相对于世界的原点进行摆放。
  3. 接下来我们将世界坐标变换为观察空间坐标,使得每个坐标都是从摄像机或者说观察者的角度进行观察的。
  4. 坐标到达观察空间之后,我们需要将其投影到裁剪坐标。裁剪坐标会被处理至-1.0到1.0的范围内,并判断哪些顶点将会出现在屏幕上。
  5. 最后,我们将裁剪坐标变换为屏幕坐标,我们将使用一个叫做视口变换(Viewport Transform)的过程。视口变换将位于-1.0到1.0范围的坐标变换到由glViewport函数所定义的坐标范围内。最后变换出来的坐标将会送到光栅器,将其转化为片段。
  • 5
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值