Three.js 蜡烛教程
蜡烛 ·Candle Shader· ▶ 在线运行案例案例合集三维可视化功能案例threehub.cn开源仓库github地址https://github.com/z2586300277/three-cesium-examples400个案例代码:网盘链接你将学到什么ShaderMaterial 自定义着色器实现核心视觉效果OrbitControls 相机轨道交互CatmullRomCurve3 样条曲线路径requestAnimationFrame渲染循环与resize自适应效果说明本案例演示蜡烛效果基于 WebGL 实现「蜡烛」可视化效果附完整可运行源码核心用到 ShaderMaterial、OrbitControls、CatmullRomCurve3。建议先打开文首在线案例查看动态画面再对照下方源码逐步理解。核心概念Scene / Camera / WebGLRenderer构成最小渲染闭环大场景可开logarithmicDepthBuffer缓解 Z-fighting。ShaderMaterial通过uniforms 自定义 GLSL 控制逐像素/逐点效果透明粒子常配合depthTest: false。OrbitControls提供轨道旋转/缩放开启enableDamping后需在 animate 中controls.update()。曲线类getPoints(n)将贝塞尔/样条离散为路径点再写入 BufferGeometry 驱动飞线或路径动画。实现步骤搭建 Scene、PerspectiveCamera、WebGLRenderer挂载 canvas 并处理resize定义 uniforms / onBeforeCompile 或 ShaderMaterial编写 GLSL 与材质参数用曲线离散点构建 BufferGeometry写入自定义 attribute 驱动动画创建 OrbitControls及 Raycaster 等交互控件若源码包含在requestAnimationFrame循环中更新状态并 renderCesium 为viewer.render或自动渲染代码要点import * as THREE from threeimport { OrbitControls } from three/examples/jsm/controls/OrbitControls.jsvar scene new THREE.Scene(); var camera new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 1000); camera.position.set(3, 5, 8).setLength(15); var renderer new THREE.WebGLRenderer({ antialias: true }); renderer.setSize(window.innerWidth, window.innerHeight); renderer.setClearColor(0x101005); renderer.shadowMap.enabled true; renderer.shadowMap.type THREE.PCFSoftShadowMap; document.body.appendChild(renderer.domElement); window.addEventListener(resize, event { camera.aspect innerWidth / innerHeight; camera.updateProjectionMatrix() renderer.setSize(innerWidth, innerHeight); })var controls new OrbitControls(camera, renderer.domElement); controls.enablePan false; controls.minPolarAngle THREE.MathUtils.degToRad(60); controls.maxPolarAngle THREE.MathUtils.degToRad(95); controls.minDistance 4; controls.maxDistance 20; controls.autoRotate true; controls.autoRotateSpeed 1; controls.target.set(0, 2, 0); controls.update();var light new THREE.DirectionalLight(0xffffff, 0.025); light.position.setScalar(10); scene.add(light); scene.add(new THREE.AmbientLight(0xffffff, 0.0625));var casePath new THREE.Path(); casePath.moveTo(0, 0); casePath.lineTo(0, 0); casePath.absarc(1.5, 0.5, 0.5, Math.PI1.5, Math.PI2); casePath.lineTo(2, 1.5); casePath.lineTo(1.99, 1.5); casePath.lineTo(1.9, 0.5); var caseGeo new THREE.LatheGeometry(casePath.getPoints(), 64); var caseMat new THREE.MeshStandardMaterial({ color: silver }); var caseMesh new THREE.Mesh(caseGeo, caseMat); caseMesh.castShadow true;var paraffinPath new THREE.Path(); paraffinPath.moveTo(0, -.25); paraffinPath.lineTo(0, -.25); paraffinPath.absarc(1, 0, 0.25, Math.PI1.5, Math.PI2); paraffinPath.lineTo(1.25, 0); paraffinPath.absarc(1.89, 0.1, 0.1, Math.PI1.5, Math.PI2); var paraffinGeo new THREE.LatheGeometry(paraffinPath.getPoints(), 64); paraffinGeo.translate(0, 1.25, 0); var paraffinMat new THREE.MeshStandardMaterial({ color: 0xffff99, side: THREE.BackSide, metalness: 0, roughness: 0.75 }); var paraffinMesh new THREE.Mesh(paraffinGeo, paraffinMat); caseMesh.add(paraffinMesh);var candlewickProfile new THREE.Shape(); candlewickProfile.absarc(0, 0, 0.0625, 0, Math.PI * 2);var candlewickCurve new THREE.CatmullRomCurve3([ new THREE.Vector3(0, 0, 0), new THREE.Vector3(0, 0.5, -0.0625), new THREE.Vector3(0.25, 0.5, 0.125) ]);var candlewickGeo new THREE.ExtrudeGeometry(candlewickProfile, { steps: 8, bevelEnabled: false, extrudePath: candlewickCurve });var colors []; var color1 new THREE.Color(black); var color2 new THREE.Color(0x994411); var color3 new THREE.Color(0xffff44); for (let i 0; i candlewickGeo.attributes.position.count; i) { if (candlewickGeo.attributes.position.getY(i) 0.4) { color1.toArray(colors, i * 3); } else { color2.toArray(colors, i * 3); }; if (candlewickGeo.attributes.position.getY(i) 0.15) color3.toArray(colors, i * 3); } candlewickGeo.setAttribute(color, new THREE.BufferAttribute(new Float32Array(colors), 3)); candlewickGeo.translate(0, 0.95, 0); var candlewickMat new THREE.MeshBasicMaterial({ vertexColors: true });var candlewickMesh new THREE.Mesh(candlewickGeo, candlewickMat); caseMesh.add(candlewickMesh);// candle light var candleLight new THREE.PointLight(0xffaa33, 1, 5, 2); candleLight.position.set(0, 3, 0); candleLight.castShadow true; caseMesh.add(candleLight); var candleLight2 new THREE.PointLight(0xffaa33, 1, 10, 2); candleLight2.position.set(0, 4, 0); candleLight2.castShadow true; caseMesh.add(candleLight2);var flameMaterials []; function flame(isFrontSide) { let flameGeo new THREE.SphereGeometry(0.5, 32, 32); flameGeo.translate(0, 0.5, 0); let flameMat getFlameMaterial(true); flameMaterials.push(flameMat); let flame new THREE.Mesh(flameGeo, flameMat); flame.position.set(0.06, 1.2, 0.06); flame.rotation.y THREE.MathUtils.degToRad(-45); caseMesh.add(flame); }flame(false); flame(true);// table var tableGeo new THREE.CylinderGeometry(14, 14, 0.5, 64); tableGeo.translate(0, -0.25, 0); var tableMat new THREE.MeshStandardMaterial({ map: new THREE.TextureLoader().load(https://threejs.org/examples/textures/hardwood2_diffuse.jpg), metalness: 0, roughness: 0.75 }); var tableMesh new THREE.Mesh(tableGeo, tableMat); tableMesh.receiveShadow true;tableMesh.add(caseMesh); scene.add(tableMesh);var clock new THREE.Clock(); var time 0;render(); function render() { requestAnimationFrame(render); time clock.getDelta(); flameMaterials[0].uniforms.time.value time; flameMaterials[1].uniforms.time.value time; candleLight2.position.x Math.sin(timeMath.PI)0.25; candleLight2.position.z Math.cos(timeMath.PI0.75) * 0.25; candleLight2.intensity 2 Math.sin(timeMath.PI2)Math.cos(timeMath.PI1.5)0.25; controls.update(); renderer.render(scene, camera); }//reference Paul https://codepen.io/prisoner849/pen/XPVGLp function getFlameMaterial(isFrontSide) { let side isFrontSide ? THREE.FrontSide : THREE.BackSide; return new THREE.ShaderMaterial({ uniforms: { time: { value: 0 } }, vertexShader:uniform float time; varying vec2 vUv; varying float hValue; float random (in vec2 st) { return fract(sin(dot(st.xy, vec2(12.9898,78.233)))43758.5453123);}float noise (in vec2 st) { vec2 i floor(st); vec2 f fract(st);// Four corners in 2D of a tile float a random(i); float b random(i vec2(1.0, 0.0)); float c random(i vec2(0.0, 1.0)); float d random(i vec2(1.0, 1.0));// Smooth Interpolation// Cubic Hermine Curve. Same as SmoothStep() vec2 u ff(3.0-2.0*f); // u smoothstep(0.,1.,f);// Mix 4 coorners percentages return mix(a, b, u.x) (c - a)u.y(1.0 - u.x) (d - b)u.xu.y; }void main() { vUv uv; vec3 pos position;pos * vec3(0.8, 2, 0.725); hValue position.y; //float sinT sin(time2.)0.5 0.5; float posXZlen length(position.xz);pos.y 1. (cos((posXZlen 0.25)3.1415926)0.25 noise(vec2(0, time))0.125 noise(vec2(position.x time, position.z time))0.5)position.y; // flame heightpos.x noise(vec2(time2., (position.y - time)4.0))hValue0.0312; // flame trembling pos.z noise(vec2((position.y - time)4.0, time2.))hValue0.0312; // flame tremblinggl_Position projectionMatrixmodelViewMatrixvec4(pos,1.0); }, fragmentShader:varying float hValue; varying vec2 vUv;// honestly stolen from https://www.shadertoy.com/view/4dsSzr vec3 heatmapGradient(float t) { return clamp((pow(t, 1.5)0.8 0.2)vec3(smoothstep(0.0, 0.35, t) t0.5, smoothstep(0.5, 1.0, t), max(1.0 - t1.7, t * 7.0 - 6.0)), 0.0, 1.0); }void main() { float v abs(smoothstep(0.0, 0.4, hValue) - 1.); float alpha (1. - v) * 0.99; // bottom transparency alpha - 1. - smoothstep(1.0, 0.97, hValue); // tip transparency gl_FragColor vec4(heatmapGradient(smoothstep(0.0, 0.3, hValue)) * vec3(0.95,0.95,0.4), alpha) ; gl_FragColor.rgb mix(vec3(0,0,1), gl_FragColor.rgb, smoothstep(0.0, 0.3, hValue)); // blueish for bottom gl_FragColor.rgb vec3(1, 0.9, 0.5) * (1.25 - vUv.y); // make the midst brighter gl_FragColor.rgb mix(gl_FragColor.rgb, vec3(0.66, 0.32, 0.03), smoothstep(0.95, 1., hValue)); // tip }, transparent: true, side: side })}完整源码GitHub小结本文提供蜡烛完整 Three.js 源码与在线 Demo建议先运行案例再改 uniform/参数做二次实验更多 Three.js 实战案例见 three-cesium-examples 合集 与 GitHub 开源仓库

相关新闻

Mappedbus实战教程:3步实现Java进程间高效通信(含完整代码示例)

Mappedbus实战教程:3步实现Java进程间高效通信(含完整代码示例)

Mappedbus实战教程:3步实现Java进程间高效通信(含完整代码示例) 【免费下载链接】Mappedbus Mappedbus is a low latency message bus for Java microservices utilizing shared memory. http://mappedbus.io 项目地址: https://gitcode.co…

2026/7/25 20:36:50阅读更多 →
从0到1部署gh_mirrors/back/backend:Docker容器化与CI/CD流程详解

从0到1部署gh_mirrors/back/backend:Docker容器化与CI/CD流程详解

从0到1部署gh_mirrors/back/backend:Docker容器化与CI/CD流程详解 【免费下载链接】backend A template repository for TypeScript backend server 项目地址: https://gitcode.com/gh_mirrors/back/backend GitHub 加速计划(gh_mirrors/back/bac…

2026/7/25 20:36:50阅读更多 →
PlumeImpactor多语言支持:如何切换界面语言及贡献翻译

PlumeImpactor多语言支持:如何切换界面语言及贡献翻译

PlumeImpactor多语言支持:如何切换界面语言及贡献翻译 【免费下载链接】Impactor Feature rich iOS/tvOS sideloading application written in Rust. 项目地址: https://gitcode.com/gh_mirrors/pl/Impactor PlumeImpactor是一款功能丰富的iOS/tvOS侧载应用&…

2026/7/25 20:36:50阅读更多 →
从甲骨文到数字孪生:AI驱动的历史记忆范式革命(全球首份跨文明记忆强度对比报告首发)

从甲骨文到数字孪生:AI驱动的历史记忆范式革命(全球首份跨文明记忆强度对比报告首发)

更多请点击: https://intelliparadigm.com 第一章:从甲骨文到数字孪生:AI驱动的历史记忆范式革命(全球首份跨文明记忆强度对比报告首发) 人类记忆的载体正经历一场静默却深刻的范式跃迁:从龟甲兽骨的刻痕、…

2026/7/25 21:55:11阅读更多 →
低成本落地AI数字人?实测11款方案ROI对比:从万元级SaaS到开源部署,哪款3个月内回本?

低成本落地AI数字人?实测11款方案ROI对比:从万元级SaaS到开源部署,哪款3个月内回本?

更多请点击: https://kaifayun.com 第一章:低成本落地AI数字人?实测11款方案ROI对比:从万元级SaaS到开源部署,哪款3个月内回本? 在真实业务场景中,我们对11款主流AI数字人方案进行了为期90天的…

2026/7/25 21:55:11阅读更多 →
解析semantic_slam核心模块:语义点云生成与八叉树融合技术

解析semantic_slam核心模块:语义点云生成与八叉树融合技术

解析semantic_slam核心模块:语义点云生成与八叉树融合技术 【免费下载链接】semantic_slam Real time semantic slam in ROS with a hand held RGB-D camera 项目地址: https://gitcode.com/gh_mirrors/se/semantic_slam semantic_slam是一个基于ROS的实时语…

2026/7/25 21:55:11阅读更多 →
DRV2605触觉驱动器:从核心模式到寄存器配置的嵌入式触觉反馈实战

DRV2605触觉驱动器:从核心模式到寄存器配置的嵌入式触觉反馈实战

1. 项目概述与核心价值如果你正在为你的嵌入式设备寻找一种能提供细腻、精准触觉反馈的解决方案,那么德州仪器(TI)的DRV2605触觉驱动器绝对是一个绕不开的经典选择。我接触过不少触觉驱动芯片,从简单的马达驱动到复杂的多通道方案…

2026/7/25 21:55:11阅读更多 →
Unity DOTS实战指南:ECS架构、Job System与Burst编译器的性能革命

Unity DOTS实战指南:ECS架构、Job System与Burst编译器的性能革命

1. 项目概述:为什么DOTS是Unity开发者的下一站如果你还在用传统的GameObject和MonoBehaviour模式开发Unity项目,尤其是那些对性能有极致要求的游戏(比如大规模策略游戏、MOBA的小兵海、开放世界的大量动态实体),那你可…

2026/7/25 21:55:11阅读更多 →
微信小程序数据可视化终极指南:如何用 Apache ECharts 快速创建专业图表

微信小程序数据可视化终极指南:如何用 Apache ECharts 快速创建专业图表

微信小程序数据可视化终极指南:如何用 Apache ECharts 快速创建专业图表 【免费下载链接】echarts-for-weixin 基于 Apache ECharts 的微信小程序图表库 项目地址: https://gitcode.com/gh_mirrors/ec/echarts-for-weixin 还在为微信小程序中如何展示复杂数据…

2026/7/25 21:53:10阅读更多 →
Go语言静态资源打包方案对比与实践指南

Go语言静态资源打包方案对比与实践指南

1. 项目背景与核心需求在Go语言开发中,我们经常需要处理静态资源文件的打包问题。无论是Web应用的模板文件、前端资源,还是配置文件、证书等,都需要随程序一起分发。传统做法是将这些文件与编译后的二进制文件放在同一目录下,但这…

2026/7/25 1:01:14阅读更多 →
Go语言实现高性能LDAP认证服务的架构与实践

Go语言实现高性能LDAP认证服务的架构与实践

1. 项目背景与核心价值LDAP(轻量级目录访问协议)作为企业级身份认证的黄金标准,已经服务了超过80%的财富500强公司。我在金融科技领域实施统一认证体系时,发现传统Java方案存在启动慢、内存占用高等痛点。而Go语言凭借其协程并发模…

2026/7/25 1:01:14阅读更多 →
【AI面试官实战指南】:用ChatGPT模拟10类高频技术岗面试,3天提升应答精准度92%

【AI面试官实战指南】:用ChatGPT模拟10类高频技术岗面试,3天提升应答精准度92%

更多请点击: https://intelliparadigm.com 第一章:AI面试官实战指南的核心价值与适用场景 AI面试官并非替代人类HR的“黑箱工具”,而是以可解释、可审计、可迭代的方式,赋能招聘全链路的关键基础设施。其核心价值在于将主观经验沉…

2026/7/25 1:01:14阅读更多 →
突破文档下载限制:kill-doc让你看到的都能保存

突破文档下载限制:kill-doc让你看到的都能保存

突破文档下载限制:kill-doc让你看到的都能保存 【免费下载链接】kill-doc 看到经常有小伙伴们需要下载一些免费文档,但是相关网站浏览体验不好各种广告,各种登录验证,需要很多步骤才能下载文档,该脚本就是为了解决您的…

2026/7/25 0:01:16阅读更多 →
C++ string类模拟实现:从深拷贝到内存管理的完整指南

C++ string类模拟实现:从深拷贝到内存管理的完整指南

1. 项目概述:为什么我们要“手撕”string类?在C的学习道路上,尤其是从C语言过渡到C的“初阶”阶段,string类绝对是一个绕不开的核心。标准库里的std::string用起来太方便了,、find、substr,几个操作符和函数…

2026/7/25 0:01:16阅读更多 →
三角洲寻宝鼠工具:高效文件搜索与资源管理实战指南

三角洲寻宝鼠工具:高效文件搜索与资源管理实战指南

1. 先搞清楚“三角洲寻宝鼠”到底是什么工具从名称来看,“三角洲寻宝鼠”更像是一个资源查找或文件检索类工具,而不是游戏或娱乐软件。这类工具的核心价值在于帮助用户快速定位特定资源,比如文档、图片、压缩包或特定格式的文件。如果你经常需…

2026/7/25 0:01:16阅读更多 →
YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

如果你在部署 YOLOv8 时,发现推理速度只有可怜的 1-2 FPS,而别人的演示视频却能跑到 30 FPS 以上,那么问题很可能不在模型本身,而在于你的整个处理链路。很多开发者拿到一个训练好的 YOLOv8 模型后,会直接使用官方示例…

2026/7/24 23:01:03阅读更多 →
Coze与Dify对比指南:低代码AI应用开发从入门到实战

Coze与Dify对比指南:低代码AI应用开发从入门到实战

1. 从零到一:为什么你需要了解 Coze 和 Dify?如果你对 AI 应用开发感兴趣,但一看到“大模型”、“智能体”、“工作流”这些词就头疼,觉得门槛太高,那这篇文章就是为你准备的。很多开发者,包括我自己&#…

2026/7/25 19:03:04阅读更多 →
AI生图工具怎么选?2026年6月版实测对比

AI生图工具怎么选?2026年6月版实测对比

做自媒体的朋友应该都有体会:配图一直是个让人头疼的问题。2026年,AI生图工具已经非常成熟了,但工具太多反而不知道怎么选。以下是截至2026年6月我对主流AI生图工具的实测对比。Midjourney V8.1:速度之王2026年6月11日&#xff0c…

2026/7/25 19:03:04阅读更多 →