图形学和OpenGL

2020-12-03  本文已影响0人  Jassi

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从顶点数据中直接接收输入,使用​location​这一元数据指定输入变量。顶点着色器需要为它的输入提供一个额外的​layout​标识,这样我们才能把它链接到顶点数据​layout (location = 0)​。在OpenGL代码中使用查询属性位置值(Location)

fragment,它需要一个​vec4​颜色输出变量,因为片段着色器需要生成一个最终输出的颜色。如果你在片段着色器没有定义输出颜色,OpenGL会把你的物体渲染为黑色(或白色)。

数据类型:

Vector类型:

<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绘制图形还是很难的(很多时候是一个数学问题)吧 所以权衡一下把

上一篇 下一篇

猜你喜欢

热点阅读