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

使用Quaternion旋转模型时如何防止模型侧滚?

解决Three.js模型旋转侧滚问题

要避免模型旋转时出现侧滚,核心是约束模型的额外旋转自由度——仅让模型的前方向(原Z轴)指向目标方向,同时固定模型的局部向上轴(原Y轴)的朝向,避免绕目标方向的扭转。

原代码中q.setFromUnitVectors(vB, vC)仅保证前方向对齐,但模型的其他轴旋转是自由的,这就是侧滚的原因。以下是两种可行的解决方案:

方法一:手动构造正交轴系(更可控)

通过构建正交的三个轴(右、上、前)来定义旋转,确保模型向上轴保持与原向上方向的正交投影一致:

//Box natural direction
let vB = new THREE.Vector3(0, 0, 1);
// 模型原始向上方向(原Y轴)
let upB = new THREE.Vector3(0, 1, 0);

//Cable direction
let vC = new THREE.Vector3(1, 1, 0).normalize();

// 构造无侧滚的旋转轴系
const forward = vC.clone();
// 计算右轴:前方向叉乘原向上方向,确保正交
const right = new THREE.Vector3().crossVectors(forward, upB).normalize();
// 处理前方向与原向上方向平行的极端情况
if (right.lengthSq() < 0.0001) {
    right.set(1, 0, 0).cross(forward).normalize();
}
// 计算正交的向上轴:右轴叉乘前方向
const up = new THREE.Vector3().crossVectors(right, forward).normalize();

// 从轴系生成旋转矩阵,再转成四元数
const rotationMatrix = new THREE.Matrix4().makeBasis(right, up, forward);
let q = new THREE.Quaternion().setFromRotationMatrix(rotationMatrix);

// 后续模型应用代码不变
const boxG = new THREE.BoxGeometry(4, 8, 10);           
const boxM = new THREE.Mesh(boxG, matSS);

const conG = new THREE.CylinderGeometry(0.5, 0.5, 2, 16);
conG.rotateX(Math.PI / 2);

const conM = new THREE.Mesh(conG, matSS);
conM.translateZ(5);
boxM.applyQuaternion(q);            
boxM.add(conM);
scene.add(boxM);

//Cable to connect
const cabG = new THREE.CylinderGeometry(0.25, 0.25, 100, 16);
cabG.rotateX(Math.PI / 2);
const cabM = new THREE.Mesh(cabG, matBL);
const cabP = vC.clone().setLength(50);
cabM.applyQuaternion(q);
cabM.position.set(cabP.x,cabP.y,cabP.z);
   
scene.add(cabM);

方法二:使用lookAt矩阵(更简洁)

利用Three.js的lookAt矩阵直接生成约束向上方向的旋转,本质和方法一逻辑一致:

//Box natural direction
let vB = new THREE.Vector3(0, 0, 1);
let upB = new THREE.Vector3(0, 1, 0);

//Cable direction
let vC = new THREE.Vector3(1, 1, 0).normalize();

// 用lookAt生成旋转:让模型Z轴指向vC,同时保持upB为向上方向
const lookAtMatrix = new THREE.Matrix4().lookAt(
    new THREE.Vector3(0,0,0), // 模型原点
    vC, // 目标方向(作为点)
    upB // 约束的向上方向
);
let q = new THREE.Quaternion().setFromRotationMatrix(lookAtMatrix);

// 后续模型代码与原代码一致

原理说明

两种方法都是通过固定模型的向上轴朝向,消除了绕目标方向(vC)的额外旋转自由度,从而避免侧滚。旋转后的模型不仅前方向对齐vC,局部Y轴也会保持在垂直于vC的平面内,且与原向上方向的投影一致。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 14:50:42