Установка глобального поворота вектора с помощью кватерниона в ТРИ. js - PullRequest
0 голосов
/ 10 апреля 2020

Я хотел бы установить абсолютное глобальное вращение вектора, используя кватернион.

Допустим, у меня есть функция f(v, q), которая поворачивает вектор v в кватернион q.

THREE.Vector3 имеет функцию .applyQuaternion, которая применяет вращение к вектору, но это относительное вращение. Например, вызов функции f(f(v, q), q) будет применен q дважды. Вместо этого я ожидал бы f(f(v, q), q) = f(v, q), поскольку q - это абсолютное вращение вектора.

Я знаю, что могу вычислить немного deltaQ = currentQ.premultiply(q.inverse()) и затем вызвать .applyQuaternion, но я не знаю, как запросить currentQ или текущее вращение вектора, чтобы я мог «отменить» его и применить новый кватернион.

Спасибо за любую помощь!

РЕДАКТИРОВАТЬ:

В идеале я бы хотел повернуть вокруг точки, определенной в мировом координатном пространстве, поэтому у меня есть вызовы object.worldToLocal и object.localToWorld. Однако, когда я делаю эти преобразования, орбитальный объект улетает с карты.

const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera( 75, window.innerWidth/window.innerHeight, 0.1, 1000 );

const renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
/* const orbitControls = new THREE.OrbitControls(camera, renderer.domElement); */

// CONSTRUCT ORBITER
const orbitGeometry = new THREE.SphereGeometry(0.1, 32, 32);
const orbitMaterial = new THREE.MeshBasicMaterial({colors: 0xff0000});
const orbiter = new THREE.Mesh(orbitGeometry, orbitMaterial);

// CONSTRUCT GLOBAL AXES
const xDir = new THREE.Vector3(1, 0, 0);
const yDir = new THREE.Vector3(0, 1, 0);
const zDir = new THREE.Vector3(0, 0, 1);
const origin = new THREE.Vector3(0, 0, 0);
const xArrowWorld = new THREE.ArrowHelper(xDir, origin, 3, 0xFF00FF);
const yArrowWorld = new THREE.ArrowHelper(yDir, origin, 3, 0xffff00);
const zArrowWorld = new THREE.ArrowHelper(zDir, origin, 3, 0x00b7eb);
const worldAxes = new THREE.Group();
worldAxes.add(xArrowWorld);
worldAxes.add(yArrowWorld);
worldAxes.add(zArrowWorld);


// CONSTRUCT MARKER
const sphereGeometry = new THREE.SphereGeometry(0.1, 32, 32);
const sphereMaterial = new THREE.MeshBasicMaterial({color: 0xffffff});
const marker = new THREE.Mesh(sphereGeometry, sphereMaterial);

// scene.add(axes);
scene.add(marker);
scene.add(orbiter);
scene.add(worldAxes);

camera.position.z = 5;
camera.position.y = 3;
camera.position.x = 3;
camera.lookAt(worldAxes.position);

marker.position.set(1, 0, 0);

function rotateEuler(object, point, eulerX, eulerY, eulerZ, isExtrinsic = false) {
    if (isExtrinsic) {
        object.rotation.order = 'ZYX';
    } else {
        object.rotation.order = 'XYZ';
    }
    const q = new THREE.Quaternion();
    const eul = new THREE.Euler(eulerX, eulerY, eulerZ, object.rotation.order);
    q.setFromEuler(eul);
    rotateQuaternionAroundPoint(object, point, q);
}

function rotateQuaternionAroundPoint(object, point, q) {

    object.rotation.set(0, 0, 0)
    object.position.set(0, 0, 0);

    object.localToWorld(object.position);
    object.position.sub(point);
    object.position.applyQuaternion(q);
    object.position.add(point);
    object.worldToLocal(object.position);

}

let rotY = 0;
let rotationPoint = marker.localToWorld(marker.position.clone());

function animate() {
    requestAnimationFrame( animate );

    rotY += 0.01;

    rotateEuler(orbiter, rotationPoint, 0, rotY, 0, true);

    renderer.render( scene, camera );
}

animate();
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/110/three.min.js"></script>

1 Ответ

1 голос
/ 11 апреля 2020

Самый простой способ сделать это - сбросить Vector3 в исходное состояние, а затем применить кватернион к этому вектору сброса. Это удаляет любой предыдущий поворот из уравнения. Например, предполагая, что векторное состояние по умолчанию указывает 'UP':

function f(v, q) {
    v.set(0, 1, 0);
    v.applyQuaternion(q);
    return v;
}
...