当前位置: 首页 > article >正文

WebGL 3着色器和GLSL

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

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

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

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


顶点着色器

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

void main() {gl_Position = doMathToMakeClipspaceCoordinates
}

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

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

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

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

var buf = gl.createBuffer();

将数据存入缓冲

gl.bindBuffer(gl.ARRAY_BUFFER, buf);
gl.bufferData(gl.ARRAY_BUFFER, someData, gl.STATIC_DRAW);

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

var positionLoc = gl.getAttribLocation(someShaderProgram, "a_position");

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

// 开启从缓冲中获取数据
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);

属性可以用 floatvec2vec3vec4mat2mat3 和 mat4 数据类型。

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

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

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

    attribute vec4 a_position;
    uniform vec4 u_offset;void main() {gl_Position = a_position + u_offset;
    }

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

    var offsetLoc = gl.getUniformLocation(someProgram, "u_offset");

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

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

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

    纹理(顶点着色器中)

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

    片段着色器

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

    precision mediump float;void main() {gl_FragColor = doMathToMakeAColor;
    }

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

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

    同 Uniforms 全局变量.

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

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

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

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

    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);

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

    var someSamplerLoc = gl.getUniformLocation(someProgram, "u_texture");

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

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

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

    gl.uniform1i(someSamplerLoc, unit);

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

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

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

    顶点着色器

    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;
    }

    片段着色器

    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的特性,主要目的是为栅格化图形提供常用的计算功能。

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

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

    参考: 

    WebGL 着色器和GLSL

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

    相关文章:

    WebGL 3着色器和GLSL

    我们之前提到过着色器和GLSL&#xff0c;但是没有涉及细节&#xff0c;你可能已经对此有所了解&#xff0c; 但以防万一&#xff0c;这里将详细讲解着色器和GLSL。 在工作原理中我们提到&#xff0c;WebGL每次绘制需要两个着色器&#xff0c; 一个顶点着色器和一个片段着色器&…...

    vscode debug node + 前端

    方法 2&#xff1a;调试全栈&#xff08;Node 前端&#xff09; 如果需同时调试后端和前端&#xff1a; 分别启动两个调试会话 一个配置调试 Node.js 后端&#xff08;server.js&#xff09;。 另一个配置调试浏览器前端&#xff08;如上&#xff09;。 {// Use IntelliS…...

    Python训练营打卡 Day27

    函数专题2&#xff1a;装饰器 知识点回顾&#xff1a; 装饰器的思想&#xff1a;进一步复用函数的装饰器写法注意内部函数的返回值 昨天我们接触到了函数大部分的功能&#xff0c;然后在你日常ctrl点进某个复杂的项目&#xff0c;发现函数上方有一个xxx,它就是装饰器 装饰器本质…...

    华为OD机试真题——通信系统策略调度(用户调度问题)(2025B卷:100分)Java/python/JavaScript/C/C++/GO最佳实现

    2025 B卷 100分 题型 本专栏内全部题目均提供Java、python、JavaScript、C、C++、GO六种语言的最佳实现方式; 并且每种语言均涵盖详细的问题分析、解题思路、代码实现、代码详解、3个测试用例以及综合分析; 本文收录于专栏:《2025华为OD真题目录+全流程解析+备考攻略+经验分…...

    SQL实战:06交叉日期打折问题求解

    文章目录 概述题目&#xff1a;交叉打折问题求解题解第一步&#xff1a;使用滑动窗口统计当前活动前的最大结束日期步骤二&#xff1a;拆分出交叉部分步骤三&#xff1a;计算每次活动的持续天数步骤四&#xff1a;分组统计最终结果完整SQL 概述 最近刷题时遇到一些比较有意思的…...

    升级kafka4.0.0,无ZK版本

    设备规划&#xff1a; 172.20.192.47 kafka-0 172.20.192.48 kafka-1 172.20.192.49 kafka-2 单机块7TB Nvme磁盘一共9块 # 格式化成GPT分区 sudo parted /dev/nvme0n1 --script mklabel gpt sudo parted /dev/nvme1n1 --script mklabel gpt sudo parted /dev/nvme2n1 --s…...

    llamafactory SFT 从断点恢复训练

    背景 我使用llamafactory sft 微调模型的时候。gpu停止运行了。日志文件没有任何的报错信息。 显存还是占用状态。 查看llamafactory的进程是下述信息&#xff1a; 151312 151306 91 17:42 ? 03:58:10 [llamafactory-cl] 既然如此&#xff0c;那就只能从断点恢复训练了。 …...

    PCL 计算一条射线与二次曲面的交点

    文章目录 一、简介二、实现代码三、实现效果一、简介 对于二次曲面而言,其一般方程可以写为: z = a 0 + a 1 x + a 2 y + a...

    计算机网络-----6分层结构

    目录 “分层” 的设计思想&#xff1a; 计算机网络要完成的功能&#xff1a; 计算机网络的分层结构&#xff1a; 网络体系结构的概念&#xff1a; 各层之间的关系&#xff1a; 数据的传输过程 水平视角&#xff1a; 垂直视角&#xff1a; 相关概念 协议三要素&#x…...

    运算放大器相关的电路

    1运算放大器介绍 解释&#xff1a;运算放大器本质就是一个放大倍数很大的元件&#xff0c;就如上图公式所示 Vp和Vn相差很小但是放大后输出还是会很大。 运算放大器不止上面的三个引脚&#xff0c;他需要独立供电&#xff1b; 如图比较器&#xff1a; 解释&#xff1a;Vp&…...

    BM25 算法与关键词提取在向量数据库中的实践优化

    BM25 算法与关键词提取在向量数据库中的实践优化 在实际构建问答系统或语义检索场景中&#xff0c;向量数据库&#xff08;如 Weaviate&#xff09;提供了基于语义匹配的检索能力&#xff0c;然而我们发现 BM25 关键词检索效果不理想&#xff0c;甚至出现了召回率过低、查询必…...

    python版本管理工具-pyenv轻松切换多个Python版本

    在使用python环境开发时&#xff0c;相信肯定被使用版本所烦恼&#xff0c;在用第三方库时依赖兼容的python版本不一样&#xff0c;有没有一个能同时安装多个python并能自由切换的工具呢&#xff0c;那就是pyenv&#xff0c;让你可以轻松切换多个Python 版本。 pyenv是什么 p…...

    Elasticsearch索引全生命周期管理指南之一

    #作者&#xff1a;猎人 文章目录 一、索引常规操作二、索引mapping和别名管理 一、索引常规操作 索引数据特点&#xff1a; 索引中的数据随着时间&#xff0c;持续不断增长 按照时间序列划分索引的好处&挑战&#xff1a; 按照时间进行划分索引&#xff0c;会使得管理更加…...

    STM32F407VET6的HAL库使用CRC校验的思路

    CRC校验在数据传输快&#xff0c;且量大的时候使用。 步骤实现&#xff1a; CubeMX配置 c // 在CubeMX中启用CRC模块 // AHB总线时钟自动启用 HAL库代码 c // 初始化&#xff08;main函数中&#xff09; CRC_HandleTypeDef hcrc; hcrc.Instance CRC; hcrc.Init.Default…...

    【Manim】使用manim画一个高斯分布的动画

    1 Manim例子一 最近接触到manim&#xff0c;觉得挺有趣的&#xff0c;来玩一玩把。如下是一个使用manim画的高斯分布的动画。 from manim import * import numpy as npclass GaussianDistribution(Scene):def construct(self):# 创建坐标系axes Axes(x_range[-4, 4, 1],y_ra…...

    elementUI 循环出来的表单,怎么做表单校验?

    数据结构如下&#xff1a; diversionParamList: [ { length: null, positionNumber: null, value: null, } ] 思路&#xff1a;可根据 index 动态绑定 :props 属性值&#xff0c;校验规则写在:rules <div class"config-item" v-for"(item, index) in form.…...

    Leetcode76覆盖最小子串

    覆盖最小子串 代码来自b站左程云 class Solution {public String minWindow(String str, String tar) {char[] s str.toCharArray();char[] t tar.toCharArray();int[] cnt new int[256];for (char cha : t) { cnt[cha]--;}int len Integer.MAX_VALUE;int debt t.length…...

    电力杆塔安全监测解决方案

    一、方案背景 在台风、滑坡等自然灾害出现时&#xff0c;极易产生倒杆、断杆、杆塔倾斜、塔基滑动等致使杆塔失稳的状况&#xff0c;进而引发导线断线、线路跳闸等事故&#xff0c;给电网的安全稳定运行造成影响。可借助在铁塔上装设的传感器&#xff0c;能够感知铁塔的工作状态…...

    AD 常用系统快捷键

    (1) L: 打开层设置开关选项(在元件移动状态下&#xff0c;按下“L”键换层) (2) S: 打开选择&#xff0c;如SL(线选)、SI(框选)、SE(滑动选择) (3) J: 跳转&#xff0c;如JC(跳转到元件)、JN(跳转到网络) (4) CtrlQ: 英寸和毫米相互切换。 (5) Delete: 删除已被选择的对象 E…...

    今日行情明日机会——20250516

    上证缩量收阴线&#xff0c;小盘股表现相对更好&#xff0c;上涨的个股大于下跌的&#xff0c;日线已到前期压力位附近&#xff0c;注意风险。 深证缩量收假阳线&#xff0c;临近日线周期上涨末端&#xff0c;注意风险。 2025年5月16日涨停股行业方向分析 机器人概念&#x…...

    AlphaEvolve:LLM驱动的算法进化革命与科学发现新范式

    AlphaEvolve&#xff1a;LLM驱动的算法进化革命与科学发现新范式 本文聚焦Google DeepMind最新发布的AlphaEvolve&#xff0c;探讨其如何通过LLM与进化算法的结合&#xff0c;在数学难题突破、计算基础设施优化等领域实现革命性进展。从48次乘法优化44矩阵相乘到数据中心资源利…...

    多尺度对比度调整

    一、背景介绍 受到了前面锐化算法实现的启发&#xff0c;对高频层做增强是锐化&#xff0c;那么对中低频一起做增强&#xff0c;就应该能有局域对比度增强效果。 直接暴力实现了个基本版本&#xff0c;确实有对比度增强效果。然后搜了下关键字&#xff0c;还真找到了已经有人这…...

    解决IDEA Maven编译时@spring.profiles.active@没有替换成具体环境变量的问题

    如果不加filtering true&#xff0c;编译后的文件还是 spring.profiles.active 编译前的application.yml 编译后的application.yml【环境变量没有改变】 解决方案 找到 SpringBoot 启动类所在的pom.xml&#xff0c;在 resources 增加 filtering true&#xff0c;然后重新…...

    博客系统技术需求文档(基于 Flask)

    以下内容是AI基于要求生成的技术文档&#xff0c;仅供参考~ &#x1f9f1; 一、系统架构设计概览 层级 内容 前端层 HTML Jinja2 模板引擎&#xff0c;集成 Markdown 编辑器、代码高亮 后端层 Flask 框架&#xff0c;RESTful 风格&#xff0c;Jinja2 渲染 数据库 SQLi…...

    记参加一次数学建模

    题目请到全国大学生数学建模竞赛下载查看。 注&#xff1a;过程更新了很多文件&#xff0c;所有这里贴上的有些内容不是最新的&#xff08;而是草稿&#xff09;。 注&#xff1a;我们队伍并没有获奖&#xff0c;文章内容仅供一乐。 从这次比赛&#xff0c;给出以下赛前建议 …...

    TC8:SOMEIP_ETS_029-030

    SOMEIP_ETS_029: echoUINT8Array16Bitlength 目的 检查当method echoUINT8Array16BitLength的参数中长度字段为16bit时,SOME/IP协议层是否能对参数进行序列化和反序列化。 对于可变长度的数组而言,必须用长度字段表示数组长度。否则接收方无法判断有效数据。 SOMEIP_ETS_02…...

    PYTHON训练营DAY27

    装饰器 编写一个装饰器 logger&#xff0c;在函数执行前后打印日志信息&#xff08;如函数名、参数、返回值&#xff09; logger def multiply(a, b):return a * bmultiply(2, 3) # 输出: # 开始执行函数 multiply&#xff0c;参数: (2, 3), {} # 函数 multiply 执行完毕&a…...

    Maven使用详解:Maven的概述(二)

    一、核心定义与功能 Maven是由Apache软件基金会开发的开源项目管理工具&#xff0c;专为Java项目设计&#xff0c;主要用于自动化构建、依赖管理和项目标准化。其核心功能包括&#xff1a; 依赖管理&#xff1a;通过pom.xml文件声明依赖库&#xff0c;自动从中央仓库下载并管…...

    printspoofer的RPC调用接口的简单代码

    &#x1f9e0; 问题背景&#xff1a;为什么不能“啥都不导库”就直接调用 RPC 接口&#xff1f; 因为&#xff1a; 你想调用的是 RPC 接口函数&#xff0c;比如 RpcRemoteFindFirstPrinterChangeNotificationEx&#xff1b; 它不是像 MessageBox() 那样的普通 API&#xff0c…...

    刻录光盘--和炸铁路,tarjan

    https://www.luogu.com.cn/problem/P2835 多做多看多想&#xff0c;一切都会水到渠成 受欢迎的牛--tarjan缩点图论出度-CSDN博客 #include<bits/stdc.h> using namespace std; #define N 100011 typedef long long ll; typedef pair<ll,int> pii; int n,m; ve…...