두 XYZ 좌표를 정렬하는 방법

10956 단어 threejs3dcg
최근에는 핸드트래킹 AR 작업을 하고 있습니다. 3D 모델을 손에 맞추려면 3D 모델 객체의 좌표를 손의 좌표와 일치시켜 손에 3D 모델이 나타나는 것과 같은 효과를 내야 했습니다.

그것들을 정렬하는 것은 약간 복잡하므로 여기에서 수행하는 방법을 설명하겠습니다.

가정



정렬할 대상 좌표 XYZ(예: 손)와 좌표 xyz(예: 3D 모델)가 있다고 가정해 보겠습니다. 우리는 이미 XYZ와 xyz의 벡터를 알고 있습니다. X/Y/Z는 서로 직교하고 정규화되며(길이는 1) x/y/z도 마찬가지입니다. 목표는 xyz 벡터를 XYZ에 정렬하는 것입니다.



원점 정렬은 XYZ 원점 위치를 xyz 원점 위치로 설정하는 것만으로 할 수 있기 때문에 이 기사에서는 설명하지 않습니다.

다음 단계에서는 z/Z와 x/X를 정렬합니다. 그러나 작업 순서는 중요하지 않습니다. y/Y를 먼저 정렬하고 z/Z를 다음에 정렬할 수 있습니다.

Z를 Z에 정렬



먼저 z축을 정렬합니다.



교차 벡터z × Z와 교차 벡터 주위의 좌표를 회전시키는 데 사용되는 역코사인과 내적을 사용하여 θ를 계산합니다. 회전을 달성하기 위해 quaternion을 사용할 수 있습니다. 스스로 쿼터니언을 계산하는 것은 약간 복잡하며 일반적으로 3D CG 엔진에는 회전할 축과 각도에서 쿼터니언을 계산하는 내장 기능이 있습니다. 정말로 직접 구현하고 싶다면 this article 을 참조하십시오.



이것은 의사 코드의 예입니다. 프로그래밍 언어/3D CG 엔진(예: Three.js/Unity/Unreal Engine)에는 cross/dot/normalize/acos/fromAxisAngle이 있어야 합니다.

Vec3 z = ... // Your z
Vec3 Z = ... // Your Z
Vec3 axisZ = normalize(cross(z, Z)); // Normalized cross vector.
float angleZ = acos(dot(z, Z)); // The angle between z and Z --> theta in the image.
Quaternion qz = fromAxisAngle(axisZ, angleZ); // Later we will make other quaternions so let's name it qz.


이제 z를 Z축에 정렬하기 위한 쿼터니언qz이 있습니다.

x를 X에 정렬



쿼터니언qz을 좌표에 적용하면 다음 이미지와 같이 x'/y'/z'가 됩니다.



x/X 축을 정렬하는 것은 기본적으로 z/Z에서 했던 것과 동일한 프로세스입니다. z/Z가 이미 정렬되었으므로 x와 X는 동일한 평면에 있습니다. x/X가 정렬되면 y/Y가 자동으로 정렬됩니다. 그러나 쿼터니언qz을 x 벡터에 적용하는 것을 잊지 마십시오. 회전된 x 벡터의 이름을 x' 로 지정하겠습니다.



슈도코드는 이와 같아야 합니다. applyQuaternion는 벡터에 쿼터니언을 적용하는 함수입니다. 귀하의 프로그래밍 언어/3D 엔진에는 이에 상응하는 것이 있어야 합니다.

Vec3 rotatedX = applyQuaternion(x, qz); // x'
Vec3 X = ... // Your X
Vec3 axisX = normalize(cross(rotatedX, X));
float angleX = acos(dot(rotatedX, X)); // The angle between x' and X --> phi in the image
Quaternion qx = fromAxisAngle(axisX, angleX);


다음 쿼터니언qx이 있습니다.

쿼터니언 결합



이제 qzqx 가 있습니다. 쿼터니언을 결합하면 좌표 정렬을 실현할 수 있는 최종 쿼터니언을 갖게 됩니다.
multiplyQuaternions는 두 개의 쿼터니언을 하나로 결합하는 함수입니다. 귀하의 프로그래밍 언어/3D 엔진에는 이에 상응하는 것이 있어야 합니다. qzqx의 순서가 중요하니 주의하세요.

Quaternion q = mltiplyQuaternions(qx, qz);


쿼터니언q을 x/y/z에 각각 적용하면 X/Y/Z와 동일한 벡터를 얻을 수 있습니다.



부록: Three.js 코드



위의 의사 코드를 보여주었습니다. 또한 Three.js에서 예제를 제공합니다.

// Your coordinates.
// x/y/z are vectors that will be aligned FROM.
const x = new Vector3(...);
const y = new Vector3(...);
const z = new Vector3(...); // <-- You do not need this actually.

// X/Y/Z are vectors that will be aligned TO.
const X = new Vector3(...);
const Y = new Vector3(...);
const Z = new Vector3(...); // <-- You do not need this actually.


const axisZ = z.clone().cross(Z).normalize();
const angleZ = Math.acos(z.dot(Z));
const qz = new Quaternion().setFromAxisAngle(axisZ, angleZ);

const rotatedX = x.clone().applyQuaternion(qz);
const axisX = rotatedX.clone().cross(X).normalize();
const angleX = Math.acos(rotatedX.dot(X));
const qx = new Quaternion().setFromAxisAngle(axisX, angleX);

// Final quaternion
const q = new Quaternion().multiplyQuaternions(qx, qz);

// You can use q like this.
yourModel.rotation.setFromQuaternion(q)


원한다면 내 Demo 를 확인할 수 있습니다!

좋은 웹페이지 즐겨찾기