出处: https://youtu.be/4iNJdWXsFQ4?si=02SsxcVVoB6N-AXs
嘿,大家好,让我们看看如何使用分层建模来制作一个计算机图形机器人。这是我们的机器人。实际上它是一个机械臂,但它有一些很酷的动作。我们将用这三个正方形来制作它。
让我们从底座开始。这个正方形已经非常接近了。我们只需要把它稍微缩短一点。让我们在垂直方向上将其缩小50%。我们可以使用这个矩阵来实现,它将y坐标除以二。但实际上我们会使用一个3x3版本的矩阵,这使得我们可以表示平移操作。这被称为齐次坐标。
好的,让我们继续处理机器人的下一部分,红色的身体部分。它需要调整大小,并放置在底座顶部,如下所示。我们将首先水平缩小并垂直拉伸它。接下来我们将使用平移矩阵将其向上移动。
这是应用这些矩阵的正确顺序吗?让我们更仔细地看看这里。我们希望先缩放再平移。那么我们不应该在这里交换矩阵的顺序吗?让我们试一试。这些矩阵通过在右侧乘以向量来应用。但现在你可以看到t会先乘以x。这与我们想要的相反。所以s放在右边是正确的。
好的,让我们添加最后一部分。我们将首先对其进行缩放和翻译到顶部。最后,我们将旋转到正确位置。
等等,那不对。它围绕原点旋转了,而原点位于该图的底部。
为了理解如何修复这个问题,让我们更仔细地看看旋转是如何工作的。当你应用旋转时,所有东西都会移动得很好,几乎所有的点都会移动。有一个点是固定的,那就是原点。
如果你的对象触及原点,那个点根本不会移动。缩放也是同样的道理。任何可以用2x2矩阵表示的变换都是如此。这非常有用。让我们看看它是如何工作的。
只需考虑模型中你希望保持固定的点。在这种情况下,它是绿色部分的底部。现在将你的模型平移,使该点位于原点。然后应用旋转。让我们试试看。现在回到绿色部分已经缩放但尚未移动的地方。让我们移动,使底座,即我们希望的固定点,位于原点。现在我们将旋转它并将其平移到红色部分的顶部。好了。我们的机器人完成了。
嗯,是的,但过程有点痛苦。我们不得不写一大堆矩阵。假设我们想添加第四部分,这个橙色的部分,情况会变得更糟。
还有另一个问题。如果你想移动你的机器人怎么办?这里,我们对底座应用平移。哎呀,其余的机器人被甩在后面了。我想没有人会想要这样的机器人。
所以让我告诉你一种更好的方法来构建你的机器人,使用一种叫做分层建模的技术。
到目前为止,我们为机器人的所有部分都使用了一个全局坐标系。相反,让我们引入三个局部坐标系,每个部分一个。我们将从将每个正方形中心化在其自己的局部坐标系中开始。
现在,让我们对每个部分应用缩放矩阵,并沿y轴平移每个部分,但在其自身的局部坐标系中。就这样。我们有了一个机器人。而且每个部分只需要两个简单的变换。
但是这些坐标系是从哪里来的呢?让我们设置它们。我们将从底座处的一个坐标系开始,我们称之为c零。
现在要得到c一,我们只需要向上平移。让我们给机器人在c一处添加一个旋转关节。我们可以通过添加一个旋转矩阵,R一,来实现。这将旋转整个上部组件,这很酷。
那么我们应该以什么顺序指定这两个操作?T?还是R?让我们更仔细地看看。假设我们首先应用平移。现在如果我们旋转,由于旋转的原点在底部,c一会被移动到错误的位置。相反,让我们先旋转再平移。不错。
好吧。现在我们将重复这个过程,通过另一个旋转和平移来创建c二。
现在,如果我们将底座平移会发生什么?让我们添加一个平移矩阵,t零,来看看结果。[4:47.520-4:48.050]平移c零会导致整个机器人平移,而不是断开底座,这很棒。这是因为模型的其余部分是相对于c零定义的。因此移动c零会移动整个模型。改变R一会旋转整个上部组件。最后,如果我们只想旋转绿色部分,我们改变R2。这很好。它像机器人一样移动。好吧?
这仍然有很多东西需要跟踪。我们有部分变换和坐标变换。我们如何使用所有这些来正确渲染机器人?
事实证明,使用树结构有一个非常优雅的解决方案。
c零是我们的第一个坐标系,我们将它放在树的根节点。c一是相对于c零定义的,因此它将成为子节点,我们将它的变换放在它们之间的边上。同样,我们将c二作为c一的子节点,并加上它的变换。[5:47.289]最后,我们将t零放在顶部,因为它变换整个模型。好吧,现在我们有一棵树来表示所有的局部坐标系。现在我们也将零件加进去。底座是相对于c零定义的,因此它成为子节点,并加上它的变换,我们将对红色和绿色部分做同样的处理。这棵树代表了我们的整个机器人作为一个分层模型。
那么我们如何渲染这个模型呢?答案是使用深度优先遍历,这是一种标准的树遍历算法。
为此,我们将使用一个矩阵栈,它将保存当前活动的一组变换,用于应用到每个部分。当我们遍历树时,矩阵将被推入或弹出栈。
我们将从根节点推入t零开始。接下来我们将遍历左子树。当我们遍历到蓝色节点的边时,该边的变换将被推入栈中。现在是时候渲染底座了。我们需要的所有变换都已经准备好在栈中,从上到下排列,因此底座被正确缩放和平移。
现在我们完成了底座,节点将弹出它的变换并移动到下一个节点,c一。当我们遍历到红色节点时,所有的变换都在栈中,不仅正确地变换红色部分,还变换其局部坐标系。
现在我们继续向下遍历到绿色节点。遍历完成后,绿色部分及其所有变换都将被渲染。
好了。正如你所见,有许多矩阵在栈上应用于绿色部分。但分层的魔力在于我们不需要跟踪所有这些。树的通用性自动处理了这一切。我们只需专注于更容易的任务,即定义每个局部坐标系,以及局部部分变换。
所以你可能已经开始厌倦机器人手臂了。我说得对吗?好吧,让我们放大一点。实际上它是一只兔子,我们也可以用一棵稍大的树来表示它。
不,等等,它是一个虫子。层次结构真是令人惊叹。我们甚至可以在同一个层次结构中包含多个对象。再加上灯光和相机。
事实上,整个场景都可以表示。我们称其为场景图。我希望你喜欢这个关于分层建模及其惊人功能的视频。