学习Three.js--曲线(Curve)
前置核心说明
Curve 是 Three.js 中所有曲线/直线的基类,定义了曲线的核心行为(如采样顶点、计算长度等)。所有2D/3D曲线均继承自 Curve,核心作用是「通过数学公式生成连续的顶点序列」,再基于这些顶点创建线条模型,实现任意自定义曲线的绘制。
核心规则
- 维度分类:
- 2D曲线:基于XY平面(Z=0),继承
THREE.Curve,如LineCurve/ArcCurve; - 3D曲线:基于XYZ三维空间,继承
THREE.Curve(部分别名/子类),如LineCurve3/CatmullRomCurve3;
- 2D曲线:基于XY平面(Z=0),继承
- 核心流程:
创建曲线实例 → 采样顶点(getPoints) → 几何体绑定顶点 → 创建线模型 → 添加到场景; - 线模型类型(决定曲线渲染方式):
模型类型 核心特点 适用场景 THREE.Line按顶点顺序绘制连续线条 开放曲线(如直线、贝塞尔曲线) THREE.LineLoop闭合线条(最后一个顶点连接第一个) 封闭曲线(如椭圆、圆) THREE.LineSegments每两个顶点为一组绘制分段线 离散线条(如网格线) - 采样精度:
getPoints(n)中n是采样点数(非顶点数),n越大曲线越平滑(推荐50~100,复杂曲线可设200)。
一、2D曲线(XY平面,Z=0)
所有2D曲线均基于XY平面,Z坐标默认0,核心用于绘制平面曲线。
1. LineCurve(2D直线)
核心说明
两点确定的2D直线,是最简单的2D曲线,无曲率。
构造函数参数
// 语法:new THREE.LineCurve(起点向量, 终点向量)
const lineCurve = new THREE.LineCurve(
new THREE.Vector2(x1, y1), // 必传:起点(Vector2对象)
new THREE.Vector2(x2, y2) // 必传:终点(Vector2对象)
);
| 参数 | 类型 | 说明 |
|---|---|---|
v1 | THREE.Vector2 | 直线起点(XY坐标) |
v2 | THREE.Vector2 | 直线终点(XY坐标) |
使用示例
// 1. 创建2D直线(从(0,0)到(100, 50))
const lineCurve = new THREE.LineCurve(
new THREE.Vector2(0, 0),
new THREE.Vector2(100, 50)
);
// 2. 采样顶点(50个点,直线足够平滑)
const points = lineCurve.getPoints(50);
// 3. 创建几何体并绑定顶点
const geometry = new THREE.BufferGeometry();
geometry.setFromPoints(points);
// 4. 创建线材质
const material = new THREE.LineBasicMaterial({ color: 0xff0000 });
// 5. 创建线模型(开放直线用Line)
const line = new THREE.Line(geometry, material);
scene.add(line);
2. ArcCurve(2D圆弧)
核心说明
基于圆心、半径、起始角/终止角的2D圆弧,可绘制圆、半圆、任意弧度的圆弧。
构造函数参数
// 语法:new THREE.ArcCurve(圆心X, 圆心Y, 半径, 起始角, 终止角, 是否逆时针)
const arcCurve = new THREE.ArcCurve(
0, // 必传:圆心X坐标
0, // 必传:圆心Y坐标
50, // 必传:圆弧半径
0, // 必传:起始角(弧度,0=右向X轴)
Math.PI, // 必传:终止角(弧度,Math.PI=180°)
false // 可选:是否逆时针绘制,默认false(顺时针)
);
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
aX | Number | — | 圆心X坐标 |
aY | Number | — | 圆心Y坐标 |
aRadius | Number | — | 圆弧半径 |
aStartAngle | Number | — | 起始角度(弧度,0=X轴正方向,Math.PI/2=Y轴正方向) |
aEndAngle | Number | — | 终止角度(弧度) |
aClockwise | Boolean | false | 是否顺时针绘制,true=顺时针,false=逆时针 |
使用示例(绘制半圆)
// 1. 创建半圆(圆心(0,0),半径50,0~π弧度)
const arcCurve = new THREE.ArcCurve(0, 0, 50, 0, Math.PI);
// 2. 采样顶点
const points = arcCurve.getPoints(50);
// 3. 几何体+材质+模型
const geometry = new THREE.BufferGeometry();
geometry.setFromPoints(points);
const material = new THREE.LineBasicMaterial({ color: 0x00ff00 });
const line = new THREE.Line(geometry, material);
scene.add(line);
3. EllipseCurve(2D椭圆/圆)
核心说明
基于圆心、长半轴、短半轴的2D椭圆,当长半轴=短半轴时即为圆(替代ArcCurve绘制完整圆)。
构造函数参数
// 语法:new THREE.EllipseCurve(圆心X, 圆心Y, 长半轴, 短半轴, 起始角, 终止角, 是否逆时针, 旋转角)
const ellipseCurve = new THREE.EllipseCurve(
0, // 必传:圆心X坐标
0, // 必传:圆心Y坐标
100, // 必传:X轴方向长半轴
50, // 必传:Y轴方向短半轴
0, // 可选:起始角,默认0
2 * Math.PI,// 可选:终止角,默认2π(完整椭圆)
false, // 可选:是否逆时针,默认false
0 // 可选:椭圆旋转角(弧度),默认0
);
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
aX | Number | — | 圆心X坐标 |
aY | Number | — | 圆心Y坐标 |
xRadius | Number | — | X轴方向半轴长度(长半轴) |
yRadius | Number | — | Y轴方向半轴长度(短半轴) |
aStartAngle | Number | 0 | 起始角度(弧度) |
aEndAngle | Number | 2π | 终止角度(弧度,2π=完整椭圆) |
aClockwise | Boolean | false | 是否顺时针绘制 |
aRotation | Number | 0 | 椭圆整体旋转角度(弧度) |
使用示例(优化版,用户示例升级)
// 1. 创建椭圆(圆心(0,0),长半轴100,短半轴50,完整椭圆)
const ellipseCurve = new THREE.EllipseCurve(0, 0, 100, 50);
// 2. 采样顶点(50个点,椭圆足够平滑)
const points = ellipseCurve.getPoints(50);
// 3. 创建几何体并绑定顶点
const geometry = new THREE.BufferGeometry();
geometry.setFromPoints(points);
// 4. 线材质(红色,线宽1)
const material = new THREE.LineBasicMaterial({
color: 0xff0000,
linewidth: 1 // 注意:WebGL中线宽仅部分浏览器支持>1
});
// 5. 创建闭合线模型(椭圆用LineLoop)
const line = new THREE.LineLoop(geometry, material);
scene.add(line);
4. SplineCurve(2D样条曲线)
核心说明
通过多个控制点生成的平滑2D曲线(插值曲线),曲线会穿过所有控制点,比贝塞尔曲线更易控制。
构造函数参数
// 语法:new THREE.SplineCurve(控制点数组)
const splineCurve = new THREE.SplineCurve([
new THREE.Vector2(x1, y1),
new THREE.Vector2(x2, y2),
// ... 更多控制点
]);
| 参数 | 类型 | 说明 |
|---|---|---|
points | Array<THREE.Vector2> | 必传:2D控制点数组(至少2个,越多曲线越复杂) |
使用示例
// 1. 创建2D样条曲线(4个控制点)
const splineCurve = new THREE.SplineCurve([
new THREE.Vector2(-100, 0), // 控制点1
new THREE.Vector2(-50, 80), // 控制点2
new THREE.Vector2(50, -80), // 控制点3
new THREE.Vector2(100, 0) // 控制点4
]);
// 2. 采样顶点(100个点,保证平滑)
const points = splineCurve.getPoints(100);
// 3. 几何体+材质+模型
const geometry = new THREE.BufferGeometry();
geometry.setFromPoints(points);
const material = new THREE.LineBasicMaterial({ color: 0x0000ff });
const line = new THREE.Line(geometry, material);
scene.add(line);
5. QuadraticBezierCurve(2D二次贝塞尔曲线)
核心说明
由「起点+控制点+终点」3个点定义的2D贝塞尔曲线,单曲率,适合简单弯曲。
构造函数参数
// 语法:new THREE.QuadraticBezierCurve(起点, 控制点, 终点)
const quadBezier = new THREE.QuadraticBezierCurve(
new THREE.Vector2(x1, y1), // 必传:起点
new THREE.Vector2(x2, y2), // 必传:控制点(决定弯曲方向)
new THREE.Vector2(x3, y3) // 必传:终点
);
| 参数 | 类型 | 说明 |
|---|---|---|
v0 | THREE.Vector2 | 起点 |
v1 | THREE.Vector2 | 控制点(核心,决定曲线形状) |
v2 | THREE.Vector2 | 终点 |
使用示例
// 1. 创建二次贝塞尔曲线
const quadBezier = new THREE.QuadraticBezierCurve(
new THREE.Vector2(-80, 0), // 起点
new THREE.Vector2(0, 80), // 控制点(向上弯曲)
new THREE.Vector2(80, 0) // 终点
);
// 2. 采样顶点
const points = quadBezier.getPoints(80);
// 3. 渲染
const geometry = new THREE.BufferGeometry();
geometry.setFromPoints(points);
const material = new THREE.LineBasicMaterial({ color: 0xffff00 });
const line = new THREE.Line(geometry, material);
scene.add(line);
6. CubicBezierCurve(2D三次贝塞尔曲线)
核心说明
由「起点+控制点1+控制点2+终点」4个点定义的2D贝塞尔曲线,双曲率,适合复杂弯曲(如字体轮廓、路径动画)。
构造函数参数
// 语法:new THREE.CubicBezierCurve(起点, 控制点1, 控制点2, 终点)
const cubicBezier = new THREE.CubicBezierCurve(
new THREE.Vector2(x1, y1), // 必传:起点
new THREE.Vector2(x2, y2), // 必传:控制点1
new THREE.Vector2(x3, y3), // 必传:控制点2
new THREE.Vector2(x4, y4) // 必传:终点
);
| 参数 | 类型 | 说明 |
|---|---|---|
v0 | THREE.Vector2 | 起点 |
v1 | THREE.Vector2 | 控制点1(左侧弯曲) |
v2 | THREE.Vector2 | 控制点2(右侧弯曲) |
v3 | THREE.Vector2 | 终点 |
使用示例
// 1. 创建三次贝塞尔曲线
const cubicBezier = new THREE.CubicBezierCurve(
new THREE.Vector2(-100, 0), // 起点
new THREE.Vector2(-50, 100),// 控制点1(向上)
new THREE.Vector2(50, -100),// 控制点2(向下)
new THREE.Vector2(100, 0) // 终点
);
// 2. 采样顶点
const points = cubicBezier.getPoints(100);
// 3. 渲染
const geometry = new THREE.BufferGeometry();
geometry.setFromPoints(points);
const material = new THREE.LineBasicMaterial({ color: 0xff00ff });
const line = new THREE.Line(geometry, material);
scene.add(line);
二、3D曲线(XYZ三维空间)
3D曲线突破XY平面限制,支持XYZ三维坐标,核心用于3D路径(如飞行轨迹、管道模型)。
1. LineCurve3(3D直线)
核心说明
两点确定的3D直线,Z坐标可自定义,是3D最基础的曲线。
构造函数参数
// 语法:new THREE.LineCurve3(起点向量, 终点向量)
const lineCurve3 = new THREE.LineCurve3(
new THREE.Vector3(x1, y1, z1), // 必传:3D起点
new THREE.Vector3(x2, y2, z2) // 必传:3D终点
);
| 参数 | 类型 | 说明 |
|---|---|---|
v1 | THREE.Vector3 | 3D起点(XYZ坐标) |
v2 | THREE.Vector3 | 3D终点(XYZ坐标) |
使用示例
// 1. 创建3D直线(从(0,0,0)到(100, 50, 80))
const lineCurve3 = new THREE.LineCurve3(
new THREE.Vector3(0, 0, 0),
new THREE.Vector3(100, 50, 80)
);
// 2. 采样顶点
const points = lineCurve3.getPoints(50);
// 3. 渲染
const geometry = new THREE.BufferGeometry();
geometry.setFromPoints(points);
const material = new THREE.LineBasicMaterial({ color: 0x00ff00 });
const line = new THREE.Line(geometry, material);
scene.add(line);
2. CatmullRomCurve3(3D样条曲线)
核心说明
Three.js官方推荐的3D样条曲线(替代SplineCurve3),通过多个3D控制点生成平滑曲线,曲线穿过所有控制点,适合3D路径规划。
构造函数参数
// 语法:new THREE.CatmullRomCurve3(控制点数组, 是否闭合, 曲线类型, 张力)
const catmullCurve = new THREE.CatmullRomCurve3(
[
new THREE.Vector3(x1, y1, z1),
new THREE.Vector3(x2, y2, z2),
// ... 更多控制点
],
false, // 可选:是否闭合,默认false
'centripetal',// 可选:曲线类型,默认'centripetal'
0.5 // 可选:张力(0~1),默认0.5,值越大曲线越平缓
);
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
points | Array<THREE.Vector3> | — | 必传:3D控制点数组(至少2个) |
closed | Boolean | false | 是否闭合曲线 |
type | String | 'centripetal' | 曲线类型:'centripetal'(默认,自然)、'chordal'(更紧绷)、'catmullrom'(更平滑) |
tension | Number | 0.5 | 张力(0=无张力,1=最大张力) |
使用示例
// 1. 创建3D样条曲线(4个控制点,空间弯曲)
const catmullCurve = new THREE.CatmullRomCurve3([
new THREE.Vector3(-100, 0, 0), // 控制点1
new THREE.Vector3(-50, 80, 50), // 控制点2
new THREE.Vector3(50, -80, 100), // 控制点3
new THREE.Vector3(100, 0, 50) // 控制点4
]);
// 2. 采样顶点(100个点,保证3D平滑)
const points = catmullCurve.getPoints(100);
// 3. 渲染
const geometry = new THREE.BufferGeometry();
geometry.setFromPoints(points);
const material = new THREE.LineBasicMaterial({ color: 0x0000ff });
const line = new THREE.Line(geometry, material);
scene.add(line);
3. QuadraticBezierCurve3(3D二次贝塞尔曲线)
核心说明
3D版本的二次贝塞尔曲线,由「3D起点+3D控制点+3D终点」定义,支持空间弯曲。
构造函数参数
// 语法:new THREE.QuadraticBezierCurve3(起点, 控制点, 终点)
const quadBezier3 = new THREE.QuadraticBezierCurve3(
new THREE.Vector3(x1, y1, z1), // 必传:3D起点
new THREE.Vector3(x2, y2, z2), // 必传:3D控制点
new THREE.Vector3(x3, y3, z3) // 必传:3D终点
);
| 参数 | 类型 | 说明 |
|---|---|---|
v0 | THREE.Vector3 | 3D起点 |
v1 | THREE.Vector3 | 3D控制点(决定空间弯曲方向) |
v2 | THREE.Vector3 | 3D终点 |
使用示例
// 1. 创建3D二次贝塞尔曲线
const quadBezier3 = new THREE.QuadraticBezierCurve3(
new THREE.Vector3(-80, 0, 0), // 起点
new THREE.Vector3(0, 80, 50), // 控制点(Z轴偏移)
new THREE.Vector3(80, 0, 100) // 终点
);
// 2. 采样顶点
const points = quadBezier3.getPoints(80);
// 3. 渲染
const geometry = new THREE.BufferGeometry();
geometry.setFromPoints(points);
const material = new THREE.LineBasicMaterial({ color: 0xffff00 });
const line = new THREE.Line(geometry, material);
scene.add(line);
4. CubicBezierCurve3(3D三次贝塞尔曲线)
核心说明
3D版本的三次贝塞尔曲线,由4个3D点定义,支持复杂空间弯曲,是3D路径动画的核心曲线。
构造函数参数
// 语法:new THREE.CubicBezierCurve3(起点, 控制点1, 控制点2, 终点)
const cubicBezier3 = new THREE.CubicBezierCurve3(
new THREE.Vector3(x1, y1, z1), // 必传:3D起点
new THREE.Vector3(x2, y2, z2), // 必传:3D控制点1
new THREE.Vector3(x3, y3, z3), // 必传:3D控制点2
new THREE.Vector3(x4, y4, z4) // 必传:3D终点
);
| 参数 | 类型 | 说明 |
|---|---|---|
v0 | THREE.Vector3 | 3D起点 |
v1 | THREE.Vector3 | 3D控制点1 |
v2 | THREE.Vector3 | 3D控制点2 |
v3 | THREE.Vector3 | 3D终点 |
使用示例
// 1. 创建3D三次贝塞尔曲线
const cubicBezier3 = new THREE.CubicBezierCurve3(
new THREE.Vector3(-100, 0, 0), // 起点
new THREE.Vector3(-50, 100, 50),// 控制点1
new THREE.Vector3(50, -100, 80),// 控制点2
new THREE.Vector3(100, 0, 100) // 终点
);
// 2. 采样顶点
const points = cubicBezier3.getPoints(100);
// 3. 渲染
const geometry = new THREE.BufferGeometry();
geometry.setFromPoints(points);
const material = new THREE.LineBasicMaterial({ color: 0xff00ff });
const line = new THREE.Line(geometry, material);
scene.add(line);
三、CurvePath(组合曲线)
核心说明
CurvePath 是「曲线容器」,可将多个2D/3D曲线组合成一个复合曲线,支持统一采样、平移、旋转等操作,适合绘制复杂路径(如迷宫、文字轮廓)。
核心方法
| 方法名 | 说明 | 示例 |
|---|---|---|
add(curve) | 添加单个曲线到容器 | curvePath.add(lineCurve) |
getPoints(n) | 统一采样所有曲线的顶点 | curvePath.getPoints(100) |
closePath() | 闭合组合曲线(最后一个曲线终点连接第一个曲线起点) | curvePath.closePath() |
使用示例(组合2D直线+圆弧)
// 1. 创建CurvePath容器
const curvePath = new THREE.CurvePath();
// 2. 添加子曲线(直线+圆弧)
// 子曲线1:2D直线(从(0,0)到(100,0))
const lineCurve = new THREE.LineCurve(
new THREE.Vector2(0, 0),
new THREE.Vector2(100, 0)
);
curvePath.add(lineCurve);
// 子曲线2:圆弧(从(100,0)到(100,100),90°圆弧)
const arcCurve = new THREE.ArcCurve(
100, 0, 100, 0, Math.PI/2, true
);
curvePath.add(arcCurve);
// 3. 闭合曲线(可选)
// curvePath.closePath();
// 4. 统一采样顶点(100个点)
const points = curvePath.getPoints(100);
// 5. 渲染组合曲线
const geometry = new THREE.BufferGeometry();
geometry.setFromPoints(points);
const material = new THREE.LineBasicMaterial({ color: 0xff6600 });
const line = new THREE.Line(geometry, material);
scene.add(line);
四、完整实战示例(多曲线组合)
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Three.js 曲线完整示例</title>
<style>body { margin: 0; overflow: hidden; }</style>
</head>
<body>
<script type="module">
// 地址,升级为174版本
import * as THREE from 'https://esm.sh/three@0.174.0';
import { OrbitControls } from 'https://esm.sh/three@0.174.0/examples/jsm/controls/OrbitControls.js';
import { GLTFLoader } from 'https://esm.sh/three@0.174.0/examples/jsm/loaders/GLTFLoader.js';
// 1. 创建三大核心
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth/window.innerHeight, 0.1, 1000);
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
camera.position.set(0, 0, 300); // 相机后退,看清所有曲线
// 2. 轨道控制器(3D视角交互)
const controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;
controls.dampingFactor = 0.05;
// 3. 绘制2D椭圆
const ellipseCurve = new THREE.EllipseCurve(0, 0, 80, 40);
const ellipsePoints = ellipseCurve.getPoints(50);
const ellipseGeo = new THREE.BufferGeometry();
ellipseGeo.setFromPoints(ellipsePoints);
const ellipseMat = new THREE.LineBasicMaterial({ color: 0xff0000 });
const ellipseLine = new THREE.LineLoop(ellipseGeo, ellipseMat);
scene.add(ellipseLine);
// 4. 绘制3D样条曲线
const catmullCurve = new THREE.CatmullRomCurve3([
new THREE.Vector3(-100, 0, 0),
new THREE.Vector3(-50, 80, 50),
new THREE.Vector3(50, -80, 100),
new THREE.Vector3(100, 0, 50)
]);
const catmullPoints = catmullCurve.getPoints(100);
const catmullGeo = new THREE.BufferGeometry();
catmullGeo.setFromPoints(catmullPoints);
const catmullMat = new THREE.LineBasicMaterial({ color: 0x0000ff });
const catmullLine = new THREE.Line(catmullGeo, catmullMat);
scene.add(catmullLine);
// 5. 动画循环
function animate() {
requestAnimationFrame(animate);
controls.update();
renderer.render(scene, camera);
}
animate();
// 6. 窗口适配
window.addEventListener('resize', () => {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
});
</script>
</body>
</html>
示例效果
- 场景中显示红色2D椭圆(XY平面)和蓝色3D样条曲线(空间弯曲);
- 支持鼠标旋转/缩放视角,查看3D曲线的空间形态;
- 曲线平滑无锯齿,色彩无偏色。
五、注意事项与优化
1. 常见坑点
- 线宽限制:WebGL标准中线宽(
linewidth)仅支持1px,部分浏览器支持>1但兼容性差,如需粗线条建议用Mesh模拟(如挤压曲线成面); - 3D曲线视角:3D曲线需调整相机位置(Z轴后退),否则可能看不到;
- 采样点数:复杂曲线(如三次贝塞尔)需增加采样点数(100~200),否则会出现锯齿;
- CurvePath闭合:
closePath()仅对2D曲线有效,3D曲线闭合需手动调整控制点。
2. 性能优化
- 复用几何体:多个曲线复用同一个
BufferGeometry(清空顶点后重新绑定); - 减少采样点数:简单曲线(直线、圆弧)采样点数设50即可,无需过高;
- 批量渲染:多个曲线合并为一个
Line模型,减少渲染调用。
核心总结
- 核心流程:
创建曲线 → getPoints采样顶点 → 几何体绑定顶点 → Line/LineLoop渲染; - 曲线选型:
- 2D简单曲线:LineCurve/ArcCurve/EllipseCurve;
- 2D复杂曲线:SplineCurve/CubicBezierCurve;
- 3D路径:CatmullRomCurve3(推荐)/CubicBezierCurve3;
- 复合曲线:CurvePath(组合多个子曲线);
- 关键参数:
getPoints(n)中n决定平滑度,推荐50~100;- 3D曲线需调整相机Z轴位置,确保可见;
- 贝塞尔曲线的「控制点」是决定曲线形状的核心。