
写在前面
这是一个基于WebGL技术实现的3D圣诞树场景,融合了音乐可视化效果和粒子系统,营造出一个充满节日氛围的虚拟空间。通过Three.js引擎的强大渲染能力,结合着色器编程和音频分析技术,创造出一个可以与音乐互动的圣诞树森林。
系列文章
| 序号 | 目录 |
|---|---|
| 1 | HTML满屏跳动的爱心 |
| 2 | HTML五彩缤纷的爱心 |
| 3 | HTML满屏漂浮爱心 |
| 4 | HTML情人节爱心 |
| 5 | HTML蓝色爱心射线 |
| 6 | HTML跳动的爱心 |
| 7 | HTML跳动的双爱心 |
| 8 | HTML粒子爱心 |
| 9 | HTML蓝色动态爱心 |
| 10 | HTML橙色动态粒子爱心 |
| 11 | HTML旋转爱心 |
| 12 | HTML爱情树 |
| 13 | HTML元素周期表 |
| 14 | HTML飞舞的花瓣 |
| 15 | HTML星空特效 |
| 16 | HTML黑客帝国字母雨 |
| 17 | HTML哆啦A梦 |
| 18 | HTML流星雨 |
| 19 | HTML沙漏爱心 |
| 20 | HTML爱心字母雨 |
| 21 | HTML爱心流星雨 |
| 22 | HTML生日蛋糕 |
| 23 | HTML流光爱心 |
| 24 | HTML粉色爱心 |
| 25 | HTML满屏飘字 |
| 26 | HTML飞舞爱心 |
| 27 | HTML音乐圣诞树 |
| 28 | HTML星空圣诞树 |
| 29 | HTML礼物圣诞树 |
| 30 | HTML旋转圣诞树 |
| 31 | HTML旋转相册① |
| 32 | HTML旋转相册② |
| 33 | HTML旋转相册③ |
| 34 | HTML大雪纷飞① |
| 35 | HTML大雪纷飞② |
| 36 | HTML炫酷烟花① |
| 37 | HTML炫酷烟花② |
| 38 | HTML炫酷烟花③ |
| 39 | HTML炫酷烟花④ |
| 40 | HTML炫酷烟花⑤ |
| 41 | HTML炫酷烟花⑥ |
| 42 | HTML炫酷烟花⑦ |
| 43 | HTML炫酷烟花⑧ |
| 44 | HTML炫酷烟花⑨ |
| 45 | HTML金色流星雨 |
| 敬请期待...... |
技术需求
-
WebGL渲染引擎核心功能
- Three.js框架集成:引入完整的Three.js库文件,提供3D场景渲染基础;加载EffectComposer、RenderPass等后期处理模块,实现高级视觉效果。
- 场景管理:构建Scene对象作为容器,管理所有3D对象的层次结构;通过PerspectiveCamera设置透视投影,模拟人眼观察效果。
- 渲染循环控制:使用requestAnimationFrame创建平滑动画循环,确保60FPS流畅体验;配合WebGLRenderer进行硬件加速渲染。
-
音频可视化处理机制
- 音频分析器构建:集成AudioListener和AudioAnalyser对象,实时分析音频频谱数据;设置2048大小的FFT分析窗口,捕捉音乐细节变化。
- 频谱数据映射:将音频频谱信息通过DataTexture传递给着色器,实现音乐节拍与视觉效果同步;通过纹理采样控制粒子大小和透明度变化。
-
粒子系统与着色器编程
- 自定义着色器材质:编写vertexShader和fragmentShader程序,实现粒子的动态变换和颜色混合;利用attribute变量为每个粒子设置独立属性。
- 缓冲几何体优化:使用BufferGeometry高效管理大量粒子数据;通过Float32BufferAttribute优化内存使用,提升渲染性能。
-
用户交互与界面设计
- 文件上传处理:实现本地音频文件读取功能,支持多种音频格式;通过FileReader接口解析音频数据,提供个性化体验。
- 界面响应式布局:构建HTML界面元素,提供音乐选择和上传功能;使用CSS样式美化界面,确保跨设备兼容性。
-
后期处理与视觉增强
- 泛光效果实现:集成UnrealBloomPass后期处理通道,营造梦幻光晕效果;通过参数调节控制辉光强度和范围。
- 抗锯齿优化:启用WebGL抗锯齿功能,提升画面质量;使用EffectComposer管理多个渲染通道,实现复合视觉效果。
主要代码
创作不易,订阅后可查看完整代码
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>圣诞树🎄</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/normalize/5.0.0/normalize.min.css">
<style>
* {
box-sizing: border-box;
}
body {
margin: 0;
height: 100vh;
overflow: hidden;
display: flex;
align-items: center;
justify-content: center;
background: #161616;
color: #c5a880;
font-family: sans-serif;
}
label {
display: inline-block;
background-color: #161616;
padding: 16px;
border-radius: 0.3rem;
cursor: pointer;
margin-top: 1rem;
width: 300px;
border-radius: 10px;
border: 1px solid #c5a880;
text-align: center;
}
ul {
list-style-type: none;
padding: 0;
margin: 0;
}
.btn {
background-color: #161616;
border-radius: 10px;
color: #c5a880;
border: 1px solid #c5a880;
padding: 16px;
width: 300px;
margin-bottom: 16px;
line-height: 1.5;
cursor: pointer;
}
.separator {
font-weight: bold;
text-align: center;
width: 300px;
margin: 16px 0px;
color: #a07676;
}
.title {
color: #a07676;
font-weight: bold;
font-size: 1.25rem;
margin-bottom: 16px;
}
.text-loading {
font-size: 2rem;
}
</style>
<script>
window.console = window.console || function (t) { };
</script>
<script>
if (document.location.search.match(/type=embed/gi)) {
window.parent.postMessage("resize", "*");
}
</script>
</head>
<body translate="no">
<script src="https://cdn.jsdelivr.net/npm/three@0.115.0/build/three.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/three@0.115.0/examples/js/postprocessing/EffectComposer.js"></script>
<script src="https://cdn.jsdelivr.net/npm/three@0.115.0/examples/js/postprocessing/RenderPass.js"></script>
<script src="https://cdn.jsdelivr.net/npm/three@0.115.0/examples/js/postprocessing/ShaderPass.js"></script>
<script src="https://cdn.jsdelivr.net/npm/three@0.115.0/examples/js/shaders/CopyShader.js"></script>
<script src="https://cdn.jsdelivr.net/npm/three@0.115.0/examples/js/shaders/LuminosityHighPassShader.js"></script>
<script src="https://cdn.jsdelivr.net/npm/three@0.115.0/examples/js/postprocessing/UnrealBloomPass.js"></script>
<div id="overlay">
<ul>
<li class="title">请选择音乐</li>
<li><button class="btn" id="btnA" type="button">Music1</button></li>
<li><button class="btn" id="btnB" type="button">Music2</button></li>
<li><button class="btn" id="btnC" type="button">Music3</button></li>
<li><button class="btn" id="btnD" type="button">Music4</button></li>
<li class="separator">或者</li>
<li>
<input type="file" id="upload" hidden />
<label for="upload">本地音乐</label>
</li>
</ul>
</div>
<script id="rendered-js">
const { PI, sin, cos } = Math;
const TAU = 2 * PI;
const map = (value, sMin, sMax, dMin, dMax) => {
return dMin + (value - sMin) / (sMax - sMin) * (dMax - dMin);
};
const range = (n, m = 0) =>
Array(n).
fill(m).
map((i, j) => i + j);
const rand = (max, min = 0) => min + Math.random() * (max - min);
const randInt = (max, min = 0) => Math.floor(min + Math.random() * (max - min));
const randChoise = arr => arr[randInt(arr.length)];
const polar = (ang, r = 1) => [r * cos(ang), r * sin(ang)];
let scene, camera, renderer, analyser;
let step = 0;
const uniforms = {
time: { type: "f", value: 0.0 },
step: { type: "f", value: 0.0 }
};
const params = {
exposure: 1,
bloomStrength: 0.9,
bloomThreshold: 0,
bloomRadius: 0.5
};
let composer;
const fftSize = 2048;
const totalPoints = 4000;
const listener = new THREE.AudioListener();
const audio = new THREE.Audio(listener);
document.querySelector("input").addEventListener("change", uploadAudio, false);
const buttons = document.querySelectorAll(".btn");
buttons.forEach((button, index) =>
button.addEventListener("click", () => loadAudio(index)));
......
创作流程
当我开始构思这个圣诞树项目时,脑海中浮现的是一个充满魔法和温暖的冬日场景。我希望创造出一个不仅视觉上令人惊叹,还能与音乐产生共鸣的3D体验。整个创作过程就像是在构建一个虚拟的圣诞世界,每一个元素都承载着我对节日氛围的理解和想象。
首先,我需要确定整体的视觉风格和色彩搭配。我选择了深邃的暗色调作为背景,这样可以让圣诞树的光芒更加突出。金色、绿色和白色的组合让我联想到传统的圣诞装饰,而淡蓝色的点缀则增添了一丝冬日的清冷感。这种色彩方案既要营造节日气氛,又要确保视觉上的和谐统一。
接下来,我开始思考如何构建圣诞树的基本形状。我意识到使用粒子系统是最佳选择,因为它可以创造出轻盈、闪烁的效果,就像真正的圣诞灯饰一样。我设计了一个数学函数来生成树的轮廓,通过极坐标变换创造出螺旋上升的枝条效果。每棵树由数千个粒子组成,这些粒子按照特定的规律分布在空间中,形成逼真的树形结构。
为了让场景更加生动,我决定添加飘落的雪花效果。雪花同样使用粒子系统实现,但它们具有不同的运动轨迹和速度。我为每片雪花设置了随机的相位和振幅,让它们在空中以自然的方式飘舞。不同形状的雪花纹理增加了视觉层次,营造出真实的雪景氛围。
地面的设计也不能忽视。我创建了一个粒子平面,散布着各种颜色的光点,模拟雪地反射的光芒。这些光点随着音乐节拍闪烁,与空中的圣诞树形成呼应,构建出完整的场景层次。
音频可视化是这个项目的核心亮点。我需要将音乐的频谱数据实时映射到视觉元素上。通过分析音频的频率分布,我可以控制圣诞树粒子的大小、亮度和颜色变化。当音乐节奏强烈时,圣诞树会变得更加明亮和动态;而在柔和的旋律中,它则显得宁静而优雅。
用户交互体验是我关注的重点之一。我设计了一个简洁直观的界面,让用户可以选择预设音乐或上传自己的音频文件。加载过程中的动画提示增强了用户体验,让用户感受到即将到来的视觉盛宴。
后期处理效果的添加让整个场景更加梦幻。我集成了泛光效果,让光源产生柔和的光晕,营造出温暖的氛围。这种效果在暗色背景下特别突出,让圣诞树的光芒显得更加迷人。
在技术实现过程中,我特别注重性能优化。大量粒子的渲染对硬件要求很高,因此我使用了缓冲几何体和高效的着色器程序。通过合理管理内存和优化渲染循环,确保了流畅的动画效果。
测试阶段,我尝试了不同风格的音乐来验证可视化效果。从轻柔的圣诞颂歌到欢快的节日舞曲,每种音乐都能产生独特的视觉反馈。这种音乐与视觉的完美结合,让整个作品充满了生命力。
最终,当我看到满屏幕闪烁的圣诞树随着音乐节拍摇摆,雪花在空中优雅飞舞时,我知道这个项目成功地传达了我想要表达的节日温暖和魔法氛围。
写在后面
我是一只有趣的兔子,感谢你的喜欢!