图形学和OpenGL
OpenGL
- 开放图形库或者“开放式图形库” 是用于渲染2D、3D矢量图形的跨语言、跨平台的应用程序编程接口规范(API规范).
- 是Khronos Group开发维护的一个规范,它主要为我们定义了用来操作图形和图片的一系列函数的API,需要注意的是OpenGL本身并非API。
- GPU的硬件开发商则需要提供满足OpenGL规范的实现,这些实现通常被称为“驱动”,它们负责将OpenGL定义的API命令翻译为GPU指令。显卡驱动中包括了对OpenGL规范的实现。
竞品:
metal 苹果的
vulkan
directX/direct3D 微软的(对应编程语言HLSL)
shader
https://learnopengl-cn.github.io/01%20Getting%20started/05%20Shaders/
着色器(Shader)是运行在GPU上的小程序。这些小程序为图形渲染管线的某个特定部分而运行。从基本意义上来说,着色器只是一种把输入转化为输出的程序。着色器也是一种非常独立的程序,因为它们之间不能相互通信;它们之间唯一的沟通只有通过输入和输出。
https://blog.csdn.net/onafioo/article/details/38983197
着色程序分为两类:vertex shader program(顶点着色程序)和fragment shader program(片断着色程序)。对应GPU上的两个组件:Programmable Vertex Processor(可编程顶点处理器,又称为顶点着色器)和 Programmable Fragment Processor(可编程片断处理器,又称为片断着色器)。顶点和片段处理器被分离成可编程单元,可编程顶点处理器是一个硬件单元,可以运行顶点程序,而可编程片段处理器则是一个可以运行片段程序的单元。
顶点和片段处理器都拥有非常强大的并行计算能力
什么是片断?片断和像素有什么不一样?所谓片断就是所有的三维顶点在光栅化(矢量图转成位图)之后的数据集合,这些数据还没有经过深度值比较,而屏幕显示的像素都是经过深度比较的。
顶点着色器控制顶点坐标转换过程;片段着色器控制像素颜色计算过程。这样就区分出顶点着色程序和片段着色程序的各自分工:Vertex program负责顶点坐标变换和几何计算;Fragment program负责像素颜色计算;前者的输出是后者的输入。
GLSL
声明
着色器是使用一种叫GLSL的类C语言写成的, GPU变成语言
着色器的开头总是要声明版本,接着是输入和输出变量、uniform和函数。每个着色器的入口点都是函数,在这个main函数中我们处理所有的输入变量,并将结果输出到输出变量中。
#version version_number
in type in_variable_name;
in type in_variable_name;
out type out_variable_name;
uniform type uniform_name;
int main()
{
// 处理输入并进行一些图形操作
...
// 输出处理过的结果到输出变量
out_variable_name = weird_stuff_we_processed;
}
分类:
-
vertexShader: 数量有限 跟硬件有关,一般不少于16个
fragmentShader
-
着色器是各自独立的小程序,每个着色器都有输入和输出,并进行数据交流和传递。一个输出变量与下一个着色器阶段的输入匹配(名字相同),它就会传递下去。
vertexShader从顶点数据中直接接收输入,使用location这一元数据指定输入变量。顶点着色器需要为它的输入提供一个额外的layout标识,这样我们才能把它链接到顶点数据layout (location = 0)。在OpenGL代码中使用查询属性位置值(Location)
fragment,它需要一个vec4颜色输出变量,因为片段着色器需要生成一个最终输出的颜色。如果你在片段着色器没有定义输出颜色,OpenGL会把你的物体渲染为黑色(或白色)。
数据类型:
-
基础类型 int、float、double、uint、bool
-
容器类型:Vector、Matrix
Vector类型:
- 可以包含1-4个基础类型的分量
<colgroup><col width="395"><col width="395"></colgroup>
| 类型 | 含义 |
| vecn | 包含n个float分量的默认向量 |
| bvecn | 包含n个bool分量的向量 |
| ivecn | 包含n个int分量的向量 |
| uvecn | 包含n个unsigned int分量的向量 |
| dvecn | 包含n个double分量的向量 |
重组swizzling
一个向量的分量可以通过vec.x这种方式获取,这里x是指这个向量的第一个分量。你可以分别使用.x、.y、.z和.w来获取它们的第1、2、3、4个分量。GLSL也允许你对颜色使用rgba,或是对纹理坐标使用stpq访问相同的分量。
向量这一数据类型也允许一些有趣而灵活的分量选择方式,叫做(Swizzling)。重组允许这样的语法:
vec2 someVec;
vec4 differentVec = someVec.xyxx;
vec3 anotherVec = differentVec.zyw;
vec4 otherVec = someVec.xxxx + anotherVec.yxzy;
你可以使用上面4个字母任意组合来创建一个和原来向量一样长的(同类型)新向量,只要原来向量有那些分量即可;然而,你不允许在一个vec2向量中去获取.z元素。我们也可以把一个向量作为一个参数传给不同的向量构造函数,以减少需求参数的数量:
vec2 vect = vec2(0.5, 0.7);
vec4 result = vec4(vect, 0.0, 0.0);
vec4 otherResult = vec4(result.xyz, 1.0);
uniform
是一种从CPU中的应用向GPU中的着色器发送数据的方式,但uniform和顶点属性有些不同。首先,uniform是(Global)。全局意味着uniform变量必须在每个着色器程序对象中都是独一无二的,而且它可以被着色器程序的任意着色器在任意阶段访问。第二,无论你把uniform值设置成什么,uniform会一直保存它们的数据,直到它们被重置或更新。
输入输出
vertexShader与fragShader链接
**顶点着色器**
#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;
}
如何使用GLSL
使用canvas.getContext('webgl'), 就可以使用gl实例的语法了 eg
.createShader(shaderType)
.shaderSource(shaderInstance, option)
.compileShader(shaderInstance)
.createProgram()
.attachShader(programInstance, shaderInstance)
.linkProgram(programInstance)
.useProgram(programInstance)
.createBuffer()
.bindBuffer(bufferType, bufferInstance)
.bufferData(bufferType, data)
.vertexAttribArrary()
.enableVertexAttribArray(position)
.drawArrays()
可以解决前端的什么问题呢?
生成图片、修改图片
减少引入切图
结论
但是使用OpenGL绘制图形还是很难的(很多时候是一个数学问题)吧 所以权衡一下把