Мне нужно сделать узел в иерархии узлов лицом к камере или, другими словами, быть рекламным щитом. Для каждого узла я храню его всемирную матрицу и вращение мира как кватернион. Что я знаю о кватернионах, операция, которую я хочу, - это получить разницу между кватернионом камеры и кватернионом вращения узла и просто повернуть узел указанной разницей.Получение узла в иерархии узлов перед камерой (рекламный щит)
Моя камера хранится в виде углов эйлера, поэтому я построю кватернион камеры, сначала создавая вращение по оси 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);
}
Есть ли некоторые очевидные ошибки я делаю?
Не могу поверить, что я почему-то не заметил этого. О масках look-at, я не могу использовать их здесь, потому что на узлы влияет остальная иерархия узлов, я не могу просто заменить их преобразование матрицей взгляда, и в противном случае они не будут работать, потому что они работают на основе того, что у вас есть ориентация с фиксированной осью. – user2503048