跳到主要内容

节点变换矩阵

我们应该已经知道了如何创建一个几何,并给它定义材质,使它看起来更加立体和生动,但它仍然是静态物体。如果我们想渲染出一个带有动画的场景,应该怎么做呢?需要用到渲染节点nodetransform属性,这个属性用于变换渲染节点在3D空间中的方位,同时也可以对节点内的渲染几何进行拉伸。

什么是transform矩阵

transform属性的数据类型是Matrix4,对一个向量进行任意缩放、平移和旋转变换,都可以看作是给向量左乘一个矩阵,如果存在多次变换,那就相当于连续多次左乘矩阵。那么问题来了,矩阵是如何与旋转、缩放和平移一一对应的呢?

旋转

想要表达3D空间中的一个旋转,需要定义一个角度θ\theta和一个旋转轴u=(𝑥,𝑦,𝑧)\mathbf u = (𝑥, 𝑦, 𝑧),这个旋转轴是任意方向的单位向量。我们可以用一个四元数q\mathbf q来描述对向量ν0\mathbf \nu _0进行旋转,形成一个新向量ν1\mathbf \nu _1

q=[cos(12θ),sin(12θ)u]\mathbf q = [ cos(\frac 12 \theta), sin(\frac 12 \theta)\mathbf u ] ν1=qν0q1\mathbf \nu _1 = \mathbf q \mathbf \nu _0 \mathbf q ^ {-1}

四元数与一个旋转矩阵对应,令a=cos(12θ),b=sin(12θ)ux,c=sin(12θ)uy,d=sin(12θ)uza = cos(\frac 12 \theta), b = sin(\frac 12 \theta)\mathbf u_x, c = sin(\frac 12 \theta)\mathbf u_y, d = sin(\frac 12 \theta)\mathbf u_z,这个矩阵如下:

Mrotation=(12c22d22bc2ad2ac+2bd02bc+2ad12b22d22cd2ab02bd2ac2ab+2cd12b22c200001)M_{rotation} = \left( \begin{matrix} 1-2c^2-2d^2 & 2bc-2ad & 2ac+2bd & 0 \\ 2bc+2ad & 1-2b^2-2d^2 & 2cd-2ab & 0\\ 2bd-2ac & 2ab+2cd & 1-2b^2-2c^2 & 0\\ 0 & 0 & 0 & 1\\ \end{matrix} \right)

将矩阵作用到向量ν0\mathbf \nu _0上,可以得到同样的结果:

ν1=Mrotationν0\mathbf \nu _1 = M_{rotation} \mathbf \nu _0

缩放

对空间中的一个向量进行缩放,由于向量的三个方向上的缩放系数可能不尽相同,所以可以用一个缩放向量来描述:(S1S2S3 )\left( S_1\, S_2\,S_3\ \right),这个向量与一个缩放矩阵对应:

Mscaling=(S10000S20000S300001)M_{scaling} = \left( \begin{matrix} S_1 & 0 & 0 & 0 \\ 0 & S_2 & 0 & 0\\ 0 & 0 & S_3 & 0\\ 0 & 0 & 0 & 1\\ \end{matrix} \right)

我们将该矩阵与一个任意向量(xyz )\left( x\, y\,z\ \right)左乘,就会得到一个被缩放的新向量

(S10000S20000S300001)(xyz1)=(x×S1y×S2z×S31)\left( \begin{matrix} S_1 & 0 & 0 & 0 \\ 0 & S_2 & 0 & 0\\ 0 & 0 & S_3 & 0\\ 0 & 0 & 0 & 1\\ \end{matrix} \right) \left( \begin{matrix} x \\ y \\ z \\ 1 \\ \end{matrix} \right) = \left( \begin{matrix} x \times S_1 \\ y \times S_2\\ z \times S_3\\ 1 \\ \end{matrix} \right)

平移

平移是在原始向量的基础上,加上一个平移向量从而获得一个不同位置的新向量,如果我们把平移向量表示为:(T1T2T3 )\left( T_1\, T_2\,T_3\ \right),我们就可以把平移矩阵定义为:

Mtranslation=(100T1010T2001T30001)M_{translation} = \left( \begin{matrix} 1 & 0 & 0 & T_1 \\ 0 & 1 & 0 & T_2\\ 0 & 0 & 1 & T_3\\ 0 & 0 & 0 & 1\\ \end{matrix} \right)

我们将该矩阵与一个任意向量(xyz )\left( x\, y\,z\ \right)左乘,就会得到一个被平移的新向量

(100T1010T2001T30001)(xyz1)=(100x+T1010y+T2001z+T30001)\left( \begin{matrix} 1 & 0 & 0 & T_1 \\ 0 & 1 & 0 & T_2\\ 0 & 0 & 1 & T_3\\ 0 & 0 & 0 & 1\\ \end{matrix} \right) \left( \begin{matrix} x \\ y \\ z \\ 1 \\ \end{matrix} \right) = \left( \begin{matrix} 1 & 0 & 0 & x+T_1 \\ 0 & 1 & 0 & y+T_2\\ 0 & 0 & 1 & z+T_3\\ 0 & 0 & 0 & 1\\ \end{matrix} \right)

如何使用transform矩阵

首先我们定义一个transform矩阵:

auto transform = _mat4();

Matrix4类具备以下操作:

  • Matrix4::toRotation(), 获取当前矩阵的旋转四元数

  • Matrix4::toScaling(), 获取当前矩阵的缩放向量

  • Matrix4::toTranslation(), 获取当前矩阵的平移向量

  • Matrix4::fromRotation(r), 将旋转四元数r转换成矩阵

  • Matrix4::fromScaling(s), 将缩放向量s转换成矩阵

  • Matrix4::fromTranslation(t), 将平移向量t转换成矩阵

  • Matrix4::rotate(r), 将当前矩阵按照该旋转四元数进行旋转

  • Matrix4::scale(s), 将当前矩阵按照该缩放向量进行缩放

  • Matrix4::translate(t), 将当前矩阵按照该平移向量进行平移

案例一:平移transform矩阵

在这个例子中,我们将上面定义的transform矩阵按照向量(2, 0, 0)平移,然后我们将该transform矩阵传递给一个渲染节点node,那么在渲染时,该节点中的渲染对象primitive在3D空间中的位置相较原来的位置平移了(2, 0, 0)。

transform->translate(vec3(2, 0, 0));
auto node = _node({ primitive }, transform);

案例二:定位器操纵几何

在下面的这个例子中,我们将定位器渲染节点locator的transform变化,同步给一个几何所在的渲染节点,从而实现通过定位器来操纵几何。

locator->bind("updated", [&]()->void {
auto transform = locator->transform;
*node->transform = *transform;
});