BabylonJS - Curve3
Babylon.js - Curve3
Section titled “Babylon.js - Curve3”BABYLON.Curve3 类提供了静态方法,用于基于各种数学样条曲线算法在 3D 空间中创建平滑曲线。这些生成的曲线本质上是按顺序排列的 Vector3 点数组,然后可以用作其他 MeshBuilder 方法(如 CreateLines、CreateTube 或 CreateRibbon)的路径,或用于沿着曲线移动物体进行动画。
使用 Curve3 可以避免手动计算平滑曲线所需的大量中间点,从而简化了复杂路径的创建过程。
常用曲线类型
Section titled “常用曲线类型”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();3. 赫米特样条曲线 (Hermite Spline)
Section titled “3. 赫米特样条曲线 (Hermite Spline)”由起始点、终点以及在起始点和终点处的切线向量定义。切线控制曲线离开起始点和到达终点的方向。
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();演示:可视化不同曲线
Section titled “演示:可视化不同曲线”此演示创建并显示了上述四种曲线类型的线条,并使用辅助函数显示坐标轴和标签以便参考。
<!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 样条曲线经过的控制点。这使你可以直观地比较每种算法生成的曲线形状。