概述
本文将详细介绍如何使用 Three.js 中的曲线功能。我们将学习如何创建 CatmullRomCurve3 样条曲线,并利用曲线来控制物体的运动轨迹,以及如何将曲线可视化地显示在场景中。
准备工作
首先,我们需要引入必要的 Three.js 库:
import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
场景初始化
首先,我们需要创建一个基本的 Three.js 场景:
let camera, scene, renderer;
const clock = new THREE.Clock();
const textureLoader = new THREE.TextureLoader();
let moon;
let earth;
let curve;
const raycaster = new THREE.Raycaster();
function init() {
const EARTH_RADIUS = 1;
const MOON_RADIUS = 0.27;
// 创建透视相机
camera = new THREE.PerspectiveCamera(
45,
window.innerWidth / window.innerHeight,
1,
200
);
camera.position.set(0, 5, -10);
// 初始化场景
scene = new THREE.Scene();
}
光照设置
添加适当的光照使场景更真实:
// 方向光
const dirLight = new THREE.DirectionalLight(0xffffff);
dirLight.position.set(0, 0, -1);
scene.add(dirLight);
// 环境光
const light = new THREE.AmbientLight(0xffffff, 0.5); // soft white light
scene.add(light);
创建地球和月球模型
使用纹理贴图创建地球和月球模型:
// 创建地球
const earthGeometry = new THREE.SphereGeometry(EARTH_RADIUS, 16, 16);
const earthMaterial = new THREE.MeshPhongMaterial({
specular: 0x333333,
shininess: 5,
map: textureLoader.load("textures/planets/earth_atmos_2048.jpg"),
specularMap: textureLoader.load("textures/planets/earth_specular_2048.jpg"),
normalMap: textureLoader.load("textures/planets/earth_normal_2048.jpg"),
normalScale: new THREE.Vector2(0.85, 0.85),
});
earth = new THREE.Mesh(earthGeometry, earthMaterial);
scene.add(earth);
// 创建月球
const moonGeometry = new THREE.SphereGeometry(MOON_RADIUS, 16, 16);
const moonMaterial = new THREE.MeshPhongMaterial({
shininess: 5,
map: textureLoader.load("textures/planets/moon_1024.jpg"),
});
moon = new THREE.Mesh(moonGeometry, moonMaterial);
scene.add(moon);
创建 CatmullRomCurve3 曲线
这是关键部分,我们使用一系列点来创建平滑的 CatmullRomCurve3 样条曲线:
// 根据这一系列的点创建闭合曲线
curve = new THREE.CatmullRomCurve3(
[
new THREE.Vector3(-10, 0, 10), // 起始点
new THREE.Vector3(-5, 5, 5), // 控制点1
new THREE.Vector3(0, 0, 5), // 控制点2
new THREE.Vector3(5, -5, 5), // 控制点3
new THREE.Vector3(10, 0, 10), // 结束点
],
true // true 表示创建闭合曲线,false 表示开放曲线
);
CatmullRomCurve3 曲线是一种样条曲线,它会经过所有的控制点,形成平滑的路径。参数 true 表示创建闭合曲线,即曲线的终点会连接到起点。
可视化曲线
将曲线可视化地显示在场景中:
// 在曲线里,getPoints获取501个点(500个分段+1)
const points = curve.getPoints(500);
console.log(points);
const geometry = new THREE.BufferGeometry().setFromPoints(points);
const material = new THREE.LineBasicMaterial({ color: 0xff0000 });
// 创建线条对象并添加到场景
const curveObject = new THREE.Line(geometry, material);
scene.add(curveObject);
getPoints(divisions) 方法会沿着曲线均匀地采样指定数量的点。在这里,我们使用 500 个分段,因此会得到 501 个点(包括起始点和结束点)。这样可以确保曲线看起来平滑流畅。
渲染器和控制器设置
设置渲染器和控制器:
renderer = new THREE.WebGLRenderer();
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
const controls = new OrbitControls(camera, renderer.domElement);
controls.minDistance = 5;
controls.maxDistance = 100;
动画循环与曲线运动
在动画循环中,我们让月球沿着曲线运动,同时相机也跟随曲线:
function animate() {
requestAnimationFrame(animate);
const elapsed = clock.getElapsedTime();
// 计算归一化的时间参数(0到1之间)
const time = elapsed/10 % 1;
// 根据时间参数获取曲线上对应的点
const point = curve.getPoint(time);
// 将月球位置设置为曲线上当前点的位置
moon.position.copy(point);
// 相机也跟随曲线运动
camera.position.copy(point);
// 相机始终看向地球位置
camera.lookAt(earth.position)
// 渲染场景
renderer.render(scene, camera);
}
getPoint(t) 方法用于获取曲线上特定参数位置的点,其中 t 是一个介于 0 和 1 之间的值。当 t=0 时,返回曲线的起始点;当 t=1 时,返回曲线的结束点(在闭合曲线的情况下,这与起始点相同)。
曲线类型详解
Three.js 提供了多种曲线类型:
- CatmullRomCurve3: 经过所有控制点的三次样条曲线
- CubicBezierCurve3: 三次贝塞尔曲线
- QuadraticBezierCurve3: 二次贝塞尔曲线
- LineCurve3: 直线段
CatmullRomCurve3 曲线参数
CatmullRomCurve3 曲线构造函数接受以下参数:
new THREE.CatmullRomCurve3(points, closed, curveType, tension)
points: Vector3 类型的数组,定义曲线经过的点closed: Boolean 类型,是否闭合曲线curveType: String 类型,默认为 "centripetal",还有 "chordal" 和 "catmullrom"tension: Number 类型,张力参数,默认为 0.5,值越大曲线越紧绷
应用场景
曲线在 Three.js 中有多种应用场景:
- 路径动画: 让物体沿着预设路径运动
- 摄像机动画: 让摄像机沿着路径移动,创建电影般的镜头效果
- 地形生成: 使用曲线生成平滑的地形轮廓
- 粒子系统: 控制粒子的运动轨迹
- UI 动画: 创建复杂的 UI 动画效果
总结
通过这个项目,我们学习了如何使用 Three.js 的曲线功能:
- 如何创建 CatmullRomCurve3 样条曲线
- 如何将曲线可视化显示在场景中
- 如何让物体沿着曲线运动
- 如何控制动画的时间参数
- 曲线在 3D 应用中的多种用途
曲线是 Three.js 中一个非常强大的功能,它可以让我们创建流畅的动画和复杂的路径效果,为我们的 3D 应用增添更多的动态美感。