使节点层次中的节点面向摄影机(公告牌)

Getting a node in a node hierarchy to face the camera (billboard)

本文关键字:节点 摄影机 层次      更新时间:2023-09-26

我需要使节点层次结构中的一个节点面向摄影机,或者换句话说,是一个广告牌。对于每个节点,我将其世界矩阵和世界旋转存储为四元数。根据我对四元数的了解,我想要的运算是得到一个节点的相机四元数和旋转四元数之间的差,并简单地将节点旋转所述差。

我的相机存储为欧拉角,所以我通过首先创建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);
}

我犯了什么明显的错误吗?

您的假设是错误的:

我想要的操作是得到相机之间的差异四元数和节点的旋转四元数,并简单地旋转通过所述差来确定节点。

如果操作正确,则会导致节点朝向与摄影机相同的方向。这与实际面对相机大不相同。

您需要的是找到在世界空间中面向摄影机位置的变换。您可能会从gluLookAt()的快速研究中受益。