Skip to content

BabylonJS - Curve3

BABYLON.Curve3 类提供了静态方法,用于基于各种数学样条曲线算法在 3D 空间中创建平滑曲线。这些生成的曲线本质上是按顺序排列的 Vector3 点数组,然后可以用作其他 MeshBuilder 方法(如 CreateLines、CreateTube 或 CreateRibbon)的路径,或用于沿着曲线移动物体进行动画。

使用 Curve3 可以避免手动计算平滑曲线所需的大量中间点,从而简化了复杂路径的创建过程。

1. 二次贝塞尔曲线 (Quadratic Bezier Curve)

Section titled “1. 二次贝塞尔曲线 (Quadratic Bezier Curve)”

一种简单的曲线,由三个点定义:一个起始点、一个终点和一个控制点,控制点将曲线拉向自身。

const startPoint = new BABYLON.Vector3(0, 0, 0);
const controlPoint = new BABYLON.Vector3(5, 5, 0);
const endPoint = new BABYLON.Vector3(10, 0, 0);
const numberOfPoints = 20; // 沿曲线生成的点数
const quadraticBezierCurve = BABYLON.Curve3.CreateQuadraticBezier(
startPoint,
controlPoint,
endPoint,
numberOfPoints
);
// 获取 Vector3 点数组
const pointsArray = quadraticBezierCurve.getPoints();
// 示例:使用 CreateLines 绘制曲线
const lineMesh = BABYLON.MeshBuilder.CreateLines("qBezierLine", { points: pointsArray }, scene);
lineMesh.color = BABYLON.Color3.Red();

2. 三次贝塞尔曲线 (Cubic Bezier Curve)

Section titled “2. 三次贝塞尔曲线 (Cubic Bezier Curve)”

一种更通用的曲线,由四个点定义:一个起始点、一个终点和两个控制点,分别影响曲线在起始点和终点处的形状。

const startPoint = new BABYLON.Vector3(0, 0, 0);
const controlPoint1 = new BABYLON.Vector3(2, 8, 2);
const controlPoint2 = new BABYLON.Vector3(8, 8, -2);
const endPoint = new BABYLON.Vector3(10, 0, 0);
const numberOfPoints = 30; // 点数
const cubicBezierCurve = BABYLON.Curve3.CreateCubicBezier(
startPoint,
controlPoint1,
controlPoint2,
endPoint,
numberOfPoints
);
const pointsArray = cubicBezierCurve.getPoints();
const lineMesh = BABYLON.MeshBuilder.CreateLines("cBezierLine", { points: pointsArray }, scene);
lineMesh.color = BABYLON.Color3.Green();

由起始点、终点以及在起始点和终点处的切线向量定义。切线控制曲线离开起始点和到达终点的方向。

const startPoint = new BABYLON.Vector3(0, 0, 0);
const startTangent = new BABYLON.Vector3(5, 5, 0); // 从起始点离开的方向
const endPoint = new BABYLON.Vector3(10, 0, 5);
const endTangent = new BABYLON.Vector3(5, -5, 0); // 到达终点的方向
const numberOfPoints = 25; // 点数
const hermiteSpline = BABYLON.Curve3.CreateHermiteSpline(
startPoint,
startTangent,
endPoint,
endTangent,
numberOfPoints
);
const pointsArray = hermiteSpline.getPoints();
const lineMesh = BABYLON.MeshBuilder.CreateLines("hermiteLine", { points: pointsArray }, scene);
lineMesh.color = BABYLON.Color3.Blue();

4. Catmull-Rom 样条曲线 (Catmull-Rom Spline)

Section titled “4. Catmull-Rom 样条曲线 (Catmull-Rom Spline)”

创建一条经过给定控制点序列的平滑曲线。当你已知路径必须经过的几个点时,这非常有用。

const controlPoints = [
new BABYLON.Vector3(-5, 0, 0),
new BABYLON.Vector3(0, 5, 2),
new BABYLON.Vector3(5, 0, -2),
new BABYLON.Vector3(10, 5, 0),
new BABYLON.Vector3(15, 0, 0)
];
const pointsPerSegment = 10; // 在每个控制点之间生成的点数
const catmullRomSpline = BABYLON.Curve3.CreateCatmullRomSpline(
controlPoints,
pointsPerSegment
);
const pointsArray = catmullRomSpline.getPoints();
const lineMesh = BABYLON.MeshBuilder.CreateLines("catmullRomLine", { points: pointsArray }, scene);
lineMesh.color = BABYLON.Color3.Yellow();
// 获取曲线长度
const curveLength = catmullRomSpline.length();
console.log("Catmull-Rom curve length:", curveLength);

你可以使用 continue() 方法将不同的曲线段连接起来。

// 假设 quadraticBezierCurve 和 cubicBezierCurve 是已定义的 Curve3 对象
const combinedCurve = quadraticBezierCurve.continue(cubicBezierCurve);
const combinedPoints = combinedCurve.getPoints();
const combinedLine = BABYLON.MeshBuilder.CreateLines("combined", { points: combinedPoints }, scene);
combinedLine.color = BABYLON.Color3.Magenta();

此演示创建并显示了上述四种曲线类型的线条,并使用辅助函数显示坐标轴和标签以便参考。

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<title>Babylon.js - Curve3 Demo</title>
<script src="https://cdn.babylonjs.com/babylon.js"></script>
<style>
html, body { overflow: hidden; width: 100%; height: 100%; margin: 0; padding: 0; }
#renderCanvas { width: 100%; height: 100%; touch-action: none; }
</style>
</head>
<body>
<canvas id="renderCanvas"></canvas>
<script type="text/javascript">
const canvas = document.getElementById("renderCanvas");
const engine = new BABYLON.Engine(canvas, true);
// 创建文本标签的辅助函数
const makeTextPlane = function (text, color, size, scene) {
const dynamicTexture = new BABYLON.DynamicTexture("DynamicTexture" + text, {width: text.length * 20 + 10, height: 70}, scene, true);
dynamicTexture.hasAlpha = true;
dynamicTexture.drawText(text, null, 50, "bold 36px Arial", color, "transparent", true);
const plane = BABYLON.MeshBuilder.CreatePlane("TextPlane" + text, {size: size}, scene, true);
plane.material = new BABYLON.StandardMaterial("TextPlaneMaterial" + text, scene);
plane.material.backFaceCulling = false;
plane.material.specularColor = new BABYLON.Color3(0, 0, 0);
plane.material.diffuseTexture = dynamicTexture;
plane.material.useAlphaFromDiffuseTexture = true;
return plane;
};
// 显示坐标轴的辅助函数
const showAxis = function(size, scene) {
const axisX = BABYLON.MeshBuilder.CreateLines("axisX", { points: [ new BABYLON.Vector3.Zero(), new BABYLON.Vector3(size, 0, 0)] }, scene);
axisX.color = new BABYLON.Color3(1, 0, 0);
const xChar = makeTextPlane("X", "red", size / 10, scene);
xChar.position = new BABYLON.Vector3(0.9 * size, 0.05 * size, 0);
const axisY = BABYLON.MeshBuilder.CreateLines("axisY", { points: [ new BABYLON.Vector3.Zero(), new BABYLON.Vector3(0, size, 0)] }, scene);
axisY.color = new BABYLON.Color3(0, 1, 0);
const yChar = makeTextPlane("Y", "green", size / 10, scene);
yChar.position = new BABYLON.Vector3(0, 0.9 * size, -0.05 * size);
const axisZ = BABYLON.MeshBuilder.CreateLines("axisZ", { points: [ new BABYLON.Vector3.Zero(), new BABYLON.Vector3(0, 0, size)] }, scene);
axisZ.color = new BABYLON.Color3(0, 0, 1);
const zChar = makeTextPlane("Z", "blue", size / 10, scene);
zChar.position = new BABYLON.Vector3(0, 0.05 * size, 0.9 * size);
};
const createScene = function () {
const scene = new BABYLON.Scene(engine);
scene.clearColor = new BABYLON.Color4(0.2, 0.2, 0.2, 1.0);
const camera = new BABYLON.ArcRotateCamera("camera1", Math.PI / 4, Math.PI / 3, 30, new BABYLON.Vector3(5, 3, 0), scene);
camera.attachControl(canvas, true);
camera.wheelPrecision = 50;
const light = new BABYLON.HemisphericLight("light1", new BABYLON.Vector3(0, 1, 0), scene);
light.intensity = 0.8;
showAxis(10, scene);
// --- 定义和绘制曲线 ---
// 1. 二次贝塞尔 (红色)
const qbCurve = BABYLON.Curve3.CreateQuadraticBezier(
new BABYLON.Vector3(0, 0, 0), new BABYLON.Vector3(5, 8, -2), new BABYLON.Vector3(10, 0, 0), 20);
const qbLine = BABYLON.MeshBuilder.CreateLines("qBezier", { points: qbCurve.getPoints() }, scene);
qbLine.color = new BABYLON.Color3(1, 0.2, 0.2);
// 2. 三次贝塞尔 (绿色)
const cbCurve = BABYLON.Curve3.CreateCubicBezier(
new BABYLON.Vector3(-5, 0, 5), new BABYLON.Vector3(-2, 8, 3), new BABYLON.Vector3(5, 8, -3), new BABYLON.Vector3(10, 0, 5), 30);
const cbLine = BABYLON.MeshBuilder.CreateLines("cBezier", { points: cbCurve.getPoints() }, scene);
cbLine.color = new BABYLON.Color3(0.2, 1, 0.2);
// 3. 赫米特样条曲线 (蓝色)
const hsCurve = BABYLON.Curve3.CreateHermiteSpline(
new BABYLON.Vector3(-8, 0, -5), new BABYLON.Vector3(0, 10, 0),
new BABYLON.Vector3(8, 0, -5), new BABYLON.Vector3(0, -10, 10), 25);
const hsLine = BABYLON.MeshBuilder.CreateLines("hermite", { points: hsCurve.getPoints() }, scene);
hsLine.color = new BABYLON.Color3(0.2, 0.2, 1);
// 4. Catmull-Rom 样条曲线 (黄色)
const crPoints = [ new BABYLON.Vector3(-10, -2, 8), new BABYLON.Vector3(-5, 3, -3), new BABYLON.Vector3(0, -2, 5), new BABYLON.Vector3(5, 3, -6), new BABYLON.Vector3(10, -2, 8) ];
const crCurve = BABYLON.Curve3.CreateCatmullRomSpline(crPoints, 10);
const crLine = BABYLON.MeshBuilder.CreateLines("catmullRom", { points: crCurve.getPoints() }, scene);
crLine.color = new BABYLON.Color3(1, 1, 0.2);
// 标记 Catmull-Rom 控制点
crPoints.forEach((p, i) => {
const marker = BABYLON.MeshBuilder.CreateSphere(`crp_${i}`, {diameter: 0.3}, scene);
marker.position = p;
const markerMat = new BABYLON.StandardMaterial(`crpMat_${i}`, scene);
markerMat.emissiveColor = new BABYLON.Color3(1, 1, 0.2);
marker.material = markerMat;
});
// -----------------------------
return scene;
};
const scene = createScene();
engine.runRenderLoop(function () { scene.render(); });
window.addEventListener("resize", function () { engine.resize(); });
</script>
</body>
</html>

演示显示了一个 3D 坐标系(带标签的 XYZ 轴)。绘制了几条彩色的线条,代表不同类型的曲线:一条红色二次贝塞尔曲线、一条绿色三次贝塞尔曲线、一条蓝色赫米特样条曲线和一条黄色 Catmull-Rom 样条曲线。小的黄色球体标记了 Catmull-Rom 样条曲线经过的控制点。这使你可以直观地比较每种算法生成的曲线形状。