使用 Three.js 转换 GLSL 粒子效果着色器

news/2025/3/2 0:25:20/

大家好!我是 [数擎AI],一位热爱探索新技术的前端开发者,在这里分享前端和 Web3D、AI 技术的干货与实战经验。如果你对技术有热情,欢迎关注我的文章,我们一起成长、进步!
开发领域:前端开发 | AI 应用 | Web3D | 元宇宙
技术栈:JavaScript、React、ThreeJs、WebGL、Go
经验经验:6 年+ 前端开发经验,专注于图形渲染和 AI 技术
开源项目:AI简历、元宇宙、数字孪生

在这篇博客中,我们将探讨如何将一个经典的 GLSL 粒子效果着色器转换成 Three.js 可用的自定义着色器,并通过交互控制其行为。这将是一个逐步教程,帮助你理解如何在 Three.js 中应用自定义 GLSL 代码并通过鼠标交互调整效果。

目标

我们将使用 Three.js 渲染一个基于粒子的视觉效果,类似于一个动态生成的渐变色圆环,随着时间的推移,颜色和形状会发生变化。用户还可以通过鼠标移动来控制缩放和动画持续时间。

步骤一:准备工作

首先,你需要确保你的项目中包含了 Three.js。如果你还没有安装 Three.js,可以通过 npm 安装:

npm install three

如果你使用的是纯 HTML 文件,也可以直接在 HTML 中引入 Three.js:

<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>

步骤二:GLSL 粒子效果着色器代码解析

原始的 GLSL 代码创建了一个基于时间变化的粒子系统,颜色从绿色到蓝色渐变,并且粒子的大小和分布随时间变化。核心的功能包括:

  • 粒子数量(n):控制生成的粒子数量。
  • 起始和结束颜色(startColor 和 endColor):粒子颜色的渐变。
  • 粒子半径变化:随着粒子距离中心的变化,粒子的半径逐渐增大。
  • 交互性:鼠标控制缩放和动画的持续时间。

步骤三:在 Three.js 中实现 GLSL 着色器

接下来,我们将创建一个简单的 Three.js 场景,并将这个 GLSL 着色器嵌入其中。

完整代码实现

javascript">
import * as THREE from 'three';const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);// Shader code
const vertexShader = `void main() {gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);}
`;const fragmentShader = `uniform float iTime;uniform vec3 iResolution;uniform vec3 iMouse;void mainImage( out vec4 fragColor, in vec2 fragCoord ) {float t = iTime+5.0;float z = 6.0;const int n = 100; // particle countvec3 startColor = vec3(0.0, 0.64, 0.2);vec3 endColor = vec3(0.06, 0.35, 0.85);float startRadius = 0.84;float endRadius = 1.6;float power = 0.51;float duration = 4.0;vec2 s = iResolution.xy;vec2 v = z * (2.0 * fragCoord.xy - s) / s.y;// Mouse axis y => zoomif(iMouse.z > 0.0) v *= iMouse.y / s.y * 20.0;// Mouse axis x => durationif(iMouse.z > 0.0) duration = iMouse.x / s.x * 10.0;vec3 col = vec3(0.0);vec2 pm = v.yx * 2.8;float dMax = duration;float evo = (sin(iTime * 0.01 + 400.0) * 0.5 + 0.5) * 99.0 + 1.0;float mb = 0.0;float mbRadius = 0.0;float sum = 0.0;for(int i = 0; i < n; i++) {float d = fract(t * power + 48934.4238 * sin(float(i / int(evo)) * 692.7398));float tt = 0.0;float a = 6.28 * float(i) / float(n);float x = d * cos(a) * duration;float y = d * sin(a) * duration;float distRatio = d / dMax;mbRadius = mix(startRadius, endRadius, distRatio);vec2 p = v - vec2(x, y);mb = mbRadius / dot(p, p);sum += mb;col = mix(col, mix(startColor, endColor, distRatio), mb / sum);}sum /= float(n);col = normalize(col) * sum;sum = clamp(sum, 0.0, 0.4);vec3 tex = vec3(1.0);col *= smoothstep(tex, vec3(0.0), vec3(sum));fragColor.rgb = col;}void main() {vec2 fragCoord = gl_FragCoord.xy;mainImage(gl_FragColor, fragCoord);}
`;const uniforms = {iTime: { value: 0.0 },iResolution: { value: new THREE.Vector3(window.innerWidth, window.innerHeight, 1) },iMouse: { value: new THREE.Vector3(0, 0, 0) }
};const material = new THREE.ShaderMaterial({vertexShader: vertexShader,fragmentShader: fragmentShader,uniforms: uniforms
});const geometry = new THREE.PlaneGeometry(2, 2);
const mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);// Set camera position
camera.position.z = 5;function animate() {requestAnimationFrame(animate);uniforms.iTime.value += 0.05; window.addEventListener('mousemove', (event) => {uniforms.iMouse.value.x = event.clientX;uniforms.iMouse.value.y = window.innerHeight - event.clientY; uniforms.iMouse.value.z = 1; });renderer.render(scene, camera);
}animate();

步骤四:代码解析

  • ShaderMaterial 创建:我们通过 THREE.ShaderMaterial 来定义自定义的着色器,并将 GLSL 代码传入其中。通过 uniforms 对象传递外部变量(如时间、分辨率、鼠标位置)到着色器中。
  • 顶点着色器:这是一个简单的顶点着色器,它将每个顶点的坐标从模型空间转换到裁剪空间。
  • 片段着色器:在片段着色器中,我们实现了粒子效果的核心逻辑,包括动态计算粒子颜色、大小以及它们的分布。我们使用 sin 函数和一些数学操作来实现粒子效果的变化。
  • 鼠标交互:通过 mousemove 事件监听器,我们捕捉到鼠标的 X 和 Y 位置,并传递给着色器。鼠标的 Y 轴控制图形的缩放,而 X 轴控制动画的持续时间。
  • 动画循环:使用 requestAnimationFrame 来实现平滑的动画效果,定期更新时间和鼠标状态,并重新渲染场景。

步骤五:优化与扩展

在实际开发中,你可以根据需要对该代码进行优化和扩展。以下是一些常见的改进方式:

  • 性能优化:增加粒子数量时可能会导致性能下降,可以通过减少 n 或优化粒子计算逻辑来改善性能。
  • 扩展交互性:除了鼠标交互,你还可以加入键盘控制、触摸事件等方式,使用户体验更加丰富。
  • 增加更多粒子效果:可以通过修改着色器中的数学公式,增加更多动态的粒子效果,如旋转、形状变化等。

总结

通过本教程,你学会了如何将一个 GLSL 粒子效果着色器转化为 Three.js 中的自定义着色器,并通过鼠标交互来控制图形的缩放和动画时间。这种方法让你可以在 Web 上实现复杂的视觉效果,具有高度的自定义性和灵活性。


http://www.ppmy.cn/news/1575907.html

相关文章

自动化办公|xlwings与pandas交互

1. 介绍 在数据分析和 Excel 自动化中&#xff0c;pandas 作为 Python 处理数据的强大库&#xff0c;而 xlwings 则可以高效操作 Excel。将 pandas 与 xlwings 结合使用&#xff0c;可以实现从 Excel 读取数据到 DataFrame、将 DataFrame 写入 Excel 以及 Excel 的自动化处理。…

Pycharm使用matplotlib出现的问题(1、不能弹出图表 2、图表标题中文不显示)

Pycharm使用matplotlib出现的问题 问题1&#xff1a;Pycharm调试时出现&#xff1a;AttributeError: module backend_interagg has no attribute FigureCanvas. Did you mean: FigureCanvasAgg? 排查原因&#xff1a;可能是由于matplotlib后端设置不正确或与运行环境不兼容引…

图数据库Neo4j面试内容整理-图遍历和最短路径

图遍历 和 最短路径 是图数据库中两个非常重要的概念,尤其是在图数据结构中,它们是解决许多问题(如社交网络分析、推荐系统、网络分析等)的核心算法。Neo4j 提供了强大的图遍历和最短路径查询能力,帮助用户有效地从图中提取信息。 1. 图遍历(Graph Traversal)

Java进阶:Zookeeper相关笔记

概要总结&#xff1a; ●Zookeeper是一个开源的分布式协调服务&#xff0c;需要下载并部署在服务器上(使用cmd启动&#xff0c;windows与linux都可用)。 ●zookeeper一般用来实现诸如数据订阅/发布、负载均衡、命名服务、集群管理、分布式锁和分布式队列等功能。 ●有多台服…

​PDF 工具箱 软件无需安装绿色版

​PDF 工具箱 嘿&#xff0c;朋友们&#xff01;今天给大家介绍一款超棒的工具——PDF工具箱。这款神奇的小工具是由吾爱利用GPT精心打造的&#xff0c;简直就是PDF处理界的“小能手”&#xff0c;真正做到了用AI解放我们的双手&#xff0c;让处理PDF文件变得轻松又愉快。 这款…

从“记住我”到 Web 认证:Cookie、JWT 和 Session 的故事

文章目录 1. 初识 HTTP&#xff1a;一场没有记忆的对话2. Cookie&#xff1a;网站的“记忆” &#x1f36a;3. Session&#xff1a;服务端的“记忆” &#x1f3af;4. JWT&#xff1a;让用户自己带着“身份证” &#x1f511;5. Cookie vs Session vs JWT 总结 &#x1f4ca;6.…

开箱即用!一个功能丰富的 AI 语音工具箱!

当我们处理大量音频文件时&#xff0c;往往需要语音识别、转录甚至语音合成等多款工具协作完成工具。 这时候&#xff0c;要是有一款工具能够一站式解决从语音识别到语音合成的一切需求就好。 今天&#xff0c;我在 GitHub 上就发现了一款可本地部署的多功能 AI 语音工具箱&a…

MySQL 和 Elasticsearch 之间的数据同步

MySQL 和 Elasticsearch 之间的数据同步是常见的需求&#xff0c;通常用于将结构化数据从关系型数据库同步到 Elasticsearch 以实现高效的全文搜索、聚合分析和实时查询。以下是几种常用的同步方案及其实现方法&#xff1a; 1. 应用层双写&#xff08;双写模式&#xff09; 原…