顶点数据:

顶点数据是一系列顶点的集合。

一个顶点(Vertex)是一个3d坐标的数据的集合。

而顶点数据是用顶点属性(Vertex Attribute)表示的,它可以包含任何我们想用的数据

(但是简单起见,我们还是假定每个顶点只有一个3D位置和一些颜色值组成的。)

图元:

为了让openGL知道我们的坐标和颜色值构成的到底是什么,openGL需要你去指定这些数据所表示的渲染类型。

我们是希望把这些数据渲染成一系列的点?一系列的三角形?还是仅仅是一个长长的线?做出这些提示的叫做图元(Primitive)

任何一个绘制指令的调用都将把图元传递给openGL。这是其中的几个:

GL_POINTS 、GL_TRIANGLES、 GL_LINE_STRIP。

 

图形渲染管线的第一个部分是顶点着色器(Vertex Shader),它把一个单独的顶点作为输入。

顶点着色器主要的目的是把3D坐标转换为另一种3D坐标,同时顶点着色器允许我们对顶点属性进行一些基本处理。

 

图元装配(Primitive Assembly)阶段将顶点着色器输出的所有顶点作为输入(如果是GL_POINTS,那么就是一个顶点),

并所有的点装配成指定图元的形状;

 

图元装配阶段的输出会传递给几何着色器(Geometry Shader)。几何着色器把图元形式的一系列顶点的集合作为输入,

它可以通过产生新顶点构造出新的(或是其他的)图元来生成其他形状。

 

几何着色器的输出会被传入光栅化阶段(Rasterization Stage),这里它会把图元映射为最终屏幕上相应的像素,

生成供片段着色器(Fragment Shader)使用的片段(Fragment) 。在片段着色器运行之前会执行裁切(Clipping),

裁切会丢弃超出你的视图以外的所有像素,用来提升执行效率。

 

 

OpenGL 中的一个片段是OpenGL渲染一个像素所需的所有数据。

 

片段着色器的主要目的是计算一个像素的最终颜色,这也是所有OpenGL高级效果产生的地方。

通常片段着色器包含3D场景的数据(比如光照、阴影、光的颜色等等),这些数据可以被用来计算最终像素的颜色。

 

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

这个阶段检测片段的对应的深度(和模版(Stencil))值,用它们来判断这个像素是其他物体的前面还是后面,

决定是否应该丢弃。这个阶段也会检查alpha值 并对物体进行混合(Blend)。

 

然而,对于大多数场合,我们只需要配置定点和片段着色器就行了。几何着色器是可选的,通常使用它默认的着色器就行了。

在现代OpenGL中,我们必须定义至少一个顶点着色器和一个片段着色器(因为GPU中没有默认的顶点/片段着色器)。

 

渲染一个2D的三角形,我们将它顶点的z坐标设置为0.0,这样子的话三角形每一点的深度(Depth) 都是一样的,从而使它看上去像是2D的。

通常深度可以理解为z坐标,它代表一个像素在空间中和你的距离,如果离你远就可能被别的像素遮挡,你就看不到它了,它会被丢弃,以节省资源。

 

标准化设备坐标(Normalized Device Coordinates,NDC)

一旦你的顶点坐标已经在顶点着色器中处理过,它们就应该是标准化设备坐标了,

标准化坐标是一个x、y和z值在-1.0到1.0的一小段空间。

 

标准化设备坐标接着会变换为屏幕空间坐标(Screen-space Coordinates),这是使用你通过glViewport 函数提供的数据,进行视口变换(Viewport Transform)完成的。

所得的屏幕空间坐标又会被变换为片段输入到片段着色器中。

 

定义这样的顶点数据以后,我们会把它输入发送给图形渲染管线的第一个处理阶段:顶点着色器。

它会在GPU上创建内存用于存储我们的顶点数据,还要配置OpenGL如何解释这些内存,并且指定其如何发送给显卡。

我们通过顶点缓冲对象(Vertex Buffer Objects,VBO)管理这个内存。

 

顶点缓冲对象是我们在OpenGL中第一个出现的OpenGL对象。

这个缓冲有一个独一无二的ID,所以我们可以使用glGenBuffers 函数和一个缓冲ID生成一个VBO对象:

GLuint VBO;
glGenBuffers(1, &VBO);  

OpenGL有很多缓冲对象类型,顶点缓冲对象的缓冲类型是GL_ARRAY_BUFFER。OpenGL允许我们同时绑定多个缓冲,

只要它们的是不同的缓冲类型。我们可以使用glBindBuffer 函数把新创建的缓冲绑定到GL_ARRAY_BUFFER目标上:

glBindBuffer(GL_ARRAY_BUFFER,VBO);

从这一刻起,我们使用的任何(在GL_ARRAY_BUFFER目标上的)缓冲调用都会用来配置当前绑定的缓冲(VBO)。

然后我们可以调用glBufferData函数,它会把之前定义的顶点数据复制到缓冲的内存中

glBufferData(GL_ARRAY_BUFFER,sizeof(vertices),vertices,GL_STATIC_DRAW);

glBufferData是一个专门用来把用户定义的数据复制到当前绑定缓冲的函数。

1个参数是目标缓冲的类型;

2个参数是指定传输数据大小(以字节为单位);

3个参数是我们希望发送的实际数据;

4个参数指定了我们希望显卡如何管理给定的数据。它有3种形式:

GL_STATIC_DRAW :数据不会或几乎不会改变。

GL_DYNAMIC_DRAW:数据会被改变很多。

GL_STREAM_DRAW:数据每次绘制时都会改变。

 

 

向量(Vector)它简明的表达了任意空间中的位置和方向,并且它有非常有用的数学属性。

在GLSL中一个向量有最多4个分量,每个分量都代表空间中的一个坐标,它们可以通过vec.x、vec.y、vec.z和vec.w来获取。

vec.w分量而是用在所谓透视划分(Perspective Division)上。

 

在真实的程序里输入数据通常都不是标准化设备坐标,顶点着色器一般会先把它们转换至OpenGL的可视区域内。

 

顶点着色器(VertexShader)

const GLchar* vertexShaderSource = "#version 330 core \
                                   layout(location = 0) in vec3 position;    \
                                   void main()    \
                                   {    \
                                   gl_Position = vec4(position.x,position.y,position.z,1.0);    \
                                   }    \
    "; 

 

 

编译着色器

编写之后的顶点着色器源码,为了能让OpenGL使用它,我们必须在运行时动态编译它的源码。

首先创建一个着色器对象,注意还是用ID来引用的。所以我们存储这个顶点着色器为GLuint,

然后用glCreateShader 创建这个着色器:

GLuint vertexShader;
vertexShader = glCreateShader(GL_VERTEX_SHADER);

我们把需要创建的着色器类型以参数形式提供给glCreateShader。

由于我们正创建一个顶点着色器,传递的参数是GL_VERTEX_SHADER。

下一步我们把这个顶点着色器源码附加到着色器对象上,然后编译它:

glShaderSource(vertexShader,1,&vertexShaderSource,NULL);
glCompileShader(vertexShader);

glShaderSource函数参数:

1个参数要编译的着色器对象;

2个参数指定传递的源码字符串数量,上面这里只有一个;

 3个参数是顶点着色器真正的源码;

4个参数我们先设置为NULL。

 

如果想检测glCompileShader是否成功可以用glGetShaderiv 检查是否编译成功。如果失败可以用glGetShaderInfoLog获取错误信息。

 

片段着色器(Fragment Shader)

该着色器全是关于计算你的像素最后的颜色输出。

const GLchar* fragmentShaderSource = "#version 330 core    \
                                     out vec4 color;    \
                                     void main()    \
                                     {    \
                                     color = vec4(1.0f,0.5f,0.2f,1.0f);    \
                                     }    \
    ";

 

 

在计算机图形中颜色被表示为有4个元素的数组:红色、绿色、蓝色和alpha(透明度)分量,通常缩写为RGBA。

每个分量的强度设置在0.0到1.0之间。

 

编译片段着色器的过程与顶点着色器类似,只不过我们使用GL_FRAGMENT_SHADER常量作为着色器类型:

GLuint fragmentShader;
fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader,1,&fragmentShaderSource,null);
glCompileShader(fragmentShader);

 

 两个着色器现在都编译了,剩下的事情是把两个着色器对象链接到一个用来渲染的着色器程序(Shader Program)中。

 

------------------------------

https://learnopengl-cn.github.io/01%20Getting%20started/04%20Hello%20Triangle/

posted on 2017-04-13 11:08  瓦楞球  阅读(777)  评论(0编辑  收藏  举报