我正在尝试制作我的小型 3D 对象查看器。
我通过节点层次结构创建了一个场景,一开始,每个节点都包含一个Mat4存储其本地变换,但现在我想与其变换交互,所以我将Mat4更改为Transform(其中包含缩放,旋转四元数和平移)问题就变成了。
从 Mat4 作为局部变换,通过将节点的局部变换矩阵与其父节点的全局变换矩阵相乘,可以轻松计算场景中所有节点(包括根、叶……)的全局变换。
但是对于 Transform,我不知道如何像 Mat4 那样应用变换链!
我的解决方案是将 Transform 转换为 Mat4 并正常应用变换链,然后进行矩阵分解以恢复 Transform,但我认为还有另一种方法可以在不使用矩阵分解方法的情况下完成此操作。
我尝试通过其父全局变换矩阵来变换每个“缩放”、“旋转”、“平移”组件,但它不起作用。变换看起来像:
// row major matrix
auto parentGlobalTransformMat = <...>;
auto scale = Mat4::Scaling(m_transform.Scale()) * parentGlobalTransformMat;
m_transform.Scale() = Vec3(scale[0][0], scale[1][1], scale[2][2]);
auto rotation = Mat4::Rotation(m_transform.Rotation()) * parentGlobalTransformMat;
m_transform.Rotation() = Mat4ToQuat(rotation);
auto translation = Vec4(m_transform.Translation(), 1.0f) * parentGlobalTransformMat;
m_transform.Translation() = translation.xyz() / translation.w;
首先,在矩阵乘法中:
A * B != B * A
。
其次,如果您有场景层次结构(节点),那么最好有一个变换节点,您只能在其中获取/设置单个变换(平移、旋转、缩放等)。仅当需要实际矩阵(渲染操作)时,才会根据通用转换公式从值中生成矩阵。
例如:
struct transform {
vec3 translation;
vec3 center;
vec4 rotation;
vec3 scale;
mat4 matrix;
mat4 getMatrix();
};
mat4 transform::getMatrix()
{
//set identity
matrix.identity();
//to avoid unnecessary multiplications,
//its best to implement the transform class as a state machine,
//where a bitmask would tell if a property is set or not
//based on the formula: T * C * R * S * -C
matrix.translate(translation); //matrix * translationMatrix
matrix.translate(center); //matrix * translationMatrix
matrix.rotate(rotation); //matrix * rotationMatrix
matrix.scale(scale); //matrix * scaleMatrix
matrix.translate(-center); //matrix * translationMatrix
return matrix;
}
现在,让我们看一下简单的层次结构:
//root node
node root;
//set root transformations
root.translation = vec3(); //for simplicity
//child node
node child;
//set child transformations
child.rotation = vec4(); //for simplicity
//set hierarchy
root.add(child);
要获得整体转换(从层次结构中的任何点),实现可能如下所示:
struct node {
node *parent;
transform xform;
mat4 getMatrix();
};
mat4 node::getMatrix()
{
//recursive matrix multiplication
return parent->getMatrix() * xform.getMatrix();
}
当然,如果想要在层次结构中的任何给定点进行整体旋转,则仍然需要分解。但问题是,你真的需要它吗(情况并非总是如此)?