WebGL系列教程八(GLSL着色器基础语法)

目录

  • [1 前言](#1 前言)
  • [2 基本原则](#2 基本原则)
  • [3 基本数据类型](#3 基本数据类型)
  • [4 顶点着色器和片元着色器](#4 顶点着色器和片元着色器)
    • [4.1 声明](#4.1 声明)
    • [4.2 初始化项目](#4.2 初始化项目)
    • [4.3 赋值](#4.3 赋值)
  • [5 结构体](#5 结构体)
    • [5.1 声明](#5.1 声明)
    • [5.2 赋值](#5.2 赋值)
  • [6 函数](#6 函数)
    • [6.1 基本结构](#6.1 基本结构)
    • [6.2 自定义函数](#6.2 自定义函数)
    • [6.3 常用内置函数](#6.3 常用内置函数)
  • [7 精度](#7 精度)
  • [8 其他](#8 其他)
  • [9 总结](#9 总结)

1 前言

通过前七讲,我们已经见过了WebGL中的部分基础语法,这一讲我们来完善一下WebGL中的语法。GLSLOpenGL Shading Language的首字母缩写,表示的含义就是着色器语言。而我们在第一讲中就已经说过,WebGL中使用的是GLSLES版本,ESEmbedded Systems,意为嵌入式系统。因为最初GLSL ES是给嵌入式设备准备的,轻量级的三维图形渲染语言。为了方便,下文统称为GLSL

2 基本原则

1.GLSL是大小写敏感的。

2.GLSL每个语句结束时必须在结尾加上分号。

3.变量名由a-z、A-Z、0-9和下划线组成。

4.变量名不能gl_、webgl_、_webgl_开头。

5.变量名不能和关键字冲突,即不能叫做attribute、uniform等。

6.GLSL是强类型语言,声明时不能以var开头,必须以对应的类型开头。

3 基本数据类型

javascript 复制代码
int i = 8;//整型
float m = 8.0;//浮点型
bool b = false;//布尔型
vec2 v2 = vec2(1.0,2.0);//浮点型二维向量
vec3 v2 = vec3(1.0,2.0,3.0);//浮点型三维向量
vec4 v = vec4(1.0,2.0,3.0,4.0);//浮点型四维向量
//访问时用xyzw、stpq、rgba、【0123】都可以访问
//v.x 和 v.s 以及 v.r , v[0] 表达的是同一个分量。
//v.y 和 v.t 以及 v.g , v[1] 表达的是同一个分量。
//v.z 和 v.p 以及 v.b , v[2] 表达的是同一个分量。
//v.w 和 v.q 以及 v.a , v[3] 表达的是同一个分量。
vec4(v.rgb, 1)和 vec4(v.r, v.g, v.b, 1)//等价
vec4(1)和 vec4(1, 1, 1, 1)//等价
vec4 s = sin(v);和vec4 s = vec4(sin(v.x), sin(v.y), sin(v.z), sin(v.w));//等价
ivec2 iv2 = ivec2(1,2);//整型二维向量
ivec3 iv3 = ivec3(1,2,3);//整型三维向量
ivec4 iv4 = ivec4(1,2,3,4);//整型四维向量
bvec2 bv2 = bvec2(false,true);//布尔型二维向量
bvec3 bv3 = bvec3(false,true,false);//布尔型三维向量
bvec4 bv4 = bvec4(false,true,false,true);//布尔型四维向量
mat2 = mat2(1.0,1.0                         //【1.0,2.0
			2.0,2.0);//2*2的矩阵,列主序,即相当于  1.0,2.0】,mat3,mat4同理
mat3 = mat3(1.0,1.0,1.0
			2.0,2.0,2.0,
			3.0,3.0,3.0);//3*3的矩阵
mat4 = mat4(1.0,1.0,1.0,1.0,
			2.0,2.0,2.0,2.0,
			3.0,3.0,3.0,3.0,
			4.0,4.0,4.0,4.0);/4*4的矩阵
			

4 顶点着色器和片元着色器

4.1 声明

html 复制代码
//顶点着色器
<script id="vertex-shader" type="x-shader/x-vertex">
    //声明属性
    attribute vec4 a_Position;
    attribute vec4 a_Color;
    //声明全局变量,一旦赋值,就不可更改了
    uniform mat4 uRotateMatrix;
    //声明要传递到片元着色的变量
    varying vec4 v_Color;
    void main(){
        gl_Position =  uRotateMatrix * a_Position;
        v_Color = a_Color;
        v_TexCoord = a_TexCoord;
    }
</script>
//片元着色器
<script id="fragment-shader" type="x-shader/x-fragment">
    precision highp float;
    //声明要接收的量
    varying vec4 v_Color;
    void main(){
        gl_FragColor = v_Color;
    }
</script>

4.2 初始化项目

javascript 复制代码
const canvas = document.getElementById("canvas");
const gl = canvas.getContext("webgl");
//创建着色器对象
let vertexShader = gl.createShader(gl.VERTEX_SHADER);
let fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
//获取着色器对象的源
let vertexSource = document.getElementById("vertex-shader").innerText;
let fragmentSource = document.getElementById("fragment-shader").innerText;
//绑定着色器的源
gl.shaderSource(vertexShader,vertexSource);
gl.shaderSource(fragmentShader,fragmentSource);
//编译着色器
gl.compileShader(vertexShader);
gl.compileShader(fragmentShader);
console.log(gl.getShaderInfoLog(vertexShader));
//创建并关联项目
let program = gl.createProgram();
gl.attachShader(program,vertexShader);
gl.attachShader(program,fragmentShader);
gl.linkProgram(program);
gl.useProgram(program);

4.3 赋值

javascript 复制代码
//获取attribute变量
let a_Position = gl.getAttribLocation(program,'a_Position');
//赋值,有多种赋值方法,使用缓冲区见之前博文
gl.vertexAttrib1f (a_Position, v);                 // float
gl.vertexAttrib1fv(a_Position, [v]);               // float 或 float array
gl.vertexAttrib2f (a_Position,  v0, v1);            // vec2
gl.vertexAttrib2fv(a_Position,  [v0, v1]);          // vec2 或 vec2 array
gl.vertexAttrib3f (a_Position,  v0, v1, v2);        // vec3
gl.vertexAttrib3fv(a_Position,  [v0, v1, v2]);      // vec3 或 vec3 array
gl.vertexAttrib4f (a_Position,  v0, v1, v2, v4);    // vec4
gl.vertexAttrib4fv(a_Position,  [v0, v1, v2, v4]);  // vec4 或 vec4 array
//获取attribute变量
let uRotateMatrix= gl.getUniformLocation(program,'uRotateMatrix');
//赋值,有多种赋值方法
gl.uniform1f (uRotateMatrix, v);                 // float
gl.uniform1fv(uRotateMatrix, [v]);               // float 或 float array
gl.uniform2f (uRotateMatrix,  v0, v1);            // vec2
gl.uniform2fv(uRotateMatrix,  [v0, v1]);          // vec2 或 vec2 array
gl.uniform3f (uRotateMatrix,  v0, v1, v2);        // vec3
gl.uniform3fv(uRotateMatrix,  [v0, v1, v2]);      // vec3 或 vec3 array
gl.uniform4f (uRotateMatrix,  v0, v1, v2, v4);    // vec4
gl.uniform4fv(uRotateMatrix,  [v0, v1, v2, v4]);  // vec4 或 vec4 array
//赋值矩阵
gl.uniformMatrix2fv(mat2UniformLoc, false, [  4x element array ])  // mat2 或 mat2 array
gl.uniformMatrix3fv(mat3UniformLoc, false, [  9x element array ])  // mat3 或 mat3 array
gl.uniformMatrix4fv(mat4UniformLoc, false, [ 16x element array ])  // mat4 或 mat4 array
//赋值整型变量
gl.uniform1i (intUniformLoc,   v);                 // int
gl.uniform1iv(intUniformLoc, [v]);                 // int 或 int array
gl.uniform2i (ivec2UniformLoc, v0, v1);            // ivec2
gl.uniform2iv(ivec2UniformLoc, [v0, v1]);          // ivec2 或 ivec2 array
gl.uniform3i (ivec3UniformLoc, v0, v1, v2);        // ivec3
gl.uniform3iv(ivec3UniformLoc, [v0, v1, v2]);      // ivec3 or ivec3 array
gl.uniform4i (ivec4UniformLoc, v0, v1, v2, v4);    // ivec4
gl.uniform4iv(ivec4UniformLoc, [v0, v1, v2, v4]);  // ivec4 或 ivec4 array
//赋值纹理
gl.uniform1i (sampler2DUniformLoc,   v);           // sampler2D (textures)
gl.uniform1iv(sampler2DUniformLoc, [v]);           // sampler2D 或 sampler2D array
//赋值立方体纹理 
gl.uniform1i (samplerCubeUniformLoc,   v);         // samplerCube (textures)
gl.uniform1iv(samplerCubeUniformLoc, [v]);         // samplerCube 或 samplerCube array

5 结构体

5.1 声明

javascript 复制代码
struct Material {
    vec3 ambient;
    vec3 diffuse;
    vec3 specular;
    float shininess;
};

struct Light {
    vec3 position;
    vec3 color;
    float intensity;
};

struct Scene {
    Material material;
    Light light;
};
uniform Scene uScene;

void main() {
    vec3 ambient = uScene.material.ambient * uScene.light.color;
}

5.2 赋值

javascript 复制代码
// 设置 Material
gl.uniform3f(gl.getUniformLocation(program, 'uScene.material.ambient'), 1.0, 0.5, 0.31);
gl.uniform3f(gl.getUniformLocation(program, 'uScene.material.diffuse'), 1.0, 0.5, 0.31);
gl.uniform3f(gl.getUniformLocation(program, 'uScene.material.specular'), 0.5, 0.5, 0.5);
gl.uniform1f(gl.getUniformLocation(program, 'uScene.material.shininess'), 32.0);

// 设置 Light
gl.uniform3f(gl.getUniformLocation(program, 'uScene.light.position'), 10.0, 10.0, 10.0);
gl.uniform3f(gl.getUniformLocation(program, 'uScene.light.color'), 1.0, 1.0, 1.0);
gl.uniform1f(gl.getUniformLocation(program, 'uScene.light.intensity'), 1.0);

6 函数

6.1 基本结构

javascript 复制代码
返回类型 函数名(参数列表) {
    // 函数体
    return 返回值; // 如果返回类型不是 void
}
例如:add 是函数名,接受两个 float 类型的参数 a 和 b,并返回它们的和。
float add(float a, float b) {
    return a + b;
}

6.2 自定义函数

javascript 复制代码
// 自定义函数:计算镜面反射
vec3 calculateSpecular(vec3 normal, vec3 viewDir, vec3 lightDir, float shininess) {
    vec3 reflectDir = reflect(-lightDir, normal);
    float spec = pow(max(dot(viewDir, reflectDir), 0.0), shininess);
    return spec * vec3(1.0); // 假设镜面反射颜色为白色
}

void main() {
    vec3 normal = normalize(vNormal);
    vec3 lightDir = normalize(uLightPos - vFragPos);
    vec3 viewDir = normalize(uViewPos - vFragPos);

    // 使用自定义函数计算镜面反射
    vec3 specular = calculateSpecular(normal, viewDir, lightDir, 32.0);

    fragColor = vec4(specular, 1.0);
}

6.3 常用内置函数

javascript 复制代码
sin(x):返回 x 的正弦值,x 为弧度。
cos(x):返回 x 的余弦值。
tan(x):返回 x 的正切值。
asin(x):返回 x 的反正弦值,结果为弧度。
acos(x):返回 x 的反余弦值。
atan(x):返回 x 的反正切值。
atan(y, x):返回从 (x, y) 到原点的角度,结果为弧度
exp(x):返回 e^x。
log(x):返回 ln(x),即自然对数。
log2(x):返回以 2 为底的对数。
pow(x, y):返回 x 的 y 次幂。
sqrt(x):返回 x 的平方根。
inversesqrt(x):返回 1 / sqrt(x)。
abs(x):返回 x 的绝对值。
sign(x):返回 x 的符号,-1.0(负数),0.0(零),1.0(正数)。
floor(x):返回不大于 x 的最大整数。
ceil(x):返回不小于 x 的最小整数。
round(x):返回四舍五入后的整数。
mod(x, y):返回 x 除以 y 的余数。
min(x, y):返回 x 和 y 中较小的值。
max(x, y):返回 x 和 y 中较大的值。
clamp(x, minVal, maxVal):将 x 限制在 minVal 和 maxVal 之间。
mix(x, y, a):线性插值,返回 (1 - a) * x + a * y。
step(edge, x):阶跃函数,如果 x < edge 返回 0.0,否则返回 1.0。
smoothstep(edge0, edge1, x):平滑的阶跃函数,x 在 edge0 和 edge1 之间时进行平滑过渡。
dot(x, y):计算向量 x 和 y 的点积。
cross(x, y):计算向量 x 和 y 的叉积(仅适用于 vec3)。
normalize(x):将向量 x 归一化。
length(x):返回向量 x 的长度。
distance(x, y):返回向量 x 和 y 之间的距离。
reflect(I, N):计算入射向量 I 关于法线 N 的反射向量。
refract(I, N, eta):计算入射向量 I 关于法线 N 的折射向量,eta 为折射率比。
transpose(x):返回矩阵 x 的转置。
inverse(x):返回矩阵 x 的逆矩阵。
matrixCompMult(x, y):按元素相乘两个矩阵 x 和 y。
faceforward(N, I, Nref):根据视角调整法线方向,确保法线朝向观察者。
texture(sampler, coord):根据纹理坐标 coord 从 sampler 采样纹理。
textureLod(sampler, coord, lod):带有指定层次细节级别的纹理采样。
textureProj(sampler, coord):投影纹理采样。
textureGrad(sampler, coord, dPdx, dPdy):带有梯度信息的纹理采样。
min(x, y):返回 x 和 y 中较小的值。
max(x, y):返回 x 和 y 中较大的值。
clamp(x, minVal, maxVal):将 x 限制在 minVal 和 maxVal 之间。
step(edge, x):阶跃函数。
smoothstep(edge0, edge1, x):平滑的阶跃函数。

7 精度

8 其他

其他的如if判断,for循环等于C语言、JavaScript一样,这里不再赘述。

9 总结

本篇中我们介绍了GLSL的基础语法,略显枯燥乏味,但对我们能够是否熟练掌握WebGL有很大的帮助,希望读者仔细体会,回见~

相关推荐
mxwin5 小时前
Unity URP 多线程渲染:理解 Shader 变体对加载时间的影响
unity·游戏引擎·shader
sp42a3 天前
如何在 NativeScript 中使用 iOS 的 Metal 着色器
ios·着色器·nativescript
三维搬砖者4 天前
AI 解密大厂 Three.js 三维引擎开发 03|从经纬度到三维世界的坐标解码
webgl·three.js
mxwin6 天前
Unity Shader 逐像素光照 vs 逐顶点光照性能与画质的权衡策略
unity·游戏引擎·shader·着色器
mxwin6 天前
Unity URP 全局光照 (GI) 完全指南 Lightmap 采样与实时 GI(光照探针、反射探针)的 Shader 集成
unity·游戏引擎·shader·着色器
mxwin6 天前
Unity URP 溶解效果基于噪声纹理与 clip 函数实现物体渐隐渐显
unity·游戏引擎·shader
mxwin7 天前
Unity URP 下的 Early-Z / Depth Prepass 解决复杂片元着色器造成的 Overdraw 问题
unity·游戏引擎·着色器
mxwin7 天前
Unity Shader 顶点色:利用模型顶点颜色传递渲染数据
unity·游戏引擎·shader
mxwin7 天前
Unity URP 下的 GPU Instancing减少 DrawCall 的关键技术
unity·游戏引擎·shader
mxwin7 天前
Unity URP SRP Batcher 完全指南 URP/HDRP 下的核心批处理机制,大幅降低 CPU 开销
unity·游戏引擎·shader·单一职责原则