
Three.js 灯罩着色器 | 三维可视化 / AI 提示词
💡 写在前面
最近一直在研究 Three.js 的着色器效果,偶然看到这个灯罩的例子,一下子就被吸引了——那种朦胧的紫色渐变,配上深蓝背景,像极了深夜书房里一盏温暖的台灯。忍不住动手实现了一遍,过程中踩了不少坑,也有一些有趣的发现,想和大家分享一下。
📋 AI 提示词
使用 Three.js 实现【灯罩着色器】,具体要求:
【核心特效】
- 灯罩采用 CylinderGeometry 几何体,创建锥形中空结构
- 使用 ShaderMaterial 自定义着色器,通过 vUv.y 控制透明度渐变
- 灯罩颜色固定为紫色 (#CB00E3),内部包含发光灯芯
【场景与光照】
- 背景色:深蓝色 (#070630) 营造夜晚氛围
- 光源:每个灯罩内部包含 PointLight,power=1000 模拟真实台灯
【交互与控制】
- OrbitControls 鼠标交互,可旋转视角观察灯罩效果
【技术要求】
- Three.js 版本:latest
- 特殊材质:ShaderMaterial 自定义着色器
- 类结构:DeskLamp 灯罩类,包含私有方法创建灯芯和灯罩
- 几何体:SphereGeometry(灯芯)、CylinderGeometry(灯罩)、PlaneGeometry(地面)
🖼️ 效果预览
看到这个效果的时候,我脑海里浮现的是:夜深了,书房里三盏台灯静静散发着柔和的光,在深蓝的夜色中格外温暖。这种氛围,正是我想要表达的。
🎮 案例演示
建议你拖动鼠标旋转视角,从不同角度看看灯罩的透明渐变效果,特别有感觉!
📖 效果拆解
| 层次 | 视觉效果 | 技术实现 |
|---|---|---|
| 基础 | 场景构建和相机设置 | PerspectiveCamera(45, size.width / size.height, 0.1, 1000),camera.position.set(30, 30, 30) |
| 核心特效 | 灯罩几何体和透明渐变 | CylinderGeometry(1, 5, 3, 32) + ShaderMaterial,vUv.y 控制 alpha |
| 核心特效 | 灯芯发光效果 | SphereGeometry(1, 32, 16) + MeshBasicMaterial + PointLight(power=1000) |
| 增强细节 | 多个灯罩组合 | 创建 3 个 DeskLamp 实例,分布在不同位置 |
| 增强细节 | 地面反射 | PlaneGeometry(100, 100) + MeshStandardMaterial |
🔧 核心技术点
1. DeskLamp 类封装
一开始我直接写了一堆全局变量,后来觉得太乱了,就试着用类来封装。用 ES6 私有方法真的很舒服,把灯芯、灯罩、光源的创建都藏在类里面,外部只需要 new DeskLamp() 就能得到一个完整的台灯对象。
class DeskLamp extends Group {
constructor() {
super()
this.#createWick() // 创建灯芯
this.#createLampshade() // 创建灯罩
}
// 私有方法 #createWick, #createLampshade, #createLight
}
2. CylinderGeometry 锥形灯罩
这里有个小技巧:创建圆锥体其实就是用 CylinderGeometry,把顶部半径设小一点就行。我试了好几个参数组合,最终觉得 topRadius=1、bottomRadius=5 这个比例看起来最自然。
const cylinderGeometry = new CylinderGeometry(1, 5, 3, 32)
// 参数:topRadius=1, bottomRadius=5, height=3, radialSegments=32
const cylinderMaterial = new ShaderMaterial({
transparent: true, // 必须开启透明,一开始忘了加,调试了半天
uniforms: {
color: { value: new Color('#CB00E3') }
},
// ...
})
3. 透明度渐变着色器 (核心)
这是整个效果的灵魂!我特别喜欢这个渐变效果——从底部的实体紫色,慢慢过渡到顶部的完全透明,像一层薄纱笼罩着灯光。
uniform vec3 color; // 灯罩颜色 #CB00E3
varying vec2 vUv; // UV 坐标,vUv.y 从底部 0 到顶部 1
void main() {
// alpha = vUv.y:底部完全不透,顶部完全透明
gl_FragColor = vec4(color, vUv.y);
}
效果原理图:
╭───╮ ← 顶部 vUv.y=1.0, alpha=1.0 完全透明
/ ╲ ╱ \
/ ╲ \ ← 中间 vUv.y=0.5, alpha=0.5 半透明
/─────╲─────\ ← 底部 vUv.y=0, alpha=0 不透明
4. 灯芯点光源
把光源放在灯芯里面是个很巧妙的设计!一开始我把光源放在外面,结果光照效果很奇怪,后来想到把它作为灯芯的子元素,跟着灯芯一起移动,效果立刻就对了。
#createLight(mesh) {
const pointLight = new PointLight(0xffffff, 1, 100)
pointLight.power = 1000 // 这个值调了好多次才满意
mesh.add(pointLight) // 将光源添加为灯芯的子元素
}
5. 场景组合
放三个灯罩是为了营造一种温馨的氛围。我试过放一个、两个,总觉得不够热闹,放三个正好,有种对称美。
const light1 = new DeskLamp()
light1.position.set(0, 10, 0)
scene.add(light1)
const light2 = new DeskLamp()
light2.position.set(10, 10, 0)
scene.add(light2)
const light3 = new DeskLamp()
light3.position.set(0, 10, 10)
scene.add(light3)
💡 调试与优化(踩坑记录)
| 问题类型 | 表现形式 | 解决方案 |
|---|---|---|
| 灯罩不透明 | 模型完全没有透明效果 | ⚠️ 我踩过的坑!忘了设置 transparent: true,ShaderMaterial 默认不透明 |
| 透明渐变方向错误 | 从上到下渐变而非从下到上 | 检查 vUv.y 的使用方式,可能需要改为 1.0 - vUv.y |
| 光照不均匀 | 某些角度灯罩过暗 | PointLight 已在灯芯内部,注意调整 camera.position 和灯罩位置 |
| 性能问题 | 多个灯罩渲染卡顿 | 减少 radialSegments(如 32→16),或使用 InstancedMesh |
🚀 扩展思路(我的一些脑洞)
| 变体效果 | 核心改动 | 难度 | 我的想法 |
|---|---|---|---|
| 可调颜色灯罩 | 将固定颜色改为可动态修改的 uniform | ⭐ | 可以做个颜色选择器,让用户自定义灯罩颜色 |
| 渐变方向反转 | 将 vUv.y 改为 1.0 - vUv.y |
⭐ | 试试看反过来的效果,可能更像真实灯罩? |
| 动态呼吸效果 | 在 animate 中让 color 随时间变化 | ⭐⭐ | 模拟呼吸灯效果,增加生命力 |
| 灯罩开合动画 | 修改 CylinderGeometry 参数实现灯罩开合 | ⭐⭐ | 想象一下台灯打开时灯罩缓缓张开的样子 |
| 触控变色 | 添加 raycaster 监听,实现点击切换颜色 | ⭐⭐ | 交互性更强,用户体验更好 |
✨ 我的感悟
写这个例子的时候,我一直在想:技术不仅仅是冰冷的代码,更是表达情感的工具。这个灯罩效果之所以让我喜欢,就是因为它传递出一种温暖、安静的氛围。希望你在实现的过程中,也能找到属于自己的那份感动。
本文档由 ThreeLab 编辑整理,如需转载,请注明出处。







京公网安备 11010502038735号
💬 评论区
评论功能即将上线,敬请期待!