Unity 3D - 泛洪填充/油漆桶算法可防止引擎崩溃

时间:2012-03-03 13:16:31

标签: algorithm colors paint unity3d flood-fill

我一直在尝试编写一个可在Unity中运行的泛洪填充算法。该想法是基于用户选择的颜色对黑白线图的部分进行着色。我已经尝试了泛洪填充算法的几种实现,但是当它们被调用时它们都会导致统一挂起。

非常感谢任何有关这方面的帮助,这是一个重要项目的一部分。任何有关代码修改,算法设计或任何其他方法的建议都将非常感激:)

代码:

// FloodFill function
void FloodFill()
{
    // TEST - colour the clicked pixel
    //_tex.SetPixel( (int)_pixelUV.x, (int)_pixelUV.y, m_fillColour );
    //_tex.SetPixel( _pixelX, _pixelY, m_fillColour );


    // FLOOD FILL 
    // ----------

    // Create WestEast
    List<Point> m_WestEast;

    //get the pixel's colour
    Color PC = new Color(_tex.GetPixel(m_StartNode.X, m_StartNode.Y).r, _tex.GetPixel(m_StartNode.X, m_StartNode.Y).g, _tex.GetPixel(m_StartNode.X, m_StartNode.Y).b);

    //Record clicked pixel as point
    Point node = new Point(m_StartNode.X, m_StartNode.Y);

    //if the pixel's colour is boundary colour (black), return.
    if(PC == Color.black)
    {
        return;
    }

    //else continue

    // Create a list Q[]
    m_List = new List<Point>();

    //add clicked pixel to Q[]
    m_List.Add(node);

    //for each element in Q[]
    for(int i=0; i<m_List.Count; i++)
    {
        //create new WE[] and add Q[n] to it
        m_WestEast = new List<Point>();
        m_WestEast.Add(node);

        //get pixel 1 to left (w) of Q[n]
        Point w = new Point(node.X + 1, node.Y);
        //get colour of w
        Color wCol = new Color(_tex.GetPixel(w.X, w.Y).r, _tex.GetPixel(w.X, w.Y).g, _tex.GetPixel(w.X, w.Y).b);    

        while(wCol != Color.black)
        {        
            //add pixel to WE[] and repeat
            m_WestEast.Add(w);

            //get new w
            w = new Point(w.X + 1, w.Y);

            //get colour of w
            wCol = new Color(_tex.GetPixel(w.X, w.Y).r, _tex.GetPixel(w.X, w.Y).g, _tex.GetPixel(w.X, w.Y).b);    

            //else if colour is boundary colour
                //go to next step
        }

        //get pixel 1 to right (e) of Q[n]
        Point e = new Point(node.X - 1, node.Y);
        //get colour of w
        Color eCol = new Color(_tex.GetPixel(e.X, e.Y).r, _tex.GetPixel(e.X, e.Y).g, _tex.GetPixel(e.X, e.Y).b);    

        while(eCol != Color.black)
        {        
            //add pixel to WE[] and repeat
            m_WestEast.Add(e);

            //get new e
            e = new Point(e.X - 1, e.Y);

            //get colour of e
            eCol = new Color(_tex.GetPixel(e.X, e.Y).r, _tex.GetPixel(e.X, e.Y).g, _tex.GetPixel(e.X, e.Y).b);    

            //else if colour is boundary colour
                //go to next step
        }

        //for each pixel in WE[]
        for(int j=0; j<m_WestEast.Count; j++)
        {
            //set the pixel to replacement colour
            _tex.SetPixel(m_WestEast[j].X, m_WestEast[j].Y, m_fillColour);

            //get pixel 1 to north (n) of Q[n]
            Point n = new Point(m_WestEast[j].X, m_WestEast[j].Y - 1);    

            //get colour of n
            Color nCol = new Color(_tex.GetPixel(n.X, n.Y).r, _tex.GetPixel(n.X, n.Y).g, _tex.GetPixel(n.X, n.Y).b);

            //if colour is not boundary colour
            if(nCol != Color.black)
            {
                //add pixel to Q[]
                m_List.Add(n);
            }

            //get pixel 1 to south (s) of Q[n]
            Point s = new Point(m_WestEast[j].X, m_WestEast[j].Y + 1);    

            //get colour of s
            Color sCol = new Color(_tex.GetPixel(s.X, s.Y).r, _tex.GetPixel(s.X, s.Y).g, _tex.GetPixel(s.X, s.Y).b);

            //if colour is not boundary colour
            if(sCol != Color.black)
            {
                //add pixel to Q[]
                m_List.Add(s);
            }
        }

    }

    // ----------

}

1 个答案:

答案 0 :(得分:1)

您的算法一遍又一遍地添加相同的像素。它还有其他各种各样的问题,但这就是让它永远运行并消耗掉你所有记忆的原因。我认为你在这里尝试实施第三种算法:http://en.wikipedia.org/wiki/Flood_fill

你明显的区别是维基百科算法有:

11.如果n的北边节点的颜色是目标颜色,则将该节点添加到Q.
12.如果n的南边节点的颜色是目标颜色,则将该节点添加到Q.

...但是,您正在测试边界颜色,而不是目标颜色。你的算法将反复检测相同的像素,每次都注意到它们与边界颜色不同。

您还有其他一些问题:

  1. 您尝试将列表用作队列,方法是在末尾添加。这意味着它会在整个时间内增长,并且会毫无理由地占用大量内存。维基百科中的算法假定您使用队列,并且循环每次都会使一个项目出列。这不应该阻止你的算法运行,但是你可能想要在它被大量使用之前修复它。
  2. 你有很多代码重复,这使你的算法不必要地难以阅读,并且当你稍后在一个地方进行更改而忘记在其他地方复制它时会招来麻烦。