如何基于四个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轴),再基于这些轴构建旋转信息。以下是具体实现步骤:
- 计算矩形的边向量
从顶点数组中取相邻点,计算出矩形的两个边向量:
const v1 = points[1].subtract(points[0]); // 宽度方向向量 const v2 = points[3].subtract(points[0]); // 深度方向向量
- 计算平面法向量(Box的Z轴)
对两个边向量做叉乘,得到矩形平面的法向量,再归一化:
const normal = BABYLON.Vector3.Cross(v1, v2).normalize();
- 计算Box的右轴(X轴)
将宽度方向的边向量归一化,作为Box的X轴:
const right = v1.normalize();
- 计算Box的上轴(Y轴)
用法向量和右轴叉乘,得到正交的上轴:
const up = BABYLON.Vector3.Cross(normal, right).normalize();
- 构建旋转矩阵并应用到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
相关产品推荐
相关产品推荐

