Godot如何修复旋转精度错误
我有一个骨架,我的程序每帧都会旋转它。使用起始方向向量(骨骼位置到其尖端的起始位置)和结束方向向量(骨骼位置到其尖端的结束位置)来计算旋转角度和轴。每帧骨骼的骨骼从起始向量完全旋转到结束向量。对于前 70 帧,一切都很好并且旋转正确。然而,在那之后,旋转中出现了明显的错误。每帧误差都会变得越来越大,直到旋转完全错误。我认为发生这种情况是因为精度误差导致该误差累积。
在 Godot 文档中它说:
如果变换每帧都旋转,它最终会随着时间的推移开始变形。这是不可避免的。
有两种不同的方法来处理这个问题。第一个是在一段时间后对变换进行正交归一化(如果每帧都修改它,则可能每帧一次):
为了解决这个问题,我尝试了这个:
transform.orthonormalized()
这似乎没有改变任何东西,错误仍然存在。
我正在考虑使用 .look_at()
方法而不是按轴和角度旋转,但我不确定是否存在精度误差。另外,我不确定如何在骨架的骨头上调用该方法。
解决这个问题的最佳方法是什么?
I have a skeleton that my program rotates every frame. The rotation angle and axis is calculated using a starting direction vector (the bone position to the start position of its tip) and an ending direction vector (the bone position to the end position of its tip). The bones of the skeleton are rotated completely from the starting vector to the ending vector each frame. For the first 70 frames everything is fine and it rotates correctly. However, after that point, there are visible errors in the rotations. Each frame the error gets bigger and bigger until the rotation is completely wrong. I think this happens because of a precision error that causes this error to accumulate.
In the Godot docs it says:
If a transform is rotated every frame, it will eventually start deforming over time. This is unavoidable.
There are two different ways to handle this. The first is to orthonormalize the transform after some time (maybe once per frame if you modify it every frame):
To fix this issue I tried this:
transform.orthonormalized()
Which didn't seem to change anything, the errors were still there.
I was thinking of using the .look_at()
method instead of rotating by an axis and angle, but I'm not sure if the precision errors would be there or not. Also, I'm not sure how to call that method on a bone of a skeleton.
What's the best way to fix this problem?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
新答案
因此,您正在处理物理……
让我们重建转换。我们可以从所拥有的转换中提取所需的零件:
您要施加旋转,并保留其他零件。所以
我认为那是:
,或者您需要放置
旋转 * transform.basis.get_rotation_quat()
而不是。,我们从中构建了一个转换,我相信这就像这:
而且,如果没有摆脱累积错误,则应该:
旧答案
此答案假设您正在制作程序化动画。
创建启动和结束旋转(Quataternions或Axis Angle),并且每个帧都使用从终点插值旋转创建一个新的变换。也就是说,您希望从运动开始的旋转,而不是从先前框架旋转的变换。
对于插值,您可能需要使用将经过时间比总时间的比率作为权重。因此,我的意思是您将在动画开始的总时间开始,因此您将分开时间。
因此,让我们说,动画从
start_time
开始,必须将total_time
完成才能完成。在即时current_time
的情况下,您有:重量为
elapsed_time/total_time
,这是:我不知道您如何处理时间。但是,请注意,如果您使用的是
os.get_ticks_msec()
,例如,它可以使您作为整数,那么当您希望在之间浮动时,您将拥有一个整数划分。 0.0
和1.0
用于插值。因此,您需要在分裂之前施放浮动。同样,如果要将旋转应用于原始变换,请不要在每个帧中应用增量旋转。相反,每个帧将原始变换与从运动开始到当前帧的旋转结合在一起。
由于旋转不会基于先前的帧,因此错误不会累积。
New Answer
So you are dealing with physics…
Let us rebuild the transform instead. We can extract the parts we need from the transform we have:
And you have a rotation you want to apply, keeping the other parts. So
I think that would be:
Or you need to put
rotation * transform.basis.get_rotation_quat()
instead.And we build a transform from that, which I believe would be like this:
And, if that does not get rid of the accumulated error, this should:
Old Answer
This answer assumes you are making programmatic animations.
Create start and end rotations (either quaternions or axis angle), and each frame create a new transform using an interpolated rotation from the end points. That is, you want the a transform that represents the rotation from the start of the motion, not the rotation from the prior frame.
For the interpolation, you probably want to use the ratio of elapsed time over total time as weight. And by that I mean that you would divide the time since the animation started over the total time the animation must take.
So, let us say, the animation started at
start_time
, and must taketotal_time
to complete. At the instantcurrent_time
, you have:And the weight would be
elapsed_time/total_time
, which is:I don't know how you are handling time. However, be aware that if you are using something like
OS.get_ticks_msec()
for example, which gives you milliseconds as an integer, then you would have an integer division when you want a float between0.0
and1.0
for the interpolation. So you would need to cast to float before dividing.Similarly, if you want to apply the rotation to an original transform, do not apply incremental rotations each frame. Instead each frame combine the original transform with the rotation from the start of the motion to the current frame.
Since the rotations would not be based on the prior frame, the errors would not accumulate.
结合上面的Theraot的答案,我还发现,在计算旋转轴和角度之前重置转换有助于消除精确错误。
像:
In combination with Theraot's answer above, I also found that resetting the Transform before calculating the rotation axis and angle helped to remove precision errors.
Something like: