WebGL 3着色器和GLSL

我们之前提到过着色器和GLSL,但是没有涉及细节,你可能已经对此有所了解, 但以防万一,这里将详细讲解着色器和GLSL。

工作原理中我们提到,WebGL每次绘制需要两个着色器, 一个顶点着色器 和一个片段着色器 ,每一个着色器都是一个方法

一个顶点着色器和一个片段着色器链接在一起放入一个着色程序中(或者只叫程序)。

一个典型的WebGL应用会有多个着色程序。


顶点着色器

一个顶点着色器的工作是生成裁剪空间坐标值,通常是以下的形式

bash 复制代码
void main() {
   gl_Position = doMathToMakeClipspaceCoordinates
}

每个顶点调用一次(顶点)着色器,每次调用都需要设置一个特殊的全局变量gl_Position, 该变量的值就是裁剪空间坐标值。

顶点着色器需要的数据,可以通过以下三种方式获得。

Attributes 属性(从缓冲中获取的数据)

最常用的方法是缓冲和属性 ,在工作原理 中讲到了缓冲和属性,你可以创建缓冲

javascript 复制代码
var buf = gl.createBuffer();

将数据存入缓冲

javascript 复制代码
gl.bindBuffer(gl.ARRAY_BUFFER, buf);
gl.bufferData(gl.ARRAY_BUFFER, someData, gl.STATIC_DRAW);

然后初始化的时候,在你制作的(着色)程序中找到属性所在地址

javascript 复制代码
var positionLoc = gl.getAttribLocation(someShaderProgram, "a_position");

在渲染的时候告诉WebGL怎么从缓冲中获取数据传递给属性

javascript 复制代码
// 开启从缓冲中获取数据
gl.enableVertexAttribArray(positionLoc);
 
var numComponents = 3;  // (x, y, z)
var type = gl.FLOAT;    // 32位浮点数据
var normalize = false;  // 不标准化
var offset = 0;         // 从缓冲起始位置开始获取
var stride = 0;         // 到下一个数据跳多少位内存
                        // 0 = 使用当前的单位个数和单位长度 ( 3 * Float32Array.BYTES_PER_ELEMENT )
 
gl.vertexAttribPointer(positionLoc, numComponents, type, false, stride, offset);

属性可以用 float, vec2, vec3, vec4, mat2, mat3mat4 数据类型。

Uniforms 全局变量(在一次绘制中对所有顶点保持一致值)

全局变量在一次绘制过程中传递给着色器的值都一样。

在下面的一个简单的例子中, 用全局变量给顶点着色器添加了一个偏移量

bash 复制代码
attribute vec4 a_position;
uniform vec4 u_offset;
 
void main() {
   gl_Position = a_position + u_offset;
}

现在可以把所有顶点偏移一个固定值,首先在初始化时找到全局变量的地址

javascript 复制代码
var offsetLoc = gl.getUniformLocation(someProgram, "u_offset");

然后在绘制前设置全局变量

javascript 复制代码
gl.uniform4fv(offsetLoc, [1, 0, 0, 0]);  // 向右偏移一半屏幕宽度

要注意的是全局变量属于单个着色程序,如果多个着色程序有同名全局变量,需要找到每个全局变量并设置自己的值。 我们调用gl.uniform???的时候只是设置了当前程序 的全局变量,当前程序是传递给gl.useProgram 的最后一个程序

纹理(顶点着色器中)

Textures 纹理(在片段着色器中)

片段着色器

​​​​​​​一个片段着色器的工作是为当前光栅化的像素提供颜色值,通常是以下的形式

javascript 复制代码
precision mediump float;
 
void main() {
   gl_FragColor = doMathToMakeAColor;
}

每个像素都将调用一次片段着色器,每次调用需要从特殊全局变量gl_FragColor中获取颜色信息

Uniform 全局变量(片段着色器中)

Uniforms 全局变量.

Textures 纹理(片段着色器中 来自 Pixels/Texel 的数据)

在着色器中获取纹理信息,可以先创建一个sampler2D类型全局变量,然后用GLSL方法texture2D 从纹理中提取信息。

javascript 复制代码
precision mediump float;
 
uniform sampler2D u_texture;
 
void main() {
   vec2 texcoord = vec2(0.5, 0.5);  // 获取纹理中心的值
   gl_FragColor = texture2D(u_texture, texcoord);
}

从纹理中获取的数据取决于很多设置。 至少要创建并给纹理填充数据,例如

javascript 复制代码
var tex = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, tex);
var level = 0;
var width = 2;
var height = 1;
var data = new Uint8Array([
   255, 0, 0, 255,   // 一个红色的像素
   0, 255, 0, 255,   // 一个绿色的像素
]);
gl.texImage2D(gl.TEXTURE_2D, level, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, data);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);

在初始化时找到全局变量的地址

javascript 复制代码
var someSamplerLoc = gl.getUniformLocation(someProgram, "u_texture");

在渲染的时候WebGL要求纹理必须绑定到一个纹理单元上

javascript 复制代码
var unit = 5;  // 挑选一个纹理单元
gl.activeTexture(gl.TEXTURE0 + unit);
gl.bindTexture(gl.TEXTURE_2D, tex);

然后告诉着色器你要使用的纹理在那个纹理单元

javascript 复制代码
gl.uniform1i(someSamplerLoc, unit);

Varyings 可变量(从 Vertex Shader 传递并插值的数据)

工作原理提到过,可变量是一种顶点着色器给片段着色器传值的方式。

为了使用可变量,要在两个着色器中定义同名的可变量。 给顶点着色器中可变量设置的值,会作为参考值进行内插,在绘制像素时传给片段着色器的可变量。

顶点着色器

cpp 复制代码
attribute vec4 a_position;
 
uniform vec4 u_offset;
 
varying vec4 v_positionWithOffset;
 
void main() {
  gl_Position = a_position + u_offset;
  v_positionWithOffset = a_position + u_offset;
}

片段着色器

bash 复制代码
precision mediump float;
 
varying vec4 v_positionWithOffset;
 
void main() {
  // 从裁剪空间 (-1 <-> +1) 转换到颜色空间 (0 -> 1).
  vec4 color = v_positionWithOffset * 0.5 + 0.5;
  gl_FragColor = color;
}

上方的示例几乎没有意义,通常情况下直接将裁剪空间的值传给片段着色器当作颜色值是没有意义的, 虽然它可以运行并且可以生成颜色值。

GLSL

GLSL全称是 Graphics Library Shader Language (图形库着色器语言),是着色器使用的语言。 它有一些不同于JavaScript的特性,主要目的是为栅格化图形提供常用的计算功能。

所以它内建的数据类型例如vec2, vec3vec4分别代表两个值,三个值和四个值, 类似的还有mat2, mat3mat4 分别代表 2x2, 3x3 和 4x4 矩阵。 你可以做一些运算例如常量和矢量的乘法

之后的一些调用方法 以及书写规则等可自行查看,在此就不在赘述

参考:

WebGL 着色器和GLSL

18.WebGL渲染和执行流程 | 前端技术积累

相关推荐
Aurora@Hui2 天前
WebGL & Three.js
webgl
ct9783 天前
Cesium高级特效与着色器开发全指南
前端·gis·cesium·着色器
CC码码4 天前
基于WebGPU实现canvas高级滤镜
前端·javascript·webgl·fabric
ct9784 天前
WebGL 图像处理核心API
图像处理·webgl
ct9786 天前
Cesium 矩阵系统详解
前端·线性代数·矩阵·gis·webgl
vQAvXEsg8 天前
三菱FX5U四轴控制系统实战手记
着色器
ct9789 天前
WebGL Shader性能优化
性能优化·webgl
棋鬼王9 天前
Cesium(一) 动态立体墙电子围栏,Wall墙体瀑布滚动高亮动效,基于Vue3
3d·信息可视化·智慧城市·webgl
Longyugxq11 天前
Untiy的Webgl端网页端视频播放,又不想直接mp4格式等格式的。
unity·音视频·webgl
花姐夫Jun12 天前
cesium基础学习-坐标系统相互转换及相应的场景
学习·webgl