You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何基于四个Vector3点计算Babylon.js中Box网格的旋转角度?

问题:基于矩形顶点创建匹配旋转的Box网格

我刚接触3D空间与旋转相关开发,手里有一组代表矩形顶点的四个Vector3点,想要基于这些点创建一个Box网格,让它的旋转角度和这个矩形完全匹配。

我已经绘制了连接这些点的线条网格,矩形呈现出预期角度;同时创建了Box网格,配置了匹配的尺寸并将其中心点置于矩形中心,但不知道怎么设置旋转,让Box的顶面和矩形面保持平行。

原始代码:

var createScene = function () {
    // This creates a basic Babylon Scene object (non-mesh)
    var scene = new BABYLON.Scene(engine);
    // This creates and positions a free camera (non-mesh)
    var target = new BABYLON.Vector3(1.5, 4, 0)
    var camera = new BABYLON.ArcRotateCamera("camera1", Math.PI / 2 + Math.PI, Math.PI / 4, 10, target, scene)
    // This attaches the camera to the canvas
    camera.attachControl(canvas, true);
    // This creates a light, aiming 0,1,0 - to the sky (non-mesh)
    var light = new BABYLON.HemisphericLight("light", new BABYLON.Vector3(0, 1, 0), scene);
    // Default intensity is 1. Let's dim the light a small amount
    light.intensity = 0.7;

    const axes = new BABYLON.AxesViewer(scene)

    const points = [
        new BABYLON.Vector3(1, 5, 1),
        new BABYLON.Vector3(2, 5, 1),
        new BABYLON.Vector3(2, 3, -1),
        new BABYLON.Vector3(1, 3, -1)
    ]

    const lines = BABYLON.MeshBuilder.CreateLines("lines", {
        points: [...points, points[0]] // add a duplicate of first point to close polygon
    }, scene)

    const centerPoint = new BABYLON.Vector3(
        (points[0].x + points[1].x + points[2].x + points[3].x) / 4,
        (points[0].y + points[1].y + points[2].y + points[3].y) / 4,
        (points[0].z + points[1].z + points[2].z + points[3].z) / 4
    )

    const width = Math.sqrt(
      Math.pow(points[1].x - points[0].x, 2) +
      Math.pow(points[1].y - points[0].y, 2) +
      Math.pow(points[1].z - points[0].z, 2)
    )

    const depth = Math.sqrt(
      Math.pow(points[2].x - points[1].x, 2) +
      Math.pow(points[2].y - points[1].y, 2) +
      Math.pow(points[2].z - points[1].z, 2)
    )

    const height = 0.15

    const box = BABYLON.CreateBox("box", { width, height, depth}, scene)
    box.position = centerPoint
    //box.rotation = ???

    return scene;
};

解决方案

要让Box与矩形面平行,核心是计算出矩形所在平面的三个正交轴(对应Box的X、Y、Z轴),再基于这些轴构建旋转信息。以下是具体实现步骤:

  1. 计算矩形的边向量
    从顶点数组中取相邻点,计算出矩形的两个边向量:
const v1 = points[1].subtract(points[0]); // 宽度方向向量
const v2 = points[3].subtract(points[0]); // 深度方向向量
  1. 计算平面法向量(Box的Z轴)
    对两个边向量做叉乘,得到矩形平面的法向量,再归一化:
const normal = BABYLON.Vector3.Cross(v1, v2).normalize();
  1. 计算Box的右轴(X轴)
    将宽度方向的边向量归一化,作为Box的X轴:
const right = v1.normalize();
  1. 计算Box的上轴(Y轴)
    用法向量和右轴叉乘,得到正交的上轴:
const up = BABYLON.Vector3.Cross(normal, right).normalize();
  1. 构建旋转矩阵并应用到Box
    用三个轴构建旋转矩阵,转换为四元数后赋值给Box(四元数比欧拉角更稳定,避免万向锁问题):
const rotationMatrix = BABYLON.Matrix.FromColumns(right, up, normal);
box.rotationQuaternion = BABYLON.Quaternion.FromRotationMatrix(rotationMatrix);

修改后的完整代码

var createScene = function () {
    var scene = new BABYLON.Scene(engine);
    var target = new BABYLON.Vector3(1.5, 4, 0)
    var camera = new BABYLON.ArcRotateCamera("camera1", Math.PI / 2 + Math.PI, Math.PI / 4, 10, target, scene)
    camera.attachControl(canvas, true);
    var light = new BABYLON.HemisphericLight("light", new BABYLON.Vector3(0, 1, 0), scene);
    light.intensity = 0.7;

    const axes = new BABYLON.AxesViewer(scene)

    const points = [
        new BABYLON.Vector3(1, 5, 1),
        new BABYLON.Vector3(2, 5, 1),
        new BABYLON.Vector3(2, 3, -1),
        new BABYLON.Vector3(1, 3, -1)
    ]

    const lines = BABYLON.MeshBuilder.CreateLines("lines", {
        points: [...points, points[0]]
    }, scene)

    const centerPoint = new BABYLON.Vector3(
        (points[0].x + points[1].x + points[2].x + points[3].x) / 4,
        (points[0].y + points[1].y + points[2].y + points[3].y) / 4,
        (points[0].z + points[1].z + points[2].z + points[3].z) / 4
    )

    const width = Math.sqrt(
      Math.pow(points[1].x - points[0].x, 2) +
      Math.pow(points[1].y - points[0].y, 2) +
      Math.pow(points[1].z - points[0].z, 2)
    )

    const depth = Math.sqrt(
      Math.pow(points[2].x - points[1].x, 2) +
      Math.pow(points[2].y - points[1].y, 2) +
      Math.pow(points[2].z - points[1].z, 2)
    )

    const height = 0.15

    const box = BABYLON.CreateBox("box", { width, height, depth}, scene)
    box.position = centerPoint

    // 计算旋转相关向量
    const v1 = points[1].subtract(points[0]);
    const v2 = points[3].subtract(points[0]);
    const normal = BABYLON.Vector3.Cross(v1, v2).normalize();
    const right = v1.normalize();
    const up = BABYLON.Vector3.Cross(normal, right).normalize();

    // 构建旋转矩阵并设置四元数
    const rotationMatrix = BABYLON.Matrix.FromColumns(right, up, normal);
    box.rotationQuaternion = BABYLON.Quaternion.FromRotationMatrix(rotationMatrix);

    return scene;
};

内容的提问来源于stack exchange,提问作者ChevCast

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 09:55:16