一、效果概述
本文通过Three.js构建了一个具有科技感的3D场景,主要包含两大视觉元素:
- 动态心形模型:采用数学函数生成基础形状,通过顶点操作实现表面弧度。
- 星空粒子背景:随机分布的粒子群组形成空间层次感。
- 复合动画系统:包含心跳脉冲、轴向旋转、粒子场运动等动画效果。
视觉效果:
超酷3D心形粒子特效,浪漫满分!
二、核心技术实现原理
2.1,心形建模算法
心形建模算法利用了经典的心形参数方程,通过数学公式生成心形路径。该方程定义了心形在二维平面上的轮廓,其中 (x(t) = 16\sin^3 t) 和 (y(t) = 13\cos t - 5\cos 2t - 3\cos 3t - \cos 4t)。这些公式通过参数 (t) 描述了心形的曲线形状,随着 (t) 从0到 (2\pi) 的变化,生成一个完整的心形轮廓。这个路径随后被用于创建三维几何体,通过Three.js的ExtrudeGeometry进行挤出,形成一个具有深度和曲面弧度的3D心形模型。
2.1.1,心形参数方程
代码中采用经典心形线参数方程,其数学表达式为:
其中 t∈[0,2π]t∈[0,2π],步长0.01决定曲线精度。该方程相比标准心形方程 r=a(1−sinθ)r=a(1−sinθ) 能生成更圆润的边界曲线。
2.1.2,代码实现
function createHeartShape() {const shape = new THREE.Shape();for (let t = 0; t <= Math.PI*2; t += 0.01) {const x = 16 * Math.pow(Math.sin(t), 3);const y = 13*Math.cos(t) - 5*Math.cos(2*t) - 3*Math.cos(3*t) - Math.cos(4*t);// 路径绘制...}return shape;
}
2.1.3,原理说明
该方程通过多项式组合控制曲线形态,相比标准心形方程:
- 5cos2t 项控制心形凹陷深度
- 3cos3t 调整顶部曲率
- cos4t 消除底部尖角
代码中t += 0.01的步长值决定了曲线精度(约628个顶点)
2.2,三维挤出变换
2.2.1,变换矩阵
通过ExtrudeGeometry实现2D到3D转换时,运用了仿射变换矩阵:
2.2.2,代码实现
const extrudeSettings = {depth: 8, // 挤出深度bevelEnabled: true, // 启用倒角bevelSegments: 12 // 倒角细分
};
geometry.scale(0.5, 0.5, 0.5);
2.2.3,原理说明
- depth:8 沿Z轴挤出8个单位
- bevelSegments:12 使用12段圆弧平滑边缘
- 缩放矩阵将模型整体缩小50%,避免场景过载
2.3. 表面弧度算法
2.3.1,曲面变形公式:
2.3.2,代码实现
function addSurfaceCurvature(geometry) {const position = geometry.attributes.position;for (let i = 0; i < position.count; i++) {const x = position.getX(i);const y = position.getY(i);const z = position.getZ(i) + 0.01 * Math.sqrt(x*x + y*y);position.setXYZ(i, x, y, z);}geometry.computeVertexNormals();
}
2.3.3,原理说明
- 0.01为曲率系数,值越大曲面越凸
- 法线重计算确保光照反射正确,算法复杂度为O(n)
- 该变形等效于将平面映射到旋转抛物面:
其中 p=25 控制抛物面开口大小。
2.4,动画系统
2.4.1,心跳脉冲函数数学公式:
2.4.2,代码实现
// 在animate()函数中
const pulse = Math.sin(time * 3) * 0.2 + 1;
heart.scale.set(pulse, pulse, pulse);
2.4.3,原理说明
- 频率参数3:每秒完成3/(2π)≈0.477次心跳
- 振幅0.2:尺寸在0.8~1.2倍之间波动
- 基准值1:确保缩放不出现负值
2.5,粒子系统
粒子系统的实现通过使用Three.js的BufferGeometry来优化性能和内存使用。我们生成了1500个粒子,每个粒子的坐标在 [−50,50的范围内均匀分布,这意味着每个坐标轴上的位置是随机的。这样,粒子的平均密度为 0.015 粒子/单位立方体。BufferGeometry的使用相比于传统的Geometry减少了约70%的内存占用,因为它允许直接在GPU上存储和操作顶点数据,从而提高了渲染效率和性能。这种方法特别适合于需要处理大量粒子的场景,如模拟星空或烟雾效果。
2.5.1,位置随机分布函数
2.5.2,代码实现
for (let i = 0; i < 1500; i++) {positions.push((Math.random() - 0.5) * 100, // x(Math.random() - 0.5) * 100, // y (Math.random() - 0.5) * 100 // z);
}
2.5.3,原理说明,
- U(-50,50)表示均匀分布
- 粒子数1500时,平均密度为:
- 使用BufferGeometry减少内存占用约70%(相比普通Geometry)
三、光照模型实现
在光照模型中,点光源的衰减通过物理模型来实现,使得光源的强度随着距离的增加而减弱。在Three.js中,可以通过配置点光源的初始强度和衰减半径来实现这一效果。在代码中,new THREE.PointLight(0xff77aa, 1, 50) 设置了光源的初始强度为1,衰减半径为50。这意味着当距离达到50时,光照强度会减弱到一半。这种衰减模型使得光源在场景中更具真实感,模拟了现实中光线随着距离减弱的效果。,
3.1,点光源衰减物理公式:
3.2,代码实现
new THREE.PointLight(0xff77aa, 1, 50) // distance=50
四、性能优化
4.1,矩阵更新优化渲染循环:
function animate() {requestAnimationFrame(animate);// 仅更新变换矩阵renderer.render(scene, camera);
}
4.2,原理说明
- Three.js采用矩阵惰性更新机制
- 当修改object.position等属性时,仅标记需要更新矩阵
- 在渲染前统一计算世界矩阵,复杂度从O(n²)降至O(n)
五、扩展应用示例
5.1,数学原理
实时修改曲率系数k时,顶点位置更新公式:
5.2,代码实现
// 添加GUI控件
const gui = new dat.GUI();
gui.add(curveParams, 'factor', 0, 0.05).onChange(v => {heart.traverse(child => {if (child.isMesh) {addSurfaceCurvature(child.geometry, v);}});
});
六,总结
本文利用Three.js实现了一个3D曲面爱心动画,包含场景初始化、光源配置、心形模型创建、粒子背景生成和动画效果。通过数学公式生成心形路径,并使用ExtrudeGeometry进行三维挤出,形成具有曲面弧度的心形模型。添加环境光和双色点光源提供立体照明,利用BufferGeometry和PointsMaterial创建动态粒子背景,模拟星空效果。动画部分实现了心形的脉动和旋转,以及粒子背景的缓慢运动,并通过监听窗口大小变化实现响应式设计,确保在不同设备上正常显示。
任何问题,源码获取请私信留言。