【问题标题】:how to sort objects for Guendelman shock propagation?如何对 Guendelman 冲击传播的对象进行分类?
【发布时间】:2012-06-07 04:50:50
【问题描述】:

这是一个关于在 3D 中形成地形树的问题。一点上下文:我有一个物理引擎,其中有身体和碰撞点以及一些约束。这不是家庭作业,而是多线程实验。

我需要使用属于本文档中的图层的对象组以自下而上的方式对主体进行排序:请参阅“冲击传播”部分 http://www2.imm.dtu.dk/visiondag/VD05/graphical/slides/kenny.pdf

他用来描述如何遍历树的伪代码非常有意义:

shock-propagation(algorithm A)
compute contact graph
for each stack layer in bottom up order
     fixate bottom-most objects of layer
     apply algorithm A to layer
     un-fixate bottom-most objects of layer
next layer

我已经找到了算法 A(我的脉冲代码)。 具有 3D 点列表的树/层排序(拓扑排序?)的伪代码是什么样的?

即,我不知道在哪里停止/开始下一个“梯级”或“分支”。我想我可以将它按 y 位置分块,但这看起来很笨重且容易出错。我是否查看topographical sorting? 我真的不知道如何在 3D 中进行此操作。如果这是这样做的方法,我将如何获得拓扑排序的“边缘”?

我是不是想太多了,我只是通过找到点 p1 然后是 p2.y > p1.y 的最远下一个点 p2 来“连接点”?我在这里看到一个问题,使用纯距离,p1 到 p0 的距离可能大于 p2,这会导致排序错误。

【问题讨论】:

    标签: sorting 3d distance topology


    【解决方案1】:

    我自己解决了这个问题。

    我在链接到本文的可下载源代码中找到了如何完成此操作的示例:

    http://www-cs-students.stanford.edu/~eparker/files/PhysicsEngine/

    特别是从第 221 行开始的 WorldState.cs 文件。

    但想法是您为所有静态对象分配级别-1,并为每个其他对象分配不同的默认级别,例如-2。然后,对于与级别 -1 的物体的每次碰撞,您将与之碰撞的物体添加到列表中,并将其级别设置为 0。

    之后使用 while 循环 while(list.Count > 0) 检查与它发生碰撞的物体并将其设置为 body.level + 1。

    之后,对于模拟中仍然具有默认级别(我之前说过 -2)的每个主体,将其级别设置为最高级别。

    还有一些更精细的细节,但查看示例中的代码会比以往任何时候都更好地解释它。

    希望对你有帮助!

    来自 Evan Parker 代码的相关代码。 [斯坦福]

    {{{
    
    // topological sort (bfs)
                // TODO check this
                int max_level = -1;
                while (queue.Count > 0)
                {
                    RigidBody a = queue.Dequeue() as RigidBody;
                    //Console.Out.WriteLine("considering collisions with '{0}'", a.Name);
                    if (a.level > max_level) max_level = a.level;
                    foreach (CollisionPair cp in a.collisions)
                    {
                        RigidBody b = (cp.body[0] == a ? cp.body[1] : cp.body[0]);
                        //Console.Out.WriteLine("considering collision between '{0}' and '{1}'", a.Name, b.Name);
                        if (!b.levelSet)
                        {
                            b.level = a.level + 1;
                            b.levelSet = true;
                            queue.Enqueue(b);
                            //Console.Out.WriteLine("found body '{0}' in level {1}", b.Name, b.level);
                        }
                    }
                }
    
                int num_levels = max_level + 1;
    
                //Console.WriteLine("num_levels = {0}", num_levels);
    
                ArrayList[] bodiesAtLevel = new ArrayList[num_levels];
                ArrayList[] collisionsAtLevel = new ArrayList[num_levels];
                for (int i = 0; i < num_levels; i++)
                {
                    bodiesAtLevel[i] = new ArrayList();
                    collisionsAtLevel[i] = new ArrayList();
                }
    
                for (int i = 0; i < bodies.GetNumBodies(); i++)
                {
                    RigidBody a = bodies.GetBody(i);
                    if (!a.levelSet || a.level < 0) continue; // either a static body or no contacts
    
                    // add a to a's level
                    bodiesAtLevel[a.level].Add(a);
    
                    // add collisions involving a to a's level
                    foreach (CollisionPair cp in a.collisions)
                    {
                        RigidBody b = (cp.body[0] == a ? cp.body[1] : cp.body[0]);
                        if (b.level <= a.level) // contact with object at or below the same level as a
                        {
                            // make sure not to add duplicate collisions
                            bool found = false;
                            foreach (CollisionPair cp2 in collisionsAtLevel[a.level])
                                if (cp == cp2) found = true;
    
                            if (!found) collisionsAtLevel[a.level].Add(cp);
                        }
                    }
                }
    
                for (int step = 0; step < num_contact_steps; step++)
                {
                    for (int level = 0; level < num_levels; level++)
                    {
                        // process all contacts
                        foreach (CollisionPair cp in collisionsAtLevel[level])
                        {
                            cp.ResolveContact(dt, (num_contact_steps - step - 1) * -1.0f/num_contact_steps);
                        }
                    }
                }
    
    }}}
    

    【讨论】:

    • 我之前确实遇到过这个问题,但是无法编译,也没有时间调试错误。最后,我的算法有点接近了,足以工作。
    猜你喜欢
    • 1970-01-01
    • 2021-10-27
    • 2019-05-29
    • 2019-03-12
    • 1970-01-01
    • 1970-01-01
    • 2020-05-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多