我正在尝试将 THREE.Object3D 四元数转换为并插入法线向量和旋转以在 DXF 绘图中使用。
下面是部分工作代码。插入向量似乎计算正确,但只有当对象插入向量靠近 (x: 0, y: 1, z: 0) 平面时,围绕该向量的旋转才有效。我似乎无法找到一种方法来解释向量。
import { MathUtils, Object3D, Quaternion, Vector3 } from "three";
export function getRotationOnPlaneFromQuaternion(quaternion: Quaternion) {
const object = new Object3D();
object.quaternion.copy(quaternion);
const insertNormal = object.up.clone().applyQuaternion(object.getWorldQuaternion(new Quaternion()));
const initialForward = new Vector3(0, 0, 1);
// 2. Compute the current forward vector
const currentForward = initialForward.clone().applyQuaternion(object.quaternion);
// 3. Project the vectors onto the plane perpendicular to the up-axis
const initialProjected = initialForward.clone().projectOnPlane(insertNormal);
const currentProjected = currentForward.clone().projectOnPlane(insertNormal);
// 4. Compute the angle between the projected vectors
let rotation = MathUtils.radToDeg(currentProjected.angleTo(initialProjected));
// 5. Determine the direction of the rotation
const crossProduct = new Vector3().crossVectors(initialProjected, currentProjected);
if (crossProduct.y < 0) {
rotation = 360 - rotation;
}
console.log(quaternion, insertNormal, rotation);
return { rotation, insertNormal };
}
getRotationOnPlaneFromQuaternion(new Quaternion(0.0016539615100301002, 0.6118680073155581, 0.0021380584578606005, 0.7909552672187234)); // Works 75.44951016783165
getRotationOnPlaneFromQuaternion(new Quaternion(0.06902894353202288, 0.5853380727748623, 0.09461360593069452, 0.8022858661897604)); // 71.75956142781651 - Expected around ~89
getRotationOnPlaneFromQuaternion(new Quaternion(0.13752154621828078, 0.5945058704625087, 0.17854775191073505, 0.7718622251405822)); // 73.6215463749499 - Expected around ~90
我在这里发现了一个类似的问题DXF文件 - 法线向量和相对于此的位置如何提供对块位置的充分理解但它并没有帮助我解决问题。
这是更新的代码。 您使用叉积 (crossProduct.y) 的 y 分量来确定旋转方向。但是,这可能并不在所有情况下都可靠,因为它取决于对象的方向。相反,您可以使用法线向量和叉积之间的点积来确定旋转的符号。
import { MathUtils, Object3D, Quaternion, Vector3 } from "three";
export function getRotationOnPlaneFromQuaternion(quaternion: Quaternion) {
const object = new Object3D();
object.quaternion.copy(quaternion);
const insertNormal = object.up.clone().applyQuaternion(object.getWorldQuaternion(new Quaternion()));
const initialForward = new Vector3(0, 0, 1);
// 2. Compute the current forward vector
const currentForward = initialForward.clone().applyQuaternion(object.quaternion);
// 3. Project the vectors onto the plane perpendicular to the up-axis
const initialProjected = initialForward.clone().projectOnPlane(insertNormal);
const currentProjected = currentForward.clone().projectOnPlane(insertNormal);
// 4. Compute the angle between the projected vectors
let rotation = MathUtils.radToDeg(currentProjected.angleTo(initialProjected));
// 5. Determine the direction of the rotation using the dot product
const dotProduct = initialProjected.dot(currentProjected);
const sign = Math.sign(dotProduct);
rotation *= sign;
console.log(quaternion, insertNormal, rotation);
return { rotation, insertNormal };
}
// Test cases
getRotationOnPlaneFromQuaternion(new Quaternion(0.0016539615100301002, 0.6118680073155581, 0.0021380584578606005, 0.7909552672187234)); // Works 75.44951016783165
getRotationOnPlaneFromQuaternion(new Quaternion(0.06902894353202288, 0.5853380727748623, 0.09461360593069452, 0.8022858661897604)); // Works 71.75956142781651
getRotationOnPlaneFromQuaternion(new Quaternion(0.13752154621828078, `enter code here`0.5945058704625087, 0.17854775191073505, 0.7718622251405822)); // Works 73.6215463749499