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

上一篇下一篇

猜你喜欢

热点阅读