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

news2025/2/22 17:31:27

目录

  • 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中的语法。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 基本数据类型

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 声明

//顶点着色器
<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.0smoothstep(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有很大的帮助,希望读者仔细体会,回见~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2134496.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

初始爬虫1(补充)

TCP 和 UDP 是什么&#xff1f; TCP&#xff08;Transmission Control Protocol&#xff09;和 UDP&#xff08;User Datagram Protocol&#xff09;都是传输层协议&#xff0c;它们负责在计算机网络上发送和接收数据包。两者有不同的特性和适用场景&#xff1a; TCP&#xff0…

文档团队如何组成?

经常有朋友问我文档团队是由怎样背景的人组成的&#xff1f;今天来聊聊这个话题。 中国贸促会和技术传播专委会以及lnfomagic学院2023年在技术传播行业做了一个调查&#xff0c;在收到的231份有效样本中显示&#xff0c; 受访群体的背景主要是两大类&#xff0c;他们分别是技术…

视频推镜拍摄SDK解决方案,创新短视频玩法

在当今社交媒体盛行的时代&#xff0c;短视频已成为人们分享生活、展示创意的重要方式。美摄科技推出的视频推镜拍摄SDK解决方案&#xff0c;为用户提供了一种全新的短视频创作体验。 一、什么是视频推镜拍摄SDK解决方案&#xff1f; 美摄科技的视频推镜拍摄SDK解决方案是一种…

虹科方案 | 精准零部件测试!多路汽车开关按键功能检测系统

欢迎关注虹科&#xff0c;为您提供最新资讯&#xff01; #LIN/CAN总线 #零部件测试 #CAN数据 导读 在汽车制造业中&#xff0c;零部件的安全性、功能性和可靠性是确保车辆整体性能的关键。虹科针对车辆零部件的LIN/CAN总线仿真测试&#xff0c;提出了基于虹科Baby-LIN系列产…

详细分析linux中的MySql跳过密码验证以及Bug(图文)

目录 1.问题所示2. 基本知识3. 解决方法3.1 跳过验证Bug3.2 设定初始密码 1.问题所示 发现密码验证错误&#xff0c;遗失密码 2. 基本知识 停止MySQL服务&#xff1a;sudo systemctl stop mysql 以跳过权限表模式启动MySQL&#xff1a;sudo mysqld_safe --skip-grant-tables …

移情别恋c++ ദ്ദി˶ー̀֊ー́ ) ——12.二叉树(习题)

1.根据二叉树创建字符串 . - 力扣&#xff08;LeetCode&#xff09; 我的思路&#xff1a; 1. 根节点单独讨论&#xff0c;因为&#xff0c;根节点之后才会开始有括号 2.根节点的左孩子和右孩子分别进入operation函数 operation函数&#xff1a; 1.如果root不为空&#xff0c;…

计算机毕业设计选题推荐-在线投票系统-Java/Python项目实战

✨作者主页&#xff1a;IT研究室✨ 个人简介&#xff1a;曾从事计算机专业培训教学&#xff0c;擅长Java、Python、微信小程序、Golang、安卓Android等项目实战。接项目定制开发、代码讲解、答辩教学、文档编写、降重等。 ☑文末获取源码☑ 精彩专栏推荐⬇⬇⬇ Java项目 Python…

程序员的 AI 启蒙:ChatGPT+ Copilot开发Vue3 仿简书项目 90%代码AI生成

在人工智能技术日益成熟的今天&#xff0c;程序员们正在迎来一场全新的编程革命。ChatGPT和Copilot等AI工具的出现&#xff0c;让代码生成不再是遥不可及的梦想。本文将带你体验如何利用这些先进技术&#xff0c;仅用90%的代码量&#xff0c;开发出一个基于Vue3的仿简书项目&am…

电容笔有必要买吗?西圣、wiwu、倍思好不好用?王者产品测评对比

当下很多年轻人都热衷于使用 iPad 来进行学习与娱乐&#xff0c;因此电容笔还是很有必要买的&#xff0c;它可以提升我们的效率。然而作为一名数码测评博主&#xff0c;我十分清楚一旦选到质量不佳的产品&#xff0c;就会出现诸如断触、延迟等问题&#xff0c;进而拉低效率。 …

2024年9月一区SCI-神经种群动态优化算法NPDOA-附Matlab免费代码

引言 本期介绍了一种受脑神经科学启发的元启发式算法&#xff0c;称为神经种群动态优化算法Neural population dynamics optimization algorithm(NPDOA)的元启发式算法。该成果于2024年9月最新发表在中科院1区 Top SCI期刊 Knowledge-Based Systems。 原文作者将NPDOA与其他9种…

大学生必备10个AI工具网站,辅助完成辩论/开题/实践/形势政策报告、创新创业计划书、思想汇报、心得感悟等作业,提升学习效率和学术表现!

大学新生和学长学姐们都已经开学了&#xff0c;忙碌的课程和多样的作业也随之开始&#xff0c;下面将给大学生们介绍10个辅助完成作业、寻找灵感&#xff0c;提升学习专注力和学术表现的AI工具~ 1、笔墨写作 笔墨写作 - 领先的写作智能AI创作平台 | 官方首页笔墨写作是一款专…

深度剖析去中心化存储:IPFS、Arweave 和 BNB Greenfield 的技术革新与生态系统演进

引言&#xff1a; 在数字时代的浪潮中&#xff0c;数据已然成为驱动创新和决策的核心资产。然而&#xff0c;随着数据量呈指数级增长&#xff0c;传统中心化存储模式面临着前所未有的挑战。安全漏洞、隐私泄露、数据垄断等问题日益凸显&#xff0c;促使技术界重新思考数据存储…

QT多线程编程(基础概念以及示例)

QT多线程编程 前言&#xff1a;基础夯实&#xff1a;一:多线程概述二:QT多线程的使用1. 继承QThread类2. 继承QObject类3. QtConcurrent模块 三:线程同步与通信四:线程安全五:线程管理六:总结 效果展示&#xff1a;实现功能&#xff1a;核心代码&#xff1a;mainwindow.hmythre…

2024数学建模国赛官方评阅标准发布!

​↑​↑​↑​↑​↑​↑​↑​↑​↑​↑​↑​↑​↑​↑​↑​↑​↑​↑​↑​↑​↑​↑​↑​↑​↑​↑​↑​↑​↑​↑​↑​↑​↑​↑​↑​↑​↑​↑​↑​↑​↑​↑​↑​↑​↑​↑​↑​↑​↑​↑​↑​↑​↑​↑​↑​↑​↑​↑​↑​↑​↑​↑​↑​↑…

被百度 AI 文心一言推荐的 Mac App 惊喜到了!

由于工作需要&#xff0c;我需要一款 Mac 软件帮我记录所有的复制记录。 当我去百度搜索“mac 复制记录”“mac 复制历史”时&#xff0c;百度 AI 给我推荐了这三款 App&#xff1a;Maccy、CleanClip、Collect Boy。 我开始分别试用这三款软件&#xff0c;我现在还没全部试用完…

002集—— CAD划线并模拟向命令窗口发送命令(CAD—C#二次开发入门)

模拟向命令窗口发送全图居中的命令&#xff1a; Application.DocumentManager.MdiActiveDocument.SendStringToExecute("z\ne\n",true,false,false); 弹窗命令&#xff1a; Application.ShowAlertDialog("Erase the newly added polyline."); 本例在ca…

macos清理垃圾桶时提示 “操作无法完成,因为该项目正在使用中” 解决方法 , 强制清理mac废纸篓 方法

在macos中&#xff0c;删除文件后&#xff0c; 在清理垃圾桶时提示 “操作无法完成&#xff0c;因为该项目正在使用中” 出现这个提示&#xff0c;在大多数的情况下是因为数据问题导致&#xff0c;需要通过磁盘管理工具进行修复&#xff0c;修复后才可彻底的清理垃圾桶。 另外…

FPGA低功耗设计

FPGA低功耗设计 文章目录 FPGA低功耗设计前言一、功耗类型1.1 动态功耗1.2 静态功耗1.3 浪涌功耗 二、系统级低功耗设计2.1 **多电压技术&#xff1a;**即工作频率、电压和功耗的关系2.2 系统时钟分配&#xff1a;2.3 软硬件划分2.4 p 或单元库选择 三、RTL级别低功耗设计3.1 并…

运算放大电路

填鸭子呢 兴趣没了&#xff0c;啥也没了 运行过程&#xff0c;少了什么 差分放大 二极放大 功率放大 输出为饱和 反馈调整放大 倍数 考试 我可以认为就应该那样 但理解却不能如 懂了不妨碍我不会用 会用不妨碍我不懂 也想设计一个如哆来A梦那样的&#xff1b; 什么…

Gapless-REMA100:一个通过多源DEM填补空白的南极洲无缝100米参考高程模型

ABSTRACT 南极洲的数字高程模型&#xff08;DEM&#xff09;是冰川学应用中至关重要的数据集&#xff0c;广泛用于从野外工作规划到冰盖动力学分析等多个方面。高空间分辨率的DEM数据能够更详细地描绘地形。南极洲参考高程模型&#xff08;REMA&#xff09;马赛克是最近发布的…