用 Three.js 绘制炫彩心形线条并加上星空背景
在这篇教程中,我们将使用 Three.js 和 MeshLine 库,绘制出一个具有动态虚线效果的心形线条,并在背景中添加随机散布的星星效果。整体视觉非常浪漫,适合做一些特别的演示或活动页面。
一、项目初始化
在正式写代码前,需要先初始化一个前端项目,安装 Three.js、MeshLine 以及相关依赖。
-
安装依赖:
npm install three npm install meshline
二、搭建 Three.js 场景
在主文件 main.js
中,我们首先导入所需的模块及类,并创建一个基础的 Three.js 场景。主要包含以下几步:
-
导入库:
import * as THREE from "three"; import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js"; import { MeshLineGeometry, MeshLineMaterial } from "meshline";
-
创建场景:
const scene = new THREE.Scene(); scene.background = new THREE.Color(0x000000); // 黑色背景
-
创建透视相机:
const camera = new THREE.PerspectiveCamera( 75, // 视野角度 window.innerWidth / window.innerHeight, // 宽高比 0.1, // 近平面 1000 // 远平面 ); camera.position.set(0, 0, 50); // 设置相机位置
-
创建渲染器:
const renderer = new THREE.WebGLRenderer({ canvas: document.getElementById("canvas"), antialias: true, // 抗锯齿 }); renderer.setSize(window.innerWidth, window.innerHeight); renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
-
OrbitControls 轨道控制器:
使用户可以通过鼠标拖拽来旋转、缩放我们的场景。const controls = new OrbitControls(camera, renderer.domElement); controls.enableDamping = true; controls.dampingFactor = 0.05;
到这里,最基础的场景搭建已完成。
三、创建心形线条
接下来,我们使用 MeshLine 来绘制心形曲线。MeshLine 可以帮助我们更灵活地控制线条宽度、纹理等特性。
-
创建 MeshLineGeometry:
const geometry = new MeshLineGeometry();
-
生成心形曲线的顶点:
心形线条的公式(取自常用的数学心形函数):
x=16sin3(t),y=13cos(t)−5cos(2t)−2cos(3t)−cos(4t)
通过循环计算各个离散点:
const geometryPoints = [];
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) - 2 * Math.cos(3 * t) - Math.cos(4 * t);
geometryPoints.push(new THREE.Vector3(x, y, 0));
}
-
设置几何体的点并指定线条宽度变化:
如果希望线条在某些位置变粗或变细,我们可以通过回调函数(p) => 1 - p * 0.5
的方式设定线条的宽度分布。例如这里让线条在首尾稍微变细。geometry.setPoints(geometryPoints, (p) => 1 - p * 0.5);
-
创建 MeshLineMaterial:
通过MeshLineMaterial
,我们可以指定线条颜色、宽度、虚线效果等属性。const lineMaterial = new MeshLineMaterial({ color: new THREE.Color(0xff0066), // 粉红色 lineWidth: 1.5, resolution: new THREE.Vector2(window.innerWidth, window.innerHeight), dashArray: 2, // 控制虚线的点/线长度 dashOffset: 0, // 偏移量,可以用来做动态效果 dashRatio: 0.5, // 虚线空隙与实线的比例 transparent: true, depthTest: false, });
-
创建网格并添加到场景:
const mesh = new THREE.Mesh(geometry, lineMaterial); scene.add(mesh);
四、灯光设置
虽然这是一个线条为主的场景,但给场景添加一些基础光源能够让整体看起来更有层次感,同时也方便后期扩展。
-
环境光:
提供整体的漫反射光照,让物体不会过暗。const ambientLight = new THREE.AmbientLight(0xffffff, 0.5); scene.add(ambientLight);
-
方向光:
提供一个具有方向性的光源,可模拟太阳光。const directionalLight = new THREE.DirectionalLight(0xffffff, 1); directionalLight.position.set(1, 1, 1); scene.add(directionalLight);
五、动态效果与自适应
-
监听窗口尺寸变化:
当浏览器窗口改变大小时,需要更新相机的宽高比、渲染器大小以及线条材质的分辨率:window.addEventListener("resize", () => { camera.aspect = window.innerWidth / window.innerHeight; camera.updateProjectionMatrix(); renderer.setSize(window.innerWidth, window.innerHeight); lineMaterial.resolution.set(window.innerWidth, window.innerHeight); });
-
动画循环:
- 通过
requestAnimationFrame
实现帧循环。 - 在每一帧中,更新控制器、旋转网格、修改虚线的偏移量来产生“流动”的效果。
function animate() { requestAnimationFrame(animate); controls.update(); // 更新控制器 mesh.rotation.z += 0.005; // 让心形线条缓慢旋转 lineMaterial.dashOffset -= 0.01; // 虚线动态流动 renderer.render(scene, camera); } animate();
- 通过
六、添加星空背景
为了让场景更浪漫或更具层次,我们可以在背景中添加随机分布的星星:
-
创建星星的顶点:
function addStars() { const starsGeometry = new THREE.BufferGeometry(); const starsMaterial = new THREE.PointsMaterial({ color: 0xffffff, size: 0.1, }); const starsVertices = []; for (let i = 0; i < 1000; i++) { const x = (Math.random() - 0.5) * 2000; const y = (Math.random() - 0.5) * 2000; const z = (Math.random() - 0.5) * 2000; starsVertices.push(x, y, z); } starsGeometry.setAttribute("position", new THREE.Float32BufferAttribute(starsVertices, 3)); const stars = new THREE.Points(starsGeometry, starsMaterial); scene.add(stars); }
-
调用函数:
addStars();
这样,就会在整个场景范围内分布大量的小点,仿佛一个星空背景。
代码
https://github.com/calmound/threejs-demo/tree/main/line (opens in a new tab)