1

Мне нужно сделать узел в иерархии узлов лицом к камере или, другими словами, быть рекламным щитом. Для каждого узла я храню его всемирную матрицу и вращение мира как кватернион. Что я знаю о кватернионах, операция, которую я хочу, - это получить разницу между кватернионом камеры и кватернионом вращения узла и просто повернуть узел указанной разницей.Получение узла в иерархии узлов перед камерой (рекламный щит)

Моя камера хранится в виде углов эйлера, поэтому я построю кватернион камеры, сначала создавая вращение по оси X, затем вращение оси Z (у меня нет вращений по оси Y) и их умножение.

Оттуда это просто математика, чтобы получить разницу и, наконец, создать из нее матрицу вращения и умножить ее матрицу мира.

Это, однако, приводит к тому, что узлы вращаются как сумасшедшие пушки и никоим образом не обращены к камере.

Вот соответствующий код JavaScript:

// If there is a parent, multiply both world matrix and rotation by it 
// localMatrix here is the current local matrix of the node 
// rotation here is the local rotation quaternion 
if (node.parent) { 
    math.Mat4.multMat(node.parent.worldMatrix, localMatrix, node.worldMatrix); 
    math.Quaternion.concat(node.parent.worldRotation, rotation, node.worldRotation); 
} else { 
    node.worldMatrix = localMatrix; 
    node.worldRotation = rotation.copy(); 
} 

// And here the mess begins 
if (node.billboarded) { 
    var cameraX = []; 
    var cameraZ = []; 
    var camera = []; 

    // transform.rotation is my camera's rotation stored as 3 euler angles, 
    // but I am not using the Y-axis for now 
    math.Quaternion.setFromAxisAngle([1, 0, 0], transform.rotation[0], cameraX); 
    math.Quaternion.setFromAxisAngle([0, 0, 1], transform.rotation[2], cameraZ); 
    math.Quaternion.concat(cameraX, cameraZ, camera); 

    // The current rotation on the node 
    var initial = node.worldRotation.copy(); 

    // Need to reverse it, since the difference is camera * -initial 
    math.Quaternion.conjugate(initial, initial); 

    var difference = []; 

    math.Quaternion.concat(camera, initial, difference); 

    var rotationMatrix = []; 

    math.Quaternion.toRotationMatrix4(difference, rotationMatrix); 

    var finalMatrix = [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]; 

    // pivot is the node's position, need to keep the rotation in local space 
    math.Mat4.translate(finalMatrix, pivot[0], pivot[1], pivot[2]); 
    math.Mat4.multMat(finalMatrix, rotationMatrix, finalMatrix); 
    math.Mat4.translate(finalMatrix, -pivot[0], -pivot[1], -pivot[2]); 

    // And finally actually rotate the node 
    math.Mat4.multMat(node.worldMatrix, finalMatrix, node.worldMatrix); 
} 

Есть ли некоторые очевидные ошибки я делаю?

ответ

0

Ваше предположение неверно:

операции Я хочу, чтобы получить разницу между камерой кватернионами и вращением кватернионом узла, и просто повернуть узел указанной разницы.

Если вы сделали это правильно, это должно привести к тому, что ваши узлы окажутся в том же направлении, в котором находится камера. Это совсем не так, как на самом деле обращено к камере.

Что нужно, чтобы найти трансформацию, которая находится на позиции камеры в мировом пространстве. Вы можете воспользоваться некоторыми быстрыми исследованиями в gluLookAt().

+0

Не могу поверить, что я почему-то не заметил этого. О масках look-at, я не могу использовать их здесь, потому что на узлы влияет остальная иерархия узлов, я не могу просто заменить их преобразование матрицей взгляда, и в противном случае они не будут работать, потому что они работают на основе того, что у вас есть ориентация с фиксированной осью. – user2503048