Unity3D 中具有距离约束和碰撞检测抖动的 Verlet 集成问题,用于简单绳索

问题描述

我正在尝试在 Unity3D 中实现无速度的 Verlet 集成算法。

我从更新每个粒子的位置开始,使用previos和当前位置来计算粒子的速度,然后我添加距离约束以使我的粒子与每个粒子保持一定的距离其他。一切正常!

之后,我为Sphere、CubeCapsule 等基本基元添加了碰撞处理。一切正常!

之后我注意到,我的粒子在不使用粒子半径的情况下在碰撞的网格表面上推开。换句话说,绳子粒子在那一刻只是 3D 空间中的点。我希望它们是具有半径的球体。

我开始修改我的代码以在碰撞计算中使用粒子半径。我现在设法使用 Sphere ColliderCapsule Collider 来做到这一点。一切正常!

在那之后我遇到了麻烦:粒子现在在碰撞时会抖动,我的意思是那一刻绳子不动了。我认为,这个问题是距离约束和碰撞约束相互冲突。

一方面,距离约束方法试图将粒子之间的距离保持在指定值,另一方面,碰撞约束方法只是将粒子推开,如果它们在里面对撞机。我认为它推动粒子并在下一个固定步骤中 粒子之间的距离大于指定值。并且永远如此......

如果问题真的在那里,我该如何解决这个问题?非常感谢您的回答!

下面是一些源代码和gif示例:

Fixed Update Loop

Sphere Check Code Example

Gif

这个问题也跑题了:这个立方体句柄碰撞代码是否正确?下面的代码片段后的 Gif 示例 :)

                        for (int j = 0; j < collision.CollisionAmount; j++)
                        {
                            Particle particle = particles[collision.CollidingNodes[j]];

                            //Local position of particle relative to Cube
                            Vector3 localPos = collision.Transform.InverseTransformPoint(particle.current);

                            //Half size of Cube
                            Vector3 half = collision.Size * 0.5f;
                            Vector3 scale = collision.Transform.localScale;

                            float diffX = half.x - Mathf.Abs(localPos.x);

                            if (diffX <= 0)
                            {
                                continue;
                            }

                            float diffY = half.y - Mathf.Abs(localPos.y);

                            if (diffY <= 0)
                            {
                                continue;
                            }

                            float diffZ = half.z - Mathf.Abs(localPos.z);

                            if (diffZ <= 0)
                            {
                                continue;
                            }

                            float diffXZ = diffX * scale.x - diffZ * scale.z;
                            float diffXY = diffX * scale.x - diffY * scale.y;
                            float diffZY = diffZ * scale.z - diffY * scale.y;

                            if (diffXZ < 0)
                            {
                                //X < Z
                                if (diffXY < 0)
                                {
                                    localPos.x = (half.x )* Mathf.Sign(localPos.x);
                                }
                                else
                                {
                                    localPos.y = (half.y ) *  Mathf.Sign(localPos.y);
                                }
                            }
                            else if (diffXZ >= 0)
                            {
                                // X >= Z
                                if (diffZY < 0)
                                {
                                    localPos.z = (half.z )* Mathf.Sign(localPos.z);
                                }
                                else
                                {
                                    localPos.y = (half.y)*  Mathf.Sign(localPos.y);
                                }
                            }
                            else if (diffXY < 0)
                            {
                                //X < Y
                                if (diffXZ < 0)
                                {
                                    localPos.x = (half.x )* Mathf.Sign(localPos.x);
                                }
                                else
                                {
                                    localPos.z = (half.z )* Mathf.Sign(localPos.z);
                                }
                            }
                            else
                            {
                                //X >= Y
                                if (diffZY < 0)
                                {
                                    localPos.z = (half.z ) * Mathf.Sign(localPos.z);
                                }
                                else
                                {
                                    localPos.y = (half.y ) * Mathf.Sign(localPos.y);
                                }
                            }

                            particle.current = collision.Transform.TransformPoint(localPos);

                            particles[collision.CollidingNodes[j]] = particle;
                        }
                        break;

Cube Collision

Cube Collision 2

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)