CPU和GPU的区别 : CPU 和 GPU 的区别是什么?
这里重点记录下对GPU的理解, 因为OpenGl是针对于GPU编程, 所以就不能以CPU的编程思维对GPU编程, 因为涉及到后面的一些Shader编程, 函数的调用, 参数的传递, 会对新手来说有些绕.
CPU和GPU编程的不同 :
CPU我们可以从多线程的角度, 线程之间的通信操作,串行or并行的而方式执行任务, GPU不同的是, GPU的任务都是以并行的方式, 都是单线程的执行方式. 所以,很少的cache. 缓存的目的不是保存后面需要访问的数据的.
也可以简单粗暴的理解 : 这个是CPU和GPU物理结构决定的.
Shader编程
对于OpenGL的最终作用, 我们是把我们需要的图像或者一些3D模型投影到屏幕上,我们所要做的就是这么一个事情.
什么是Shader
Shader其实就是专门用来渲染图形的一种技术,通过shader,我们可以自定义显卡渲染画面的算法,使画面达到我们想要的效果。小到每一个像素点,大到整个屏幕,比如下面这两个游戏内比较常见的效果。
简单粗暴的理解
比如在Unity中创建一个材质球, 给材质球设置颜色, 设置纹理.
我们可以通过直接在Unity的可视化工具上选择我们需要设置的内容.
我们也可以通过创建一个Shader文件, 在Shader中创建一些对应的属性, 比如颜色, 大小等等. 从代码的层面去操作.
了解Shader中的材质球 和 纹理之间的概念. 代码层面可以理解为对应OpenGL中的program 和 shader.
OpenGL的可编程管线, 就是让我们可以针对于顶点着色器和片元着色器, 通过编写对应的Shader, 顶点数据怎么加载到顶点着色器中, 纹理怎么加载到片元着色器中, 怎么处理buffer数据到最终显示到屏幕上的一个事情.
建议 : 可以简单先从Shader编程学学一些基本概念, 基本操作.再来学OpenGL会快的多.
可编程管线
网上保存了一个比较好理解的图形:

简单粗暴的理解流程 :
顶点着色器 -> 光栅化 -> 测试与混合 -> 片元着色器 -> buffer缓冲区 -> 显示到屏幕
这里是一个极为精简的流程图.
对于可编程管线, 我们可以操作的只有 顶点着色器 和 片元着色器. 可以先简单有个概念.
顶点着色器
它可以用于执⾏自定义计算,实施新的变换,照明或者传统的固定功能所不允许的基于顶点的效果,例如:
矩阵变换位置
计算光照公式生成逐顶点颜色
⽣成/变换纹理坐标
片元着色器
它可以用于图片/视频/图形中每个像素的颜色填充(比如给视频添加滤镜,实际上就是将视频中每个图片的像素点颜色填充进行修改.)
计算颜⾊
获取纹理值
往像素点中填充颜色值(纹理值/颜色值);
简单粗暴的就是:
(顶点)一个是处理, 这些图像在屏幕上显示的坐标位置的问题.
(片元)一个是处理, 这些图像在屏幕上显示的长什么样的问题
看到后面的Shader程序. 应该会有这么写疑问 :一些固定的值是怎么来得.
可以往回参考下面的内容.
比如 :
顶点着色器程序
/// 着色器程序之间的数据传递
static char *MyTextureVertexShaderStr = SHADER(
\#version 330 core\n
layout (location = 0) in vec3 position; //顶点数据源输入
layout (location = 1) in vec3 color; //颜色数据源输入
layout (location = 2) in vec2 texCoords; //纹理数据源输入(2D)
out vec2 vertexTexCoords;//纹理输出
out vec4 vertexColor;//颜色输出
void main()
{
gl_Position = vec4(position, 1.0f);//坐标位置
vertexColor = vec4(color, 1.0f); //输出给片元着色器
vertexTexCoords = texCoords;
}
);
片元着色器程序
//片元着色器程序
static char *MyTextureFragmentShaderSrc = SHADER(
\#version 330 core\n
in vec2 vertexTexCoords;//纹理输入(从顶点)
in vec4 vertexColor;//颜色输入(从顶点)
uniform sampler2D myTexture;//全局myTexture
out vec4 color;//颜色输出
out vec4 FragColor;//纹理输出
void main()
{
color = vertexColor;
FragColor = texture(myTexture, vertexTexCoords);
}
);
对于gl_Position , color, FragColor如果有疑惑. 这里是根据GLSL基础量的定义来的.
gl_Position 所有的顶点着色器都必须写这个值。
gl_Color 输入属性-表示顶点的主颜色
gl_FragColor 输出的颜色用于随后的像素操作
参考 # GLSL 基础量定义
修饰符
变量的声明可以使用如下的修饰符。
修饰符 | 描述 |
---|---|
const | 常量值必须在声明是初始化。它是只读的不可修改的。 |
attribute | 表示只读的顶点数据,只用在顶点着色器中。数据来自当前的顶点状态或者顶点数组。它必须是全局范围声明的,不能再函数内部。一个attribute可以是浮点数类型的标量,向量,或者矩阵。不可以是数组或则结构体 |
uniform | 一致变量。在着色器执行期间一致变量的值是不变的。与const常量不同的是,这个值在编译时期是未知的是由着色器外部初始化的。一致变量在顶点着色器和片段着色器之间是共享的。它也只能在全局范围进行声明。 |
varying | 顶点着色器的输出。例如颜色或者纹理坐标,(插值后的数据)作为片段着色器的只读输入数据。必须是全局范围声明的全局变量。可以是浮点数类型的标量,向量,矩阵。不能是数组或者结构体。 |
centorid varying | 在没有多重采样的情况下,与varying是一样的意思。在多重采样时,centorid varying在光栅化的图形内部进行求值而不是在片段中心的固定位置求值。 |
invariant | (不变量)用于表示顶点着色器的输出和任何匹配片段着色器的输入,在不同的着色器中计算产生的值必须是一致的。所有的数据流和控制流,写入一个invariant变量的是一致的。编译器为了保证结果是完全一致的,需要放弃那些可能会导致不一致值的潜在的优化。除非必要,不要使用这个修饰符。在多通道渲染中避免z-fighting可能会使用到。 |
in | 用在函数的参数中,表示这个参数是输入的,在函数中改变这个值,并不会影响对调用的函数产生副作用。(相当于C语言的传值),这个是函数参数默认的修饰符 |
out | 用在函数的参数中,表示该参数是输出参数,值是会改变的。 |
inout | 用在函数的参数,表示这个参数即是输入参数也是输出参数。 |
内置变量
内置变量可以与固定函数功能进行交互。在使用前不需要声明。顶点着色器可用的内置变量如下表:
名称 | 类型 | 描述 |
---|---|---|
gl_Color | vec4 | 输入属性-表示顶点的主颜色 |
gl_SecondaryColor | vec4 | 输入属性-表示顶点的辅助颜色 |
gl_Normal | vec3 | 输入属性-表示顶点的法线值 |
gl_Vertex | vec4 | 输入属性-表示物体空间的顶点位置 |
gl_MultiTexCoordn | vec4 | 输入属性-表示顶点的第n个纹理的坐标 |
gl_FogCoord | float | 输入属性-表示顶点的雾坐标 |
gl_Position | vec4 | 输出属性-变换后的顶点的位置,用于后面的固定的裁剪等操作。所有的顶点着色器都必须写这个值。 |
gl_ClipVertex | vec4 | 输出坐标,用于用户裁剪平面的裁剪 |
gl_PointSize | float | 点的大小 |
gl_FrontColor | vec4 | 正面的主颜色的varying输出 |
gl_BackColor | vec4 | 背面主颜色的varying输出 |
gl_FrontSecondaryColor | vec4 | 正面的辅助颜色的varying输出 |
gl_BackSecondaryColor | vec4 | 背面的辅助颜色的varying输出 |
gl_TexCoord[] | vec4 | 纹理坐标的数组varying输出 |
gl_FogFragCoord | float | 雾坐标的varying输出 |
片段着色器的内置变量如下表:
名称 | 类型 | 描述 |
---|---|---|
gl_Color | vec4 | 包含主颜色的插值只读输入 |
gl_SecondaryColor | vec4 | 包含辅助颜色的插值只读输入 |
gl_TexCoord[] | vec4 | 包含纹理坐标数组的插值只读输入 |
gl_FogFragCoord | float | 包含雾坐标的插值只读输入 |
gl_FragCoord | vec4 | 只读输入,窗口的x,y,z和1/w |
gl_FrontFacing | bool | 只读输入,如果是窗口正面图元的一部分,则这个值为true |
gl_PointCoord | vec2 | 点精灵的二维空间坐标范围在(0.0, 0.0)到(1.0, 1.0)之间,仅用于点图元和点精灵开启的情况下。 |
gl_FragData[] | vec4 | 使用glDrawBuffers输出的数据数组。不能与gl_FragColor结合使用。 |
gl_FragColor | vec4 | 输出的颜色用于随后的像素操作 |
gl_FragDepth | float | 输出的深度用于随后的像素操作,如果这个值没有被写,则使用固定功能管线的深度值代替 |
网友评论