使用 Three.js 实现流光特效
大家好!我是 [数擎AI],一位热爱探索新技术的前端开发者,在这里分享前端和 Web3D、AI 技术的干货与实战经验。如果你对技术有热情,欢迎关注我的文章,我们一起成长、进步!
开发领域:前端开发 | AI 应用 | Web3D | 元宇宙
技术栈:JavaScript、React、ThreeJs、WebGL、Go
经验经验:6 年+ 前端开发经验,专注于图形渲染和 AI 技术
开源项目:AI简历、元宇宙、数字孪生
源码地址: https://github.com/dezhizhang/shadertoy
演示地址: https://shader.shuqin.cc/xx3fdh
在本文中,我们将深入探讨如何使用 Three.js 和 GLSL(OpenGL Shading Language)编写一个火焰效果的着色器。通过这个教程,你将学习如何创建动态的火焰效果,以及如何将它应用到 3D 渲染中。
着色器简介
着色器是图形渲染管线中的一个重要组成部分,负责处理图形渲染过程中每个像素的颜色计算。通常,着色器分为两个主要部分:
- 顶点着色器(Vertex Shader):用于处理每个顶点的位置和属性。
- 片段着色器(Fragment Shader):用于计算每个像素的颜色和纹理。
在这个示例中,我们将重点关注如何编写片段着色器来模拟火焰的视觉效果。
火焰着色器的结构
我们的火焰着色器由以下几个部分组成:
- Uniforms:这部分包含了着色器所需的外部变量,如时间、分辨率等。
- 顶点着色器:负责传递 UV 坐标给片段着色器。
- 片段着色器:执行火焰效果的核心计算,包括噪声生成、分形布朗运动(FBM)等。
以下是整个着色器的代码实现:
const flameShader = {uniforms: {time: { value: 0 },resolution: { value: new THREE.Vector2() }},vertexShader: `varying vec2 vUv;void main() {vUv = uv;gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);}`,fragmentShader: `precision highp float;#define NUM_OCTAVES 5varying vec2 vUv;uniform float time;uniform vec2 resolution;// 生成随机数float rand(vec2 n) {return fract(sin(dot(n, vec2(12.9898, 4.1414))) * 43758.5453);}// 生成噪声float noise(vec2 p) {vec2 ip = floor(p);vec2 u = fract(p);u = u * u * (3.0 - 2.0 * u);float res = mix(mix(rand(ip), rand(ip + vec2(1.0, 0.0)), u.x),mix(rand(ip + vec2(0.0, 1.0)), rand(ip + vec2(1.0, 1.0)), u.x),u.y);return res * res;}// 分形布朗运动float fbm(vec2 x) {float v = 0.0;float a = 0.5;vec2 shift = vec2(100);mat2 rot = mat2(cos(0.5), sin(0.5), -sin(0.5), cos(0.5));for (int i = 0; i < NUM_OCTAVES; ++i) {v += a * noise(x);x = rot * x * 2.0 + shift;a *= 0.5;}return v;}void main() {vec2 shake = vec2(sin(time * 1.5) * 0.01, cos(time * 2.7) * 0.01);vec2 fragCoord = vUv * resolution;vec2 p = ((fragCoord + shake * resolution) - resolution * 0.5) / resolution.y;p *= mat2(8.0, -6.0, 6.0, 8.0);vec2 v;vec4 o = vec4(0.0);float f = 3.0 + fbm(p + vec2(time * 7.0, 0.0));for (float i = 0.0; i < 50.0; i++) {v = p + cos(i * i + (time + p.x * 0.1) * 0.03 + i * vec2(11.0, 9.0)) * 5.0+ vec2(sin(time * 4.0 + i) * 0.005, cos(time * 4.5 - i) * 0.005);float tailNoise = fbm(v + vec2(time, i)) * (1.0 - (i / 50.0));vec4 currentContribution = (cos(sin(i) * vec4(1.0, 2.0, 3.0, 1.0)) + 1.0)* exp(sin(i * i + time)) / length(max(v, vec2(v.x * f * 0.02, v.y)));float thinnessFactor = smoothstep(0.0, 1.0, i / 50.0);o += currentContribution * (1.0 + tailNoise * 2.0) * thinnessFactor;}o = tanh(pow(o / 1e2, vec4(1.5)));gl_FragColor = o;}`
};
着色器解析
1. 顶点着色器
顶点着色器的任务非常简单,它将 UV 坐标传递给片段着色器,并根据模型视图矩阵和投影矩阵计算每个顶点的位置。
void main() {vUv = uv;gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
2. 片段着色器
随机数生成与噪声:我们通过 rand 函数生成一个伪随机数,结合 noise 函数生成了基础的噪声,用于创建火焰的动态效果。
分形布朗运动(FBM):使用多个频率和振幅的噪声叠加,生成复杂的纹理和动态效果,这使得火焰的效果更加自然。
动态效果:通过 time 控制火焰的变化,使用不同的参数让火焰不断变化,模拟出自然的火焰流动。
3. 渲染火焰效果
通过循环并叠加每一层的噪声和贡献,我们可以模拟火焰的扩散和衰退。使用 exp 和 tanh 函数对输出进行平滑处理,使得最终的火焰效果看起来更加柔和自然。
如何使用该着色器
-
创建一个材质: 使用 THREE.ShaderMaterial 创建一个自定义材质,将上述着色器代码传递给它。
-
设置 time 和 resolution: time 是一个动态变化的值,用来驱动火焰的动画效果。resolution 则表示画布的尺寸,影响渲染的比例。
-
应用到对象上: 创建一个平面或其他几何体,并将自定义的火焰材质应用到该几何体上。
const material = new THREE.ShaderMaterial({uniforms: flameShader.uniforms,vertexShader: flameShader.vertexShader,fragmentShader: flameShader.fragmentShader
});
完整代码
import * as THREE from 'three';// 使用示例
const camera = new THREE.OrthographicCamera(-1, 1, 1, -1, 0, 1);
const scene = new THREE.Scene();const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth,window.innerHeight);
renderer.setPixelRatio(window.devicePixelRatio);document.body.appendChild(renderer.domElement);const flameShader = {uniforms: {time: { value: 0 },resolution: { value: new THREE.Vector2() }},vertexShader: `varying vec2 vUv;void main() {vUv = uv;gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);}`,fragmentShader: `precision highp float;#define NUM_OCTAVES 5varying vec2 vUv;uniform float time;uniform vec2 resolution;float rand(vec2 n) { return fract(sin(dot(n, vec2(12.9898, 4.1414))) * 43758.5453);}float noise(vec2 p) {vec2 ip = floor(p);vec2 u = fract(p);u = u*u*(3.0-2.0*u);float res = mix(mix(rand(ip), rand(ip+vec2(1.0,0.0)), u.x),mix(rand(ip+vec2(0.0,1.0)), rand(ip+vec2(1.0,1.0)), u.x), u.y);return res*res;}float fbm(vec2 x) {float v = 0.0;float a = 0.5;vec2 shift = vec2(100);mat2 rot = mat2(cos(0.5), sin(0.5), -sin(0.5), cos(0.50));for (int i = 0; i < NUM_OCTAVES; ++i) {v += a * noise(x);x = rot * x * 2.0 + shift;a *= 0.5;}return v;}void main() {vec2 shake = vec2(sin(time * 1.5) * 0.01, cos(time * 2.7) * 0.01);vec2 fragCoord = vUv * resolution;vec2 p = ((fragCoord + shake * resolution) - resolution * 0.5) / resolution.y;p *= mat2(8.0, -6.0, 6.0, 8.0);vec2 v;vec4 o = vec4(0.0);float f = 3.0 + fbm(p + vec2(time * 7.0, 0.0));for(float i = 0.0; i < 50.0; i++) {v = p + cos(i*i + (time + p.x*0.1)*0.03 + i*vec2(11.0,9.0)) *5.0 + vec2(sin(time*4.0 + i)*0.005, cos(time*4.5 - i)*0.005);float tailNoise = fbm(v + vec2(time, i)) * (1.0 - (i/50.0));vec4 currentContribution = (cos(sin(i)*vec4(1.0,2.0,3.0,1.0)) +1.0) * exp(sin(i*i + time)) / length(max(v, vec2(v.x*f*0.02, v.y)));float thinnessFactor = smoothstep(0.0, 1.0, i/50.0);o += currentContribution * (1.0 + tailNoise*2.0) * thinnessFactor;}o = tanh(pow(o/1e2, vec4(1.5)));gl_FragColor = o;}`
};const mesh = new THREE.Mesh(new THREE.PlaneGeometry(2, 2),new THREE.ShaderMaterial({...flameShader,blending: THREE.AdditiveBlending,transparent: true})
);scene.add(mesh);function animate() {mesh.material.uniforms.time.value = performance.now() / 1000;mesh.material.uniforms.resolution.value.set(window.innerWidth, window.innerHeight);requestAnimationFrame(animate);renderer.render(scene, camera);
}animate();
总结
通过本文的介绍,你可以了解如何使用 Three.js 和 GLSL 创建一个动态的火焰效果。这个效果是基于噪声和分形布朗运动的,模拟了自然界火焰的动态变化。你可以根据自己的需要调整参数,进一步优化火焰效果。
如果你也对shader和AI感兴趣,欢迎关注我们公众号数擎Ai
相关文章:
使用 Three.js 实现流光特效
大家好!我是 [数擎AI],一位热爱探索新技术的前端开发者,在这里分享前端和 Web3D、AI 技术的干货与实战经验。如果你对技术有热情,欢迎关注我的文章,我们一起成长、进步! 开发领域:前端开发 | AI…...
Error [ERR_REQUIRE_ESM]: require() of ES Module
报错信息: 【报错】Message.js 导入方式不对,用的是 ES Moudle 的语法,提示使用 import 引入文件 项目开发没有用到 js-message 依赖,是 node-ipc 依赖中用到的 js-message 依赖, node-ipc 中限制 js-message 版本&a…...
沉浸式翻译插件深度评测:打破语言壁垒的黑科技利器
在信息爆炸的时代,语言障碍成为了许多人获取信息的一大难题。尤其是在浏览外文网站、观看外语视频或阅读外文文档时,语言不通往往会让人倍感困扰。然而,一款名为沉浸式翻译的黑科技插件,却以其强大的翻译能力和便捷的使用体验,成为了众多用户打破语言壁垒的首选工具。本文…...
Java 中 HTTP 协议版本使用情况剖析
Java 中 HTTP 协议版本使用情况剖析 一、HTTP/1.1 与 HTTP/2 概述 (一)HTTP/1.1 HTTP/1.1 是广泛应用且成熟的 HTTP 协议版本,它在互联网发展历程中扮演了重要角色。其特点主要包括: 连接方式:默认采用短连接,即每次请求都要建立新的 TCP 连接,请求完成后断开。不过也…...
蓝桥杯学习大纲
(致酷德与热爱算法、编程的小伙伴们) 在查阅了相当多的资料后,发现没有那篇博客、文章很符合我们备战蓝桥杯的学习路径。所以,干脆自己整理一篇,欢迎大家补充! 一、题型分布: 题型分布为填空…...
VSCode ssh远程连接内网服务器(不能上网的内网环境的Linux服务器)的终极解决方案
VSCode ssh远程连接内网服务器(不能上网的内网环境的Linux服务器) 离线下载vscode-server并安装: 如果远程端不能联网可以下载包离线安装,下载 vscode-server 的 url 需要和 vscode 客户端版本的 commit-id 对应.通过 vscode 面板的帮助->关于可以获…...
【多模态处理篇五】【DeepSeek文档解析:PDF/Word智能处理引擎】
你知道吗?全球每天产生的PDF文档超过10亿份,但90%的上班族还在用复制粘贴的笨办法处理文档!DeepSeek文档解析引擎就像给你的电脑装上了"文档翻译官",能把PDF/Word里的文字、表格、公式甚至排版样式都变成AI能理解的"语言"。举个真实场景:法务小姐姐用…...
STM32-心知天气项目
一、项目需求 使用 ESP8266 通过 HTTP 获取天气数据(心知天气),并显示在 OLED 屏幕上。 按键 1 :循环切换今天 / 明天 / 后天天气数据; 按键 2 :更新天气。 二、项目框图 三、cjson作用 https://gi…...
cs106x-lecture14(Autumn 2017)-SPL实现
打卡cs106x(Autumn 2017)-lecture14 (以下皆使用SPL实现,非STL库,后续课程结束会使用STL实现) 1、min Write a function named min that accepts a pointer to a ListNode representing the front of a linked list. Your function should return the …...
基于STM32的智能家居语音系统(单片机毕设)
前言 源代码下载链接: https://download.csdn.net/download/m0_74712453/90071680 需要实物的可以私信博主或者在文章最下方添加好友。 目录 一、项目介绍和演示视频 二、硬件实现 1. 材料材料 2. 原理图和PCB 三、软件实现 1. 代码解析 1.1 main函数 1.2…...
ASP.NET Core 简单文件上传
使用异步 JavaScript 和 XML(AJAX)进行简单的文件上传;用 C# 编写的服务器端代码。 使用AJAX和ASP.NET Core MVC上传文件再简单不过了。这不依赖于jQuery。此代码允许上传多个文件,并与 .NET Core 3.1、.NET 6和.NET 8兼容。 如果…...
2502C++,C++继承的多态性
构 A{单 向量<串>记;元<类 T>静 空 ff(串&a){清理(记);名向量(a,记);串 b{"---ff---"};打印(b);T::g();} };构 B:公 A{元<类 T>静 空 f(){串 a{"错误.txt"};ff<T>(a);} };构 C:公 A{元<类 T>静 空 f(){串 a{"a12.c…...
【机器学习】13.十大算法之一K均值算法(K-means)聚类详细讲解
【机器学习】13.十大算法之一K均值算法(K-means)聚类详细讲解 一摘要二个人简介三K-均值聚类(K-means)3.1-K均值算法的基本原理3.1.1- 聚类分析的目标3.1.2- K - means算法算法原理 四K-means聚类算法的收敛性五证明K均值算法的收…...
Spring扩展点之Mybatis整合模拟
Spring扩展点之Mybatis整合 单独使用MyBaitis模拟整合MyBatis到Spring 单独使用MyBaitis 通过配置文件生成sqlSessionFactory,用sqlSessionFactory开启session。通过session获取到mapper执行对应的sql。 InputStream inputStream Resources.getResourceAsStream(…...
.NET MVC实现电影票管理
.NET MVC(Model-View-Controller)是微软推出的基于 Model-View-Controller 设计模式的 Web 应用框架,属于 ASP.NET Core 的重要组成部分。其核心目标是通过清晰的分层架构实现 高内聚、低耦合 的开发模式,适用于构建可扩展的企业级…...
自媒体账号管理工具:创作罐头使用指南
创作罐头使用指南 1. 关于创作罐头 创作罐头是免费的一站式自媒体运营工具,支持各大自媒体平台多账号管理、全网爆文库、原创检测、视频一键分发、团队管理、各平台数据分析等功能。 2. 安装与注册 2.1. 如何安装创作罐头 从我们的官网下载并安装软件 www.czgts.…...
基于数据可视化+SpringBoot+安卓端的数字化OA公司管理平台设计和实现
博主介绍:硕士研究生,专注于信息化技术领域开发与管理,会使用java、标准c/c等开发语言,以及毕业项目实战✌ 从事基于java BS架构、CS架构、c/c 编程工作近16年,拥有近12年的管理工作经验,拥有较丰富的技术架…...
VSCode离线安装插件
最近在其他电脑设备上部署vscode环境出现问题,在vscode里直接安装插件失败,软件提示如下:(此前已经用此方法安装过中文插件) 这里我们选择手动下载,会自动在浏览器中跳转到该插件的下载链接并自动下载插件&…...
基于Hadoop的汽车大数据分析系统设计与实现【爬虫、数据预处理、MapReduce、echarts、Flask】
文章目录 有需要本项目的代码或文档以及全部资源,或者部署调试可以私信博主 项目介绍爬虫数据概览HIve表设计Cars Database Tables 1. cars_data2. annual_sales_volume3. brand_sales_volume4. city_sales_volume5. sales_volume_by_year_and_brand6. sales_distri…...
SHELL32!Shell_MergeMenus函数分析
SHELL32!Shell_MergeMenus函数分析 UINT Shell_MergeMenus( [in] HMENU hmDst, [in] HMENU hmSrc, UINT uInsert, UINT uIDAdjust, UINT uIDAdjustMax, ULONG uFlags ); 参数 [in] hmDst 类型: HMENU 要向其添加 hmSrc…...
进程地址空间(比特课总结)
一、进程地址空间 1. 环境变量 1 )⽤户级环境变量与系统级环境变量 全局属性:环境变量具有全局属性,会被⼦进程继承。例如当bash启动⼦进程时,环 境变量会⾃动传递给⼦进程。 本地变量限制:本地变量只在当前进程(ba…...
DeepSeek 赋能智慧能源:微电网优化调度的智能革新路径
目录 一、智慧能源微电网优化调度概述1.1 智慧能源微电网概念1.2 优化调度的重要性1.3 目前面临的挑战 二、DeepSeek 技术探秘2.1 DeepSeek 技术原理2.2 DeepSeek 独特优势2.3 DeepSeek 在 AI 领域地位 三、DeepSeek 在微电网优化调度中的应用剖析3.1 数据处理与分析3.2 预测与…...
shell脚本--常见案例
1、自动备份文件或目录 2、批量重命名文件 3、查找并删除指定名称的文件: 4、批量删除文件 5、查找并替换文件内容 6、批量创建文件 7、创建文件夹并移动文件 8、在文件夹中查找文件...
生成 Git SSH 证书
🔑 1. 生成 SSH 密钥对 在终端(Windows 使用 Git Bash,Mac/Linux 使用 Terminal)执行命令: ssh-keygen -t rsa -b 4096 -C "your_emailexample.com" 参数说明: -t rsa&#x…...
从零开始打造 OpenSTLinux 6.6 Yocto 系统(基于STM32CubeMX)(九)
设备树移植 和uboot设备树修改的内容同步到kernel将设备树stm32mp157d-stm32mp157daa1-mx.dts复制到内核源码目录下 源码修改及编译 修改arch/arm/boot/dts/st/Makefile,新增设备树编译 stm32mp157f-ev1-m4-examples.dtb \stm32mp157d-stm32mp157daa1-mx.dtb修改…...
【Oracle】分区表
个人主页:Guiat 归属专栏:Oracle 文章目录 1. 分区表基础概述1.1 分区表的概念与优势1.2 分区类型概览1.3 分区表的工作原理 2. 范围分区 (RANGE Partitioning)2.1 基础范围分区2.1.1 按日期范围分区2.1.2 按数值范围分区 2.2 间隔分区 (INTERVAL Partit…...
Element Plus 表单(el-form)中关于正整数输入的校验规则
目录 1 单个正整数输入1.1 模板1.2 校验规则 2 两个正整数输入(联动)2.1 模板2.2 校验规则2.3 CSS 1 单个正整数输入 1.1 模板 <el-formref"formRef":model"formData":rules"formRules"label-width"150px"…...
Springboot社区养老保险系统小程序
一、前言 随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱,社区养老保险系统小程序被用户普遍使用,为方…...
回溯算法学习
一、电话号码的字母组合 import java.util.ArrayList; import java.util.List;import javax.management.loading.PrivateClassLoader;public class letterCombinations {private static final String[] KEYPAD {"", //0"", //1"abc", //2"…...
【Linux】Linux 系统默认的目录及作用说明
博主介绍:✌全网粉丝23W,CSDN博客专家、Java领域优质创作者,掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域✌ 技术范围:SpringBoot、SpringCloud、Vue、SSM、HTML、Nodejs、Python、MySQL、PostgreSQL、大数据、物…...
