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

Three.js 精灵火花教程

精灵火花 ·Tween Fire· ▶ 在线运行案例

  • 案例合集:三维可视化功能案例(threehub.cn)
  • 开源仓库github地址:https://github.com/z2586300277/three-cesium-examples
  • 400个案例代码:网盘链接

你将学到什么

  • OrbitControls 相机轨道交互
  • Canvas 动态纹理贴图
  • GSAP 时间轴与补间动画
  • requestAnimationFrame渲染循环与resize自适应

效果说明

本案例演示精灵火花效果:用 Canvas 2D 绘制内容并实时映射为 Three.js 纹理;核心用到 OrbitControls、Canvas、GSAP。建议先打开文首在线案例查看动态画面,再对照下方源码逐步理解。

核心概念

  • OrbitControls轨道旋转缩放;开enableDamping时每帧需controls.update()
  • 属性插值动画,适合相机动效、UI 过渡。

实现步骤

  • 搭建 Scene / Camera / Renderer 与 OrbitControls
  • rAF 循环中 update 并 render
  • 代码要点

    import * as THREE from 'three'

    import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js' import TWEEN from "three/addons/libs/tween.module.js"; import { GUI } from 'dat.gui'

    // 获取容器并设置场景、相机和渲染器 const box = document.getElementById('box'); const scene = new THREE.Scene(); const camera = new THREE.PerspectiveCamera(50, box.clientWidth / box.clientHeight, 0.1, 1000); camera.position.set(0, 200, 200); const renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true, logarithmicDepthBuffer: true }); renderer.setSize(box.clientWidth, box.clientHeight); box.appendChild(renderer.domElement);

    // 控制器 const controls = new OrbitControls(camera, renderer.domElement); controls.enableDamping = true;

    // 动画循环 function animate() { requestAnimationFrame(animate); controls.update(); TWEEN.update(); renderer.render(scene, camera); } animate();

    // 颜色配置 const colorArr = [ { position: 0, color: 'rgba(255,255,255,1)' }, { position: 0.05, color: 'rgba(255,230,140,0.9)' }, { position: 0.2, color: 'rgba(255,180,40,0.6)' }, { position: 1, color: 'rgba(255,100,0,0)' } ];

    // 生成纹理 const canvas = document.createElement('canvas'); canvas.width = 256; canvas.height = 256; const context = canvas.getContext('2d'); context.clearRect(0, 0, canvas.width, canvas.height); const gradient = context.createRadialGradient( canvas.width / 2, canvas.height / 2, 0, canvas.width / 2, canvas.width / 2, canvas.width / 2 ); colorArr.forEach(stop => { gradient.addColorStop(stop.position, stop.color); }); context.fillStyle = gradient; context.beginPath(); context.arc(canvas.width / 2, canvas.height / 2, canvas.width / 2, 0, Math.PI * 2); context.fill();

    // 内部高光 const innerGradient = context.createRadialGradient( canvas.width / 2, canvas.height / 2, 0, canvas.width / 2, canvas.height / 2, canvas.width / 4 );

    innerGradient.addColorStop(0, 'rgba(255, 255, 255, 0.8)'); innerGradient.addColorStop(0.3, 'rgba(255, 240, 220, 0.5)'); innerGradient.addColorStop(1, 'rgba(255, 240, 200, 0)');

    context.fillStyle = innerGradient; context.beginPath(); context.arc(canvas.width / 2, canvas.height / 2, canvas.width / 4, 0, Math.PI * 2); context.fill();

    const texture = new THREE.CanvasTexture(canvas);

    // 创建粒子系统 const sprites = new THREE.Object3D(); const material = new THREE.SpriteMaterial({ map: texture, blending: THREE.AdditiveBlending, transparent: true, depthWrite: false, alphaTest: 0.01 });

    const gui = new GUI();

    const config = { r_p: 20, size: 32, xx: 200, yy: 400, zz: 100, sl: 0.1, time: 1500, d: 4 }

    gui.add(config, 'r_p', 0, 200).name('粒子范围'); gui.add(config, 'size', 0, 64).name('粒子大小'); gui.add(config, 'xx', 0, 800).name('x轴范围'); gui.add(config, 'yy', 0, 800).name('y轴范围'); gui.add(config, 'zz', 0, 800).name('z轴范围'); gui.add(config, 'sl', 0, 1).name('缩放比例'); gui.add(config, 'time', 0, 3000).name('动画时间'); gui.add(config, 'd', 0, 10).name('粒子间隔');

    // 添加粒子 for (let i = 0; i < 300; i++) { const particle = new THREE.Sprite(material); initParticle(particle, i * config.d, sprites); sprites.add(particle); }

    scene.add(sprites);

    // 初始化粒子 function initParticle(particle, delay) {

    const r_v = v => Math.random() * v - v / 2;

    // 初始化位置和大小 particle.position.set(r_v(config.r_p), r_v(config.r_p), r_v(config.r_p)); particle.scale.x = particle.scale.y = particle.scale.z = Math.random() * config.size;

    const xx = r_v(config.xx) const yy = Math.abs(r_v(config.yy)) const zz = -Math.cos((Math.PI / 10)xx)config.zz;

    new TWEEN.Tween(particle.position) .delay(delay) .to({ x: xx, y: yy, z: zz }, config.time) .start() .onComplete(() => initParticle(particle, delay))

    new TWEEN.Tween(particle.scale) .delay(delay) .to({ x: config.sl, y: config.sl }, config.time) .start();

    }

    完整源码:GitHub

    小结

    • 本文提供精灵火花完整 Three.js 源码与在线 Demo,建议先运行案例再改 uniform/参数做二次实验
    • 更多 Three.js 实战案例见 three-cesium-examples 合集 与 GitHub 开源仓库
http://www.jsqmd.com/news/1089962/

相关文章:

  • 从零到上线:Java工程师3小时搞定ChatGPT API集成,附可直接投产的Gradle依赖+Token自动刷新模块
  • LBP实战:基于LBP特征的图像纹理分类
  • LitCAD:完全免费的C开源CAD绘图软件入门指南
  • Lightweight Charts 5大核心优势:构建高性能金融图表的Canvas解决方案
  • Rusted PackFile Manager:全面战争MOD开发者的终极效率革命
  • 毕业论文的加速引擎!常用的一键生成论文工具,思路秒出超省心
  • MySQL进阶:巧用SUBSTRING_INDEX与辅助表实现字段动态拆分与行列转换
  • 3个核心步骤:掌握Icarus Verilog硬件设计验证
  • TrollInstallerX终极指南:iOS 14-16.6.1设备3分钟快速安装TrollStore
  • Destiny 2 单人模式终极指南:如何轻松享受纯粹的游戏体验
  • 音乐文件解密完全攻略:5种方法让你告别平台限制
  • Unitree RL GYM:机器人强化学习的终极跨仿真环境迁移指南
  • 3步搞定!免费将手机变身高清OBS摄像头完整教程
  • WaveTools鸣潮工具箱技术架构深度解析:帧率解锁与数据管理实现原理
  • DDrawCompat完全指南:让经典DirectX游戏在现代Windows上焕发新生
  • DeepEval深度解析:构建企业级LLM评估框架的5大核心策略
  • DLSS Swapper终极指南:三步轻松提升游戏性能,智能管理DLSS版本
  • 终极指南:如何用KMS_VL_ALL_AIO脚本一键激活Windows和Office
  • FIFA World Cup 2026 [Round of 16]
  • 从CVE-2022-26134到权限维持:Confluence OGNL注入漏洞的深度利用链剖析
  • League Akari:基于LCU API的英雄联盟客户端增强工具集
  • 【Springboot毕设全套源码+文档】基于的设计与实现(丰富项目+远程调试+讲解+定制)
  • TVA在具身智能产业化体系的落地案例详解(9)
  • ArkUI——2D绘图
  • 终极免费桌面分区工具:3步打造整洁高效的Windows工作空间
  • 构建企业级微信机器人自动化:we-work-bot完整技术指南
  • NoFences:开源桌面分区工具,打造高效整洁的数字工作空间
  • AI自动化攻击下企业AD安全防护:零信任与PAM、EDR协同防御方案
  • 3步扫码获取阿里云盘Refresh Token:告别手动登录的自动化新体验
  • TV Bro电视浏览器:用遥控器轻松上网的终极解决方案