WebGL系列教程八(GLSL着色器基础语法)
目录
- 1 前言
- 2 基本原则
- 3 基本数据类型
- 4 顶点着色器和片元着色器
- 4.1 声明
- 4.2 初始化项目
- 4.3 赋值
- 5 结构体
- 5.1 声明
- 5.2 赋值
- 6 函数
- 6.1 基本结构
- 6.2 自定义函数
- 6.3 常用内置函数
- 7 精度
- 8 其他
- 9 总结
1 前言
通过前七讲,我们已经见过了WebGL
中的部分基础语法,这一讲我们来完善一下WebGL
中的语法。GLSL
是OpenGL Shading Language
的首字母缩写,表示的含义就是着色器语言。而我们在第一讲中就已经说过,WebGL
中使用的是GLSL
的ES
版本,ES
即Embedded 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 基本数据类型
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.02.0,2.0);//2*2的矩阵,列主序,即相当于 1.0,2.0】,mat3,mat4同理
mat3 = mat3(1.0,1.0,1.02.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 声明
//顶点着色器
<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 初始化项目
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 赋值
//获取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 声明
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 赋值
// 设置 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 基本结构
返回类型 函数名(参数列表) {// 函数体return 返回值; // 如果返回类型不是 void
}
例如:add 是函数名,接受两个 float 类型的参数 a 和 b,并返回它们的和。
float add(float a, float b) {return a + b;
}
6.2 自定义函数
// 自定义函数:计算镜面反射
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 常用内置函数
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
有很大的帮助,希望读者仔细体会,回见~
相关文章:

WebGL系列教程八(GLSL着色器基础语法)
目录 1 前言2 基本原则3 基本数据类型4 顶点着色器和片元着色器4.1 声明4.2 初始化项目4.3 赋值 5 结构体5.1 声明5.2 赋值 6 函数6.1 基本结构6.2 自定义函数6.3 常用内置函数 7 精度8 其他9 总结 1 前言 通过前七讲,我们已经见过了WebGL中的部分基础语法ÿ…...

go多线程
1、简单使用(这个执行完成,如果进程执行比较久,这里不会等待它们结束) package mainimport "time"func main() {go func() {println("Hello, World!")}()time.Sleep(1 * time.Second) }2、wg.Add(数量)使用&…...
【话题】如何看待IBM中国研发部裁员?
(一)背景 在全球化的大趋势下,跨国公司的业务布局一直处于动态调整之中。IBM 作为全球知名的 IT 企业,在中国市场已经运营多年,其在中国的研发中心曾经为公司的全球业务发展做出了重要贡献。近年来,全球经…...

【C/C++】涉及string类的经典OJ编程题
【C/C】涉及string类的经典OJ编程题 一. 把字符串转化成整数(atoi)解法一:(不用long)完整代码:解法二:(用long) 二.字符串相加代码实现(含注释)&a…...
淘系等电商平台API接口系列:商品详情数据解析,json数据返回参考
——在成长的路上,我们都是同行者。这篇关于商品详情API接口的文章,希望能帮助到您。期待与您继续分享更多API接口的知识,请记得关注Anzexi58哦! 在淘系(如淘宝、天猫)等电商平台中,商品详情数据…...
vue组件之间的数据共享
一、组件之间的关系 1.父子关系 2.兄弟关系 3.后代关系 二、父子组件之间的数据共享 1.父-->子共享数据 父组件通过v-bind属性绑定向子组件共享数据,子组件需要使用props接受数据。 <template><p>父组件</p><Son :msg"msg"…...
LangChain:构建强大的LLM应用的全方位框架
LangChain:构建强大的LLM应用的全方位框架 引言 在人工智能和大语言模型(LLMs)快速发展的今天,开发者们迫切需要一个强大而灵活的框架来简化LLM应用的开发过程。LangChain应运而生,它不仅提供了丰富的工具和组件&…...

自有平台自有品牌如何利用电商API接口做定价参考(多平台商品详情数据接口)
如今,多数自有商城自有品牌在为产品做定价时都会参考淘宝|天猫|京东等主流电商平台的商品价格以做参考,这一行为的好处主要有以下几点: 通过参考主流平台价格,用户更能了解目标市场中消费者对产品的接受度,从而制定出符…...

三万字长文Java面试题——基础篇(注:该篇博客将会一直维护 最新维护时间:2024年9月18日)
🧸本篇博客重在讲解Java基础的面试题,将会实时更新,欢迎大家添加作者文末联系方式交流 📜JAVA面试题专栏:JAVA崭新面试题——2024版_dream_ready的博客-CSDN博客 📜作者首页: dream_ready-CSDN博…...
数学建模——熵权+TOPSIS+肘部法则+系统聚类
文章目录 一、起因二、代码展示 一、起因 我本科的数学建模队长找上我,让我帮她写下matlab代码,当然用的模型还是曾经打比赛的模型,所以虽然代码量多,但是写的很快,也是正逢中秋,有点时间。 当然我也没想到…...

Java | Leetcode Java题解之第403题青蛙过河
题目: 题解: class Solution {public boolean canCross(int[] stones) {int n stones.length;boolean[][] dp new boolean[n][n];dp[0][0] true;for (int i 1; i < n; i) {if (stones[i] - stones[i - 1] > i) {return false;}}for (int i 1…...
828华为云征文|华为Flexus云服务器搭建OnlyOffice私有化在线办公套件
一、引言 在当今数字化办公的时代,在线办公套件的需求日益增长。华为Flexus云服务器凭借其强大的性能和稳定性,为搭建OnlyOffice私有化在线办公套件提供了理想的平台。在2024年9月14日这个充满探索精神的日子里,我们开启利用华为Flexus云服务…...

[Java]maven从入门到进阶
介绍 apache旗下的开源项目,用于管理和构建java项目的工具 官网: Welcome to The Apache Software Foundation! 1.依赖管理 通过简单的配置, 就可以方便的管理项目依赖的资源(jar包), 避免版本冲突问题 优势: 基于项目对象模型(POM),通过一小段描述信息来管理项目的构建 2…...

Leetcode面试经典150题-130.被围绕的区域
给你一个 m x n 的矩阵 board ,由若干字符 X 和 O 组成,捕获 所有 被围绕的区域: 连接:一个单元格与水平或垂直方向上相邻的单元格连接。区域:连接所有 O 的单元格来形成一个区域。围绕:如果您可以用 X 单…...

Ruffle 继续在开源软件中支持 Adobe Flash Player
大多数人已经无需考虑对早已寿终正寝的 Adobe Flash 的支持,但对于那些仍有一些 Adobe Flash/SWF 格式的旧资产,或想重温一些基于 Flash 的旧游戏/娱乐项目的人来说,开源 Ruffle 项目仍是 2024 年及以后处理 Flash 的主要竞争者之一。 Ruffl…...

【postgres】笔记
数据库相关笔记 1.分区表创建时间戳设置问题2.查询语句2.1查询数据库某表有多少行2.2 表中某列值类型是 1.分区表创建时间戳设置问题 今天早上发现postgres数据库表中总会隔4天丢失一天的数据,后来查了一下,发现是分区表创建的有问题。 如图所示 可以看…...
#if等命令的学习
预处理命令 #include(文件包含命令) #define(宏定义命令) #undef #if(条件编译) #ifdef #ifndef #elif #endif defined函数(与if等结合使用) 下面将解释上述各自的用法、使用…...

【有啥问啥】深入浅出马尔可夫链蒙特卡罗(Markov Chain Monte Carlo, MCMC)算法
深入浅出马尔可夫链蒙特卡罗(Markov Chain Monte Carlo, MCMC)算法 0. 引言 Markov Chain Monte Carlo(MCMC)是一类用于从复杂分布中采样的强大算法,特别是在难以直接计算分布的情况下。它广泛应用于统计学、机器学习…...

java企业办公自动化OA
技术架构: sshjbpm 功能描述: 用户管理,岗位管理,部门管理,权限管理,网上交流,贴吧,审批流转。权限管理是树状结构人性化操作,也可以用作论坛。 效果图:...

【leetcode】树形结构习题
二叉树的前序遍历 返回结果:[‘1’, ‘2’, ‘4’, ‘5’, ‘3’, ‘6’, ‘7’] 144.二叉树的前序遍历 - 迭代算法 给你二叉树的根节点 root ,返回它节点值的 前序 遍历。 示例 1: 输入:root [1,null,2,3] 输出:[1,…...

手游刚开服就被攻击怎么办?如何防御DDoS?
开服初期是手游最脆弱的阶段,极易成为DDoS攻击的目标。一旦遭遇攻击,可能导致服务器瘫痪、玩家流失,甚至造成巨大经济损失。本文为开发者提供一套简洁有效的应急与防御方案,帮助快速应对并构建长期防护体系。 一、遭遇攻击的紧急应…...
DockerHub与私有镜像仓库在容器化中的应用与管理
哈喽,大家好,我是左手python! Docker Hub的应用与管理 Docker Hub的基本概念与使用方法 Docker Hub是Docker官方提供的一个公共镜像仓库,用户可以在其中找到各种操作系统、软件和应用的镜像。开发者可以通过Docker Hub轻松获取所…...
QMC5883L的驱动
简介 本篇文章的代码已经上传到了github上面,开源代码 作为一个电子罗盘模块,我们可以通过I2C从中获取偏航角yaw,相对于六轴陀螺仪的yaw,qmc5883l几乎不会零飘并且成本较低。 参考资料 QMC5883L磁场传感器驱动 QMC5883L磁力计…...

解决Ubuntu22.04 VMware失败的问题 ubuntu入门之二十八
现象1 打开VMware失败 Ubuntu升级之后打开VMware上报需要安装vmmon和vmnet,点击确认后如下提示 最终上报fail 解决方法 内核升级导致,需要在新内核下重新下载编译安装 查看版本 $ vmware -v VMware Workstation 17.5.1 build-23298084$ lsb_release…...

dedecms 织梦自定义表单留言增加ajax验证码功能
增加ajax功能模块,用户不点击提交按钮,只要输入框失去焦点,就会提前提示验证码是否正确。 一,模板上增加验证码 <input name"vdcode"id"vdcode" placeholder"请输入验证码" type"text&quo…...

高等数学(下)题型笔记(八)空间解析几何与向量代数
目录 0 前言 1 向量的点乘 1.1 基本公式 1.2 例题 2 向量的叉乘 2.1 基础知识 2.2 例题 3 空间平面方程 3.1 基础知识 3.2 例题 4 空间直线方程 4.1 基础知识 4.2 例题 5 旋转曲面及其方程 5.1 基础知识 5.2 例题 6 空间曲面的法线与切平面 6.1 基础知识 6.2…...
Java入门学习详细版(一)
大家好,Java 学习是一个系统学习的过程,核心原则就是“理论 实践 坚持”,并且需循序渐进,不可过于着急,本篇文章推出的这份详细入门学习资料将带大家从零基础开始,逐步掌握 Java 的核心概念和编程技能。 …...

Python基于历史模拟方法实现投资组合风险管理的VaR与ES模型项目实战
说明:这是一个机器学习实战项目(附带数据代码文档),如需数据代码文档可以直接到文章最后关注获取。 1.项目背景 在金融市场日益复杂和波动加剧的背景下,风险管理成为金融机构和个人投资者关注的核心议题之一。VaR&…...

Netty从入门到进阶(二)
二、Netty入门 1. 概述 1.1 Netty是什么 Netty is an asynchronous event-driven network application framework for rapid development of maintainable high performance protocol servers & clients. Netty是一个异步的、基于事件驱动的网络应用框架,用于…...

STM32---外部32.768K晶振(LSE)无法起振问题
晶振是否起振主要就检查两个1、晶振与MCU是否兼容;2、晶振的负载电容是否匹配 目录 一、判断晶振与MCU是否兼容 二、判断负载电容是否匹配 1. 晶振负载电容(CL)与匹配电容(CL1、CL2)的关系 2. 如何选择 CL1 和 CL…...