我正在尝试让基本的碰撞动力学发挥作用

发布于 2024-08-20 18:58:17 字数 9674 浏览 7 评论 0原文

我将事情简化为立方体/单个立方体与无限质量矩形碰撞和以下代码:

问题是,盒子往往旋转太多并粘在一起旋转,如果包含二分搜索,则只需经常击打和旋转。

感谢您的任何和所有帮助。

/// <summary>
/// Projects an abstract 1D line "perpendicular" to the axis, 
/// stretching across the width of the model,
/// measured from that axis.
/// </summary>
/// <param name="Axis"></param>
/// <param name="Min"></param>
/// <param name="Max"></param>
protected virtual void ProjectToAxis(Vector2 Axis, IMotionData motionData, out double Min, out double Max)
{
    Double DotP = Axis.Dot(motionData.PositionGS + (this.Vertices[0].Position * this.Model.Scale).Rotate(motionData.RotationGS));

    Min = Max = DotP;

    for (int t = 1; t < this.Vertices.Count(); ++t)
    {
        DotP = Axis.Dot(motionData.PositionGS + (this.Vertices[t].Position * this.Model.Scale).Rotate(motionData.RotationGS));

        Min = Math.Min(DotP, Min);
        Max = Math.Max(DotP, Max);
    }
}


/// <summary>
/// Projects two imaginary lines even with each edge,
/// equal to the width of each object while looking at
/// that edge, then checks to see if they intersect.
/// </summary>
/// <param name="B1"></param>
/// <param name="B2"></param>
/// <returns></returns>
public static bool DetectCollision(Body B1, Body B2, Double elapsedSeconds)
{
    CollisionData collisionInfo = new CollisionData();
    double lowestDistance = double.MaxValue;
    double distance;

    Vector2 normalB1ToB2 = (B2.MotionHandler.PositionGS - B1.MotionHandler.PositionGS).Normalized;

    foreach (Edge edge in B1.Edges)
    {
        if (edge.Normal.RelativePosition.Dot(normalB1ToB2) >= 0.0)
        {
            double minA, minB, maxA, maxB;
            B1.ProjectToAxis(edge.Normal.RelativePosition, B1.MotionHandler.MotionDataGet, out minA, out maxA);
            B2.ProjectToAxis(edge.Normal.RelativePosition, B2.MotionHandler.MotionDataGet, out minB, out maxB);


            if (minA < minB)
                distance = minB - maxA;
            else
                distance = minA - maxB;

            if (distance > 0.0f)
                return false;
            else if (Math.Abs(distance) < lowestDistance)
            {
                lowestDistance = Math.Abs(distance);

                collisionInfo.Normal = edge.Normal.RelativePosition;
                collisionInfo.Edge = edge;
            }
        }
    }


    Vector2 normalB2ToB1 = -normalB1ToB2;


    foreach (Edge edge in B2.Edges)
    {
        if (edge.Normal.RelativePosition.Dot(normalB2ToB1) >= 0.0)
        {
            double minA, minB, maxA, maxB;
            B1.ProjectToAxis(edge.Normal.RelativePosition, B1.MotionHandler.MotionDataGet, out minA, out maxA);
            B2.ProjectToAxis(edge.Normal.RelativePosition, B2.MotionHandler.MotionDataGet, out minB, out maxB);

            if (minA < minB)
                distance = minB - maxA;
            else
                distance = minA - maxB;

            if (distance > 0.0f)
                return false;
            else if (Math.Abs(distance) < lowestDistance)
            {
                lowestDistance = Math.Abs(distance);

                collisionInfo.Normal = edge.Normal.RelativePosition;
                collisionInfo.Edge = edge;
            }
        }
    }


    collisionInfo.Depth = lowestDistance;


    /* Double lowHighSeconds = elapsedSeconds;
    Double highLowSeconds = 0.0;
    Double seconds;
    IMotionData md1;
    IMotionData md2;
    bool collision;
    do
    {
        md1 = B1.MotionHandler.MotionDataLastGet.Copy;
        md2 = B2.MotionHandler.MotionDataLastGet.Copy;

        collision = true;
        lowestDistance = Double.MaxValue;
        seconds = MathExtensions.MathExt.Lerp(highLowSeconds, lowHighSeconds, 0.5);

        B1.MotionHandler.Simulate(seconds, ref md1);
        B2.MotionHandler.Simulate(seconds, ref md2);


        normalB1ToB2 = (md2.PositionGS - md1.PositionGS).Normalized;

        foreach (Edge edge in B1.Edges)
        {
            if ((edge.Normal.Position * B1.Model.Scale).Rotate(md1.RotationGS).Dot(normalB1ToB2) >= 0.0)
            {
                double minA, minB, maxA, maxB;
                B1.ProjectToAxis((edge.Normal.Position * B1.Model.Scale).Rotate(md1.RotationGS), md1, out minA, out maxA);
                B2.ProjectToAxis((edge.Normal.Position * B1.Model.Scale).Rotate(md1.RotationGS), md2, out minB, out maxB);


                if (minA < minB)
                    distance = minB - maxA;
                else
                    distance = minA - maxB;

                if (distance > 0.0f)
                    collision = false;
                else if (Math.Abs(distance) < lowestDistance)
                {
                    lowestDistance = Math.Abs(distance);

                    collisionInfo.Normal = (edge.Normal.Position * B1.Model.Scale).Rotate(md1.RotationGS);
                    collisionInfo.Edge = edge;
                }
            }
        }


        normalB2ToB1 = -normalB1ToB2;


        foreach (Edge edge in B2.Edges)
        {
            if ((edge.Normal.Position * B2.Model.Scale).Rotate(md2.RotationGS).Dot(normalB2ToB1) >= 0.0)
            {
                double minA, minB, maxA, maxB;
                B2.ProjectToAxis((edge.Normal.Position * B2.Model.Scale).Rotate(md2.RotationGS), md2, out minA, out maxA);
                B1.ProjectToAxis((edge.Normal.Position * B2.Model.Scale).Rotate(md2.RotationGS), md1, out minB, out maxB);


                if (minA < minB)
                    distance = minB - maxA;
                else
                    distance = minA - maxB;

                if (distance > 0.0f)
                    collision = false;
                else if (Math.Abs(distance) < lowestDistance)
                {
                    lowestDistance = Math.Abs(distance);

                    collisionInfo.Normal = (edge.Normal.Position * B2.Model.Scale).Rotate(md2.RotationGS);
                    collisionInfo.Edge = edge;
                }
            }
        }

        collisionInfo.Depth = lowestDistance;

        if (!collision)
        {
            lowHighSeconds = seconds;
        }
        else
        {
            highLowSeconds = seconds;
        }
    } while (Math.Abs(highLowSeconds - lowHighSeconds) > 0.0001);

    B1.MotionHandler.MotionDataSet = md1;
    B2.MotionHandler.MotionDataSet = md2; */

    // bool flip = false;
    if (collisionInfo.Edge.Parent != B2.Model)
    {
        Body temp = B1;
        B1 = B2;
        B2 = temp;
    }


    //This is needed to make sure that the collision normal is pointing at B1
    int Sign = Math.Sign(
        collisionInfo.Normal.Dot(
            B1.MotionHandler.MotionDataGet.PositionGS + (B1.Center * B1.Model.Scale).Rotate(B1.MotionHandler.MotionDataGet.RotationGS) -
            B2.MotionHandler.MotionDataGet.PositionGS + (B2.Center * B2.Model.Scale).Rotate(B2.MotionHandler.MotionDataGet.RotationGS)
        )
    );

    //Remember that the line equation is N*( R - R0 ). We choose B2->Center 
    //as R0; the normal N is given by the collision normal

    if (Sign != 1)
        collisionInfo.Normal = -collisionInfo.Normal; //Revert the collision normal if it points away from B1


    double SmallestD = double.MaxValue; //Initialize the smallest distance to a high value
        //Measure the distance of the vertex from the line using the line equation
    for (int t = 0; t < B1.Vertices.Count(); ++t)
    {
        double Distance = collisionInfo.Normal.Dot(B1.Vertices[t].WorldPosition - B2.Center);

        // If the measured distance is smaller than the smallest distance reported 
        // so far, set the smallest distance and the collision vertex
        if (Distance < SmallestD)
        {
            SmallestD = Distance;
            collisionInfo.Vertex = B1.Vertices[t];
        }
    }


    if ((Body.CollisionType & CollisionType.Velocity) > 0)
    {
        Vector2 vab1 = B1.MotionHandler.VelocityGS - B2.MotionHandler.VelocityGS;

        Vector2 rap = (B1.MotionHandler.PositionGS - collisionInfo.Normal);
        Vector2 rbp = (B2.MotionHandler.PositionGS - collisionInfo.Normal);

        Double rap2 = (rap.Cross(collisionInfo.Normal));
        Double rbp2 = (rbp.Cross(collisionInfo.Normal));

        Vector2 one = (collisionInfo.Vertex.WorldPosition - B1.MotionHandler.PositionGS).GetPerpendicular;
        Vector2 two = (collisionInfo.Vertex.WorldPosition - B2.MotionHandler.PositionGS).GetPerpendicular;

        Double j = (-(1 + 0.0) * vab1.Dot(collisionInfo.Normal)) /
            ((collisionInfo.Normal.Dot(collisionInfo.Normal) * (B1.MotionHandler.InverseMassGS + B2.MotionHandler.InverseMassGS)) +
            (one.Dot(one) * B1.MotionHandler.InverseInertiaGS) + (two.Dot(two) * B2.MotionHandler.InverseInertiaGS));


        B1.MotionHandler.AddImpulse = new Force(
            collisionInfo.Normal,
            j /* ,
            one */
        );
        B2.MotionHandler.AddImpulse = new Force(
            collisionInfo.Normal,
            -(j) /* ,
            two */
        );


        NewtonianMotionData data1 = (NewtonianMotionData)B1.MotionHandler.MotionDataGet;
        NewtonianMotionData data2 = (NewtonianMotionData)B2.MotionHandler.MotionDataGet;

        data1.AngularVelocity += (one.Dot(j * collisionInfo.Normal)) * data1.inverseInertia;
        data2.AngularVelocity += (two.Dot(-j * collisionInfo.Normal)) * data2.inverseInertia;

        B1.MotionHandler.MotionDataSet = data1;
        B2.MotionHandler.MotionDataSet = data2;
    }

    return true;
}

I've simplified things down to cubes/a single cube colliding with an infinite-mass rectangle and the following code:

The problem is, the boxes tend to spin too much and get stuck together spinning and, if the binary search is included, just hit and spin a lot.

Thanks for any and all help.

/// <summary>
/// Projects an abstract 1D line "perpendicular" to the axis, 
/// stretching across the width of the model,
/// measured from that axis.
/// </summary>
/// <param name="Axis"></param>
/// <param name="Min"></param>
/// <param name="Max"></param>
protected virtual void ProjectToAxis(Vector2 Axis, IMotionData motionData, out double Min, out double Max)
{
    Double DotP = Axis.Dot(motionData.PositionGS + (this.Vertices[0].Position * this.Model.Scale).Rotate(motionData.RotationGS));

    Min = Max = DotP;

    for (int t = 1; t < this.Vertices.Count(); ++t)
    {
        DotP = Axis.Dot(motionData.PositionGS + (this.Vertices[t].Position * this.Model.Scale).Rotate(motionData.RotationGS));

        Min = Math.Min(DotP, Min);
        Max = Math.Max(DotP, Max);
    }
}


/// <summary>
/// Projects two imaginary lines even with each edge,
/// equal to the width of each object while looking at
/// that edge, then checks to see if they intersect.
/// </summary>
/// <param name="B1"></param>
/// <param name="B2"></param>
/// <returns></returns>
public static bool DetectCollision(Body B1, Body B2, Double elapsedSeconds)
{
    CollisionData collisionInfo = new CollisionData();
    double lowestDistance = double.MaxValue;
    double distance;

    Vector2 normalB1ToB2 = (B2.MotionHandler.PositionGS - B1.MotionHandler.PositionGS).Normalized;

    foreach (Edge edge in B1.Edges)
    {
        if (edge.Normal.RelativePosition.Dot(normalB1ToB2) >= 0.0)
        {
            double minA, minB, maxA, maxB;
            B1.ProjectToAxis(edge.Normal.RelativePosition, B1.MotionHandler.MotionDataGet, out minA, out maxA);
            B2.ProjectToAxis(edge.Normal.RelativePosition, B2.MotionHandler.MotionDataGet, out minB, out maxB);


            if (minA < minB)
                distance = minB - maxA;
            else
                distance = minA - maxB;

            if (distance > 0.0f)
                return false;
            else if (Math.Abs(distance) < lowestDistance)
            {
                lowestDistance = Math.Abs(distance);

                collisionInfo.Normal = edge.Normal.RelativePosition;
                collisionInfo.Edge = edge;
            }
        }
    }


    Vector2 normalB2ToB1 = -normalB1ToB2;


    foreach (Edge edge in B2.Edges)
    {
        if (edge.Normal.RelativePosition.Dot(normalB2ToB1) >= 0.0)
        {
            double minA, minB, maxA, maxB;
            B1.ProjectToAxis(edge.Normal.RelativePosition, B1.MotionHandler.MotionDataGet, out minA, out maxA);
            B2.ProjectToAxis(edge.Normal.RelativePosition, B2.MotionHandler.MotionDataGet, out minB, out maxB);

            if (minA < minB)
                distance = minB - maxA;
            else
                distance = minA - maxB;

            if (distance > 0.0f)
                return false;
            else if (Math.Abs(distance) < lowestDistance)
            {
                lowestDistance = Math.Abs(distance);

                collisionInfo.Normal = edge.Normal.RelativePosition;
                collisionInfo.Edge = edge;
            }
        }
    }


    collisionInfo.Depth = lowestDistance;


    /* Double lowHighSeconds = elapsedSeconds;
    Double highLowSeconds = 0.0;
    Double seconds;
    IMotionData md1;
    IMotionData md2;
    bool collision;
    do
    {
        md1 = B1.MotionHandler.MotionDataLastGet.Copy;
        md2 = B2.MotionHandler.MotionDataLastGet.Copy;

        collision = true;
        lowestDistance = Double.MaxValue;
        seconds = MathExtensions.MathExt.Lerp(highLowSeconds, lowHighSeconds, 0.5);

        B1.MotionHandler.Simulate(seconds, ref md1);
        B2.MotionHandler.Simulate(seconds, ref md2);


        normalB1ToB2 = (md2.PositionGS - md1.PositionGS).Normalized;

        foreach (Edge edge in B1.Edges)
        {
            if ((edge.Normal.Position * B1.Model.Scale).Rotate(md1.RotationGS).Dot(normalB1ToB2) >= 0.0)
            {
                double minA, minB, maxA, maxB;
                B1.ProjectToAxis((edge.Normal.Position * B1.Model.Scale).Rotate(md1.RotationGS), md1, out minA, out maxA);
                B2.ProjectToAxis((edge.Normal.Position * B1.Model.Scale).Rotate(md1.RotationGS), md2, out minB, out maxB);


                if (minA < minB)
                    distance = minB - maxA;
                else
                    distance = minA - maxB;

                if (distance > 0.0f)
                    collision = false;
                else if (Math.Abs(distance) < lowestDistance)
                {
                    lowestDistance = Math.Abs(distance);

                    collisionInfo.Normal = (edge.Normal.Position * B1.Model.Scale).Rotate(md1.RotationGS);
                    collisionInfo.Edge = edge;
                }
            }
        }


        normalB2ToB1 = -normalB1ToB2;


        foreach (Edge edge in B2.Edges)
        {
            if ((edge.Normal.Position * B2.Model.Scale).Rotate(md2.RotationGS).Dot(normalB2ToB1) >= 0.0)
            {
                double minA, minB, maxA, maxB;
                B2.ProjectToAxis((edge.Normal.Position * B2.Model.Scale).Rotate(md2.RotationGS), md2, out minA, out maxA);
                B1.ProjectToAxis((edge.Normal.Position * B2.Model.Scale).Rotate(md2.RotationGS), md1, out minB, out maxB);


                if (minA < minB)
                    distance = minB - maxA;
                else
                    distance = minA - maxB;

                if (distance > 0.0f)
                    collision = false;
                else if (Math.Abs(distance) < lowestDistance)
                {
                    lowestDistance = Math.Abs(distance);

                    collisionInfo.Normal = (edge.Normal.Position * B2.Model.Scale).Rotate(md2.RotationGS);
                    collisionInfo.Edge = edge;
                }
            }
        }

        collisionInfo.Depth = lowestDistance;

        if (!collision)
        {
            lowHighSeconds = seconds;
        }
        else
        {
            highLowSeconds = seconds;
        }
    } while (Math.Abs(highLowSeconds - lowHighSeconds) > 0.0001);

    B1.MotionHandler.MotionDataSet = md1;
    B2.MotionHandler.MotionDataSet = md2; */

    // bool flip = false;
    if (collisionInfo.Edge.Parent != B2.Model)
    {
        Body temp = B1;
        B1 = B2;
        B2 = temp;
    }


    //This is needed to make sure that the collision normal is pointing at B1
    int Sign = Math.Sign(
        collisionInfo.Normal.Dot(
            B1.MotionHandler.MotionDataGet.PositionGS + (B1.Center * B1.Model.Scale).Rotate(B1.MotionHandler.MotionDataGet.RotationGS) -
            B2.MotionHandler.MotionDataGet.PositionGS + (B2.Center * B2.Model.Scale).Rotate(B2.MotionHandler.MotionDataGet.RotationGS)
        )
    );

    //Remember that the line equation is N*( R - R0 ). We choose B2->Center 
    //as R0; the normal N is given by the collision normal

    if (Sign != 1)
        collisionInfo.Normal = -collisionInfo.Normal; //Revert the collision normal if it points away from B1


    double SmallestD = double.MaxValue; //Initialize the smallest distance to a high value
        //Measure the distance of the vertex from the line using the line equation
    for (int t = 0; t < B1.Vertices.Count(); ++t)
    {
        double Distance = collisionInfo.Normal.Dot(B1.Vertices[t].WorldPosition - B2.Center);

        // If the measured distance is smaller than the smallest distance reported 
        // so far, set the smallest distance and the collision vertex
        if (Distance < SmallestD)
        {
            SmallestD = Distance;
            collisionInfo.Vertex = B1.Vertices[t];
        }
    }


    if ((Body.CollisionType & CollisionType.Velocity) > 0)
    {
        Vector2 vab1 = B1.MotionHandler.VelocityGS - B2.MotionHandler.VelocityGS;

        Vector2 rap = (B1.MotionHandler.PositionGS - collisionInfo.Normal);
        Vector2 rbp = (B2.MotionHandler.PositionGS - collisionInfo.Normal);

        Double rap2 = (rap.Cross(collisionInfo.Normal));
        Double rbp2 = (rbp.Cross(collisionInfo.Normal));

        Vector2 one = (collisionInfo.Vertex.WorldPosition - B1.MotionHandler.PositionGS).GetPerpendicular;
        Vector2 two = (collisionInfo.Vertex.WorldPosition - B2.MotionHandler.PositionGS).GetPerpendicular;

        Double j = (-(1 + 0.0) * vab1.Dot(collisionInfo.Normal)) /
            ((collisionInfo.Normal.Dot(collisionInfo.Normal) * (B1.MotionHandler.InverseMassGS + B2.MotionHandler.InverseMassGS)) +
            (one.Dot(one) * B1.MotionHandler.InverseInertiaGS) + (two.Dot(two) * B2.MotionHandler.InverseInertiaGS));


        B1.MotionHandler.AddImpulse = new Force(
            collisionInfo.Normal,
            j /* ,
            one */
        );
        B2.MotionHandler.AddImpulse = new Force(
            collisionInfo.Normal,
            -(j) /* ,
            two */
        );


        NewtonianMotionData data1 = (NewtonianMotionData)B1.MotionHandler.MotionDataGet;
        NewtonianMotionData data2 = (NewtonianMotionData)B2.MotionHandler.MotionDataGet;

        data1.AngularVelocity += (one.Dot(j * collisionInfo.Normal)) * data1.inverseInertia;
        data2.AngularVelocity += (two.Dot(-j * collisionInfo.Normal)) * data2.inverseInertia;

        B1.MotionHandler.MotionDataSet = data1;
        B2.MotionHandler.MotionDataSet = data2;
    }

    return true;
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

悲喜皆因你 2024-08-27 18:58:17

你有两个问题。

1)代码有问题。你需要解决这个问题。

2)你不知道如何弄清楚“某物”是什么。

解决第一个问题取决于解决第二个问题。您需要学习如何调试您刚刚编写的程序。

您已经对其进行了测试并得到了您认为毫无意义的结果。这是很好的第一步。现在进一步分解。在这个领域选择一个简单问题,您可以用铅笔和纸自己解决;这样做,然后观察您的算法在调试器中解决相同的问题,并检查整个过程中的每一步。 倾听安静而烦人的疑虑。当出现任何看起来稍有异常或意外的情况时,请停止正在做的事情并调查问题,直到您了解事情是否正常运行。最终你会发现某个步骤出现了问题,而这就是错误所在。

是的,这很乏味。当您发现错误并修复它时,请暂停并反思导致您首先编写该错误的原因,并找出如何不再编写此类错误。

更新:

回复:您最近的评论。

道歉被接受。现在冷静。如果你这么激动的话,你永远不会发现这个错误。你的大脑不会让你这么做。处于恐慌、激动状态的人会失去推理能力。这就是为什么防火门向外打开;逃离燃烧建筑物的人们实际上不会停下来思考“我正在推这扇门,但它没有打开,也许我应该尝试拉动”。他们只是更加努力。 我怀疑你做得更努力了。

调试需要理性对小细节的仔细关注。如果你对这个问题感到烦恼,那么这个问题就会被抛到九霄云外,而且只会变得更糟。 从经历过的人那里得到它。我们都经历过。如果你自己的程序中出现了一个错误,而你却无法发现它,这是一件非常令人沮丧的事情。

没有人帮助你的原因是……好吧,让我列出我必须满足的一组先决条件,以帮助你提供更多模糊的陈词滥调和如何集中调试工作的建议:

1)我有了解有关 3D 物理模拟的一些知识。 1992年,我对简单牛顿力学的微分方程有了相当不错的掌握,但从那以后我就没有使用过它。阻尼驱动弹簧的方程与刚体碰撞的方程有很大不同。如果我花几周时间复习笔记,我就能把数学知识带回来,但这是不现实的。您现在需要非常熟悉 3D 碰撞物理模拟的人。

2)我必须能够阅读和理解你的代码,这是由我以外的人编写的长达数百行的代码,以解决我不熟悉的问题。更糟糕的是,一百行代码被注释掉了。为什么?相关吗?是不是有bug在里面?此外,我需要能够阅读和理解代码,而无需在调试器中运行。哎呀,我什至无法编译该代码。这取决于我没有的库。

更糟糕的是,其中一个库可能包含该错误。据我所知,该错误是某些代码中的拼写错误,该代码在您未向我们展示的地方计算了法线。显示的代码可能是完美的。

3)我需要有空闲时间来解决别人的难题;编写代码并了解物理原理的人在这个问题上没有取得任何进展。

这些都是要求;如果缺少其中任何一项,读者就无法有效地为您提供帮助。你要求你不认识的人帮助你在午夜没有手电筒的情况下在黑暗的仓库里找到一只黑猫——一只可能根本不存在的猫。接受者很少并不奇怪。在阅读过您的问题的 74 个堆栈溢出用户中,有多少人满足所有三个要求?我没有遇到他们。

如果您需要有关此网站的帮助,请发布一个更简单的问题。将问题缩小到需要较少的物理和模拟算法专业知识并且只有相关代码的问题,最好是可以编译和运行的代码。

You've got two problems.

1) There's something wrong with the code. You need to fix that.

2) You don't know how to figure out what "something" is.

Solving the first problem is gated on your solving the second problem. You need to learn how to debug a program you just wrote.

You've already tested it and gotten a result which you've identified as nonsensical. That's a good first step. Now break it down even farther. Pick a simple problem in this domain that you can solve yourself with pencil and paper; do so, and then watch your algorithm solve the same problem in the debugger, checking every step along the way. Listen to quiet nagging doubts. When there is anything that looks slightly off or unexpected, stop what you're doing and investigate the issue until you understand whether things are working correctly or not. Eventually you'll find a step where things aren't as they should be, and that's where the bug is.

Yes, this is tedious. When you've found the bug and fixed it, pause and reflect upon what caused you to write the bug in the first place, and figure out how to not write that kind of bug ever again.

UPDATE:

Re: your recent comments.

Apology accepted. Now calm down. You're never going to find this bug if you're this worked up. Your brain will not let you. Humans who are in a panicky, worked-up state lose the ability to reason. That's why fire doors open outwards; humans fleeing a burning building literally will not stop to think "I'm pushing on this door and its not opening, maybe I should try pulling". They just push harder. I suspect you are pushing harder.

Debugging requires rationality and careful attention to small details. If you're all worked up about this problem then that's going to go out the window and its just going to get worse. Take it from someone who has been there. We've all been there. It's a deeply frustrating thing to have caused a bug in your own program that you then cannot find.

The reason no one is helping you is because... well, let me list the set of preconditions that have to be met for me to help you with more than vague platitudes and suggestions of how to focus your debugging efforts:

1) I have to know something about simulation of 3d physics. I had a pretty decent grasp of the differential equations of simple of Newtonian mechanics in 1992, but I haven't used it since. And the equation of a damped driven spring is rather different than the equations of rigid body collisions. If I spent a couple weeks reviewing my notes I could get the math back, but that's not realistic. You need someone who is deeply conversant right now with 3d collision physics simulations.

2) I have to be able to read and understand your code, code which is hundreds of lines long, written by someone other than me, to solve a problem I'm not familiar with. Worse, a hundred lines of that code is commented out. Why? Is it relevant? Is the bug in there? Moreover, I need to be able to read and understand the code without running it in a debugger. Heck, I can't even compile that code. It depends on libraries that I don't have.

And even worse still, one of those libraries might contain the bug. For all I know, the bug is a typo in some code that calculates a normal somewhere that you haven't shown us. The code shown could be perfect.

3) I need to have the free time to work on someone else's hard problem; a problem that the person who wrote the code and understands the physics is making no headway on.

All of these are requirements; if any one of them is missing, the reader cannot effectively help you. You're asking people you don't know to help you find a black cat in a dark warehouse at midnight without a flashlight -- a cat that might not even be there. It's not surprising you're getting few takers. Of the 74 stack overflow users who have read your question, how many of them meet all three requirements? I meet none of them.

If you want help on this site then post an easier problem. Narrow the problem down to a problem that requires less special knowledge of physics and simulation algorithms and has only the relevant code, preferably code that can be compiled and run.

鹿港小镇 2024-08-27 18:58:17

这可能不是个好消息,但我有几件事要补充到埃里克·利珀特的分析中,并提出一个建议。

你的评论具有误导性。我知道,如果你不熟悉数学和物理,很难精确,但看看“ProjectToAxis”:

/// Projects an abstract 1D line "perpendicular" to the axis,  
/// stretching across the width of the model, 
/// measured from that axis. 

如果这听起来很刺耳,请原谅我,但

  • “抽象一维线”有点毫无意义,它应该只是说“线”。
  • 它并不是真正投影一条线。
  • 它测量的是平行于轴的范围,而不是垂直于轴的范围。
  • 确切地说,它不是“跨宽度”,而是最大程度。
  • “从该轴测量”要么毫无意义,要么是错误的,我不知道是哪一个。

相信我,我并不是想挑剔,只是想弄清楚这段代码应该做什么,而一个糟糕的评论比没有更糟糕。我可以看到这个函数的作用(假设像“Dot”这样的函数如宣传的那样工作),但我仍然不知道它是否能实现您想要的功能。

现在我看一下 DetectCollision(它不仅仅检测碰撞):

/// Projects two imaginary lines even with each edge, 
/// equal to the width of each object while looking at 
/// that edge, then checks to see if they intersect. 

什么?我所能做的就是忽略它并查看代码...其中有些部分不'这没有多大意义(例如,为什么要将物体投影到其每一个边缘上?),因此逆向工程将非常困难。

如果我知道你正在尝试的算法,我可以尝试找到错误。如果代码有效,我可以尝试推导算法。但如果代码不起作用并且(正如我怀疑的那样)你自己并不真正了解算法,我们就会陷入困境。

这是一种可能有效的方法:这个函数太长,它做了很多事情,而且你不知道它正确地完成了哪些部分。因此,您应该将其分解为几个函数并单独测试它们。 (我自己不能这样做,原因埃里克·利珀特(Eric Lippert)阐明了。)您可以首先分成两个函数,一个计算 CollisionInfo(保持物体不变),另一个调整物体的运动(保持 CollisionInfo 不变) )。

This may not be good news, but I have a couple of things to add to Eric Lippert's analysis, and a suggestion.

Your comments are misleading. I know that if you're not familiar with math and physics it's hard to be precise, but take a look at "ProjectToAxis":

/// Projects an abstract 1D line "perpendicular" to the axis,  
/// stretching across the width of the model, 
/// measured from that axis. 

Forgive me if this sounds harsh, but

  • "abstract 1d line" is kind of meaningless, it should just say "line".
  • It's not really projecting a line.
  • It's measuring extent parallel to the axis, not perpendicular to it.
  • It's not "across the width", exactly, it's just the greatest extent.
  • "measured from that axis" is either meaningless or wrong, I can't tell which.

Believe me, I'm not trying to pick nits, it's just that I'm trying to figure out what this code is supposed to do, and a bad comment is worse than none. I can see what this function does (assuming that functions like "Dot" work as advertised), but I still don't know whether it does what you want it to do.

Now I take a look at DetectCollision (which does more than just detect a collision):

/// Projects two imaginary lines even with each edge, 
/// equal to the width of each object while looking at 
/// that edge, then checks to see if they intersect. 

What? All I can do is ignore this and look at the code... There are parts of it that don't make much sense (e.g. why the heck do you project a body onto every one of its edges?), so reverse-engineering is going to be very difficult.

If I knew the algorithm you were trying for, I could try to find the bug. If the code worked, I could try to deduce the algorithm. But if the code doesn't work and (as I suspect) you don't really know the algorithm yourself, we're kind of stuck.

Here's an approach that might work: This function is too long, it does a lot, and you don't know which parts it does correctly. Ergo you should break it down into several functions and test them individually. (I can't do that myself, for the reasons Eric Lippert spelled out.) You could start by breaking into two functions, one that calculates CollisionInfo (leaving the bodies constant) and another that adjusts the motion of the bodies (leaving CollisionInfo constant).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文