3D 相对变换与绝对变换
我正在尝试为我的 3D 游戏创建一个场景图,其中每个对象的变换都相对于它的父对象。图的每个节点都有一个旋转、缩放和平移向量。
组合相对变换矩阵以获得对象的绝对变换的正确方法是什么?如果您也能解释您的解决方案,我将很高兴。
这里是一个错误的例子:
这实际上是解决方案:
Matrix GetAbsoluteTransformation()
{
if (!this.IsRoot())
{
return this.Transformation * this.Parent.GetAbsoluteTransformation();
}
else
{
return this.Transformation;
}
}
在这种情况下,当父节点旋转、缩放或移动时,子节点会进行相同的变换,这是正确的行为! 但是子进程只会绕自己的原点旋转,不会绕父进程的原点移动。
应用:
有一个有四个轮子的汽车模型。车轮围绕汽车原点相对定位。轮子可以像真正的轮子一样旋转。如果我现在旋转汽车,车轮应该始终保持在汽车上。在这种情况下,汽车是根节点,车轮是子节点。
另一个例子是太阳系模型。行星绕自己的轴旋转,绕太阳运动,卫星绕行星运动。
I am trying to create a scene graph for my 3D game in which every object's transformations are relative to it's parent. Each node of the graph has a Rotation, Scaling and Translation vector.
What is the correct way of combining the relative transformation matrices to get the absolute transformation of an object? I would be glad if you could also explain your solution.
Here is an example of to do it WRONG:
This actually turned out to be the solution:
Matrix GetAbsoluteTransformation()
{
if (!this.IsRoot())
{
return this.Transformation * this.Parent.GetAbsoluteTransformation();
}
else
{
return this.Transformation;
}
}
In this case, when the parent node is rotated, scaled or moved, the child is transformed the same amount, which is a correct behaviour!But the child will only rotate around its own origin and does not move around the parent's origin.
Applications:
There is a car model with four wheels. The wheels are relative positioned around the car's origin. The wheels can rotate just like real wheels do. If I now rotate the car, the wheels should at all time stay attached to it. In this case the car is the root and the wheels are the child nodes.
Another example would be a model of the solar system. Planets rotate around their own axis, move around the sun, and moons move around planets.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
关于你的“如何做错”,我不想向你透露,但这并没有错;相反,它是不完整的。您需要独立于父子关系来完成这些工作。
这是一个例子:就像您提到的那样,车轮连接到汽车上。如果您平移或旋转汽车,则无需触摸车轮 - 它们相对于汽车位于同一位置。然而,当您尝试获取轮子在“现实世界”中的新位置时,您必须遍历树,并在执行过程中应用矩阵变换。这一切都有效,对吧?
当您旋转对象时,它会绕其自身的原点旋转。因此,轮子可能应该绕其 y 轴旋转,而行星则应绕其 z 轴旋转。但现在如果你需要让一颗行星“绕太阳”移动,你所做的事情就完全不同了。这个需要单独计算。这并不是说使用您已经拥有的一些相同的匹配项不会减轻这种情况(尽管我不能在不亲自计算的情况下肯定地说),但它是完全不同的。
您正在考虑实际更改对象的状态。这就是场景图的美妙之处!如果您没有场景图,则必须计算出所有各种值一直回到主场景,然后进行各种数学运算。在这里,你只需要做一些三角和代数就可以围绕行星移动(你可以谷歌搜索天体力学)并相对于其恒星移动行星。下次主场景询问行星在哪里时,它就会沿着场景图走下去! :-D
With regards to your "how to do it wrong", I hate to break it to you, but it's not wrong; rather, it's incomplete. You need to do those kinds of work independently of the parent child relationship.
Here's an example of that: The wheel is attached to the car just like you mentioned. If you translate or rotate the car, you don't need to touch the wheels - they're in the same location relative to the car. However, when you try to get the wheel's new location in the 'real world', you have to traverse down the tree, applying the matrix transformations as you go. That all works, right?
When you rotate an object, it rotates around its OWN origin. So a wheel should probably be rotating around its y axis, and a planet around its z axis. But now if you need to move a planet "around the sun", you're doing something completely different. This has to be calculated separately. That's not to say it's not going to be eased by using some of the same match you already have, (although I can't say for sure without doing the math myself) but it's entirely different.
You're looking at actually changing the state of the object. That's the beauty of the scene graph! If you didn't have a scene graph, you would have to figure out all the various values all the way back to the main scene and then do all kinds of math. Here, you just have to do a little bit of trig and algebra to move around the planet (you can google the celestial mechanics) and move the planet relative to its star. The next time the main scene asks where the planet is, it will just go down the scene graph! :-D
我认为这是正确的行为。
我不认为围绕父级的原点旋转可以通过简单的矩阵堆栈来完成。我认为你只能从父母传播给孩子。
您可以尝试根据距父级绝对原点的偏移量设置相对旋转和变换,尽管这比简单地推入矩阵堆栈需要更多的计算。
这是一个类似的问题: 从内部获取绝对位置和旋转场景图?
I think this is the correct behavior.
I don't think rotating around the parent's origin is something that can be accomplished with a simple matrix stack. I think you can only propagate from parents to children.
You could try instead setting the relative rotation and transformation based on offsets from the parent's absolute origin, though that's a lot more calculations than simply pushing onto a matrix stack.
Here's a similar question: Getting absolute position and rotation from inside a scene graph?
这取决于您使用的是 OpenGL 还是 Direct3D。在 OpenGL 中,变换是从右到左应用的,而在 Direct3D 中,它们是从左到右应用的。它们都是设计变换系统的完全有效的方法,但这意味着您必须以不同的方式思考它们。
我发现在 OpenGL 系统中思考是最容易的,但是相反。我没有考虑从右到左应用变换时对象的顶点如何移动,而是想象对象的坐标系按从左到右的顺序进行变换。每个变换都是相对于新的局部坐标系应用的,而不是相对于世界坐标系。
对于汽车上的车轮而言,涉及三个变换:汽车在空间中的位置、车轮相对于汽车的原点以及车轮相对于中性位置的方向。只需按照从左到右的顺序应用它们(对于 Direct3D 反之亦然)。要绘制四个轮子,首先应用汽车的变换,然后记住当前的变换,然后依次应用位置和方向变换,每次之后返回到记住的汽车变换。
It depends on whether you are using OpenGL or Direct3D. In OpenGL, transforms are applied right-to-left, whereas in Direct3D, they apply left-to-right. They are both perfectly valid ways of designing the transform system, but it means you have to think about them differently.
I find it easiest to think in OpenGL's system, but in reverse. Instead of thinking about how the vertices of an object move around as transforms are applied right-to-left, I imagine the coordinate system of the object being transformed in a left-to-right order. Each transform is applied relative to the new local coordinate system, not relative to the world.
In the case of the wheels on the car, there are three transforms involved: the car's position in space, a wheel's origin relative to the car, and the wheel's orientation relative to its neutral position. Simply apply these in left-to-right order (or vice-versa for Direct3D). To draw four wheels, first apply the car's transform, then remember the current transform, then apply the location and orientation transforms in turn, going back to the remembered car transform after each.