forum.boolean.name

forum.boolean.name (http://forum.boolean.name/index.php)
-   Алгоритмика (http://forum.boolean.name/forumdisplay.php?f=21)
-   -   Заливка контура (2д) (http://forum.boolean.name/showthread.php?t=18195)

is.SarCasm 20.05.2013 16:54

Заливка контура (2д)
 
Делаю игру-рисовалку. Нужно реализовать нормальную заливку фигур.
Я использую что-то типа рекурсии и зарисовываю части не точками, а линиями.

В коде ниже я использую Unity3d, но там в принципе всё должно быть интуитивно понятно:

Код:

void Fill(IntVector2 pos, Texture2D canvas, Color newColor)
{
// For speed control
float time = Time.realtimeSinceStartup;
int  points=0;
// DEBUGGG


IntVector2 point;
Stack pixelStack = new Stack(); // point from where start filling
bool spanTop = false; // Does line above need to be filled?
bool spanBot = false; // below
Color oldColor = canvas.GetPixel(pos.x,pos.y); // Set color that will be replaced


pixelStack.Push(pos); // Start
while(pixelStack.Count>0) // Рекурсия
{
        point =  pixelStack.Pop() as IntVector2; // Get new point
        spanBot = false; spanTop = false;
        while(point.x>=0 && canvas.GetPixel(point.x,point.y)==oldColor) // FInd most left pixel
        {
                point.x--;
        }
        point.x++;
       
        // Start fill line from left to right
        while(point.x<canvas.width && canvas.GetPixel(point.x,point.y)==oldColor) // until we meet another pixel
        {
                canvas.SetPixel(point.x,point.y,newColor);
               
                // Is there line above needs filling?
                if(spanTop==false && point.y>0 && canvas.GetPixel(point.x,point.y-1)==oldColor)
                {
                        IntVector2 newpoint = new IntVector2(point.x,point.y-1);
                        pixelStack.Push(newpoint); // add new point from where we will start fill line
                        spanTop = true;
                        points++; // for debug
                } else if(spanTop==true && point.y>0 && canvas.GetPixel(point.x,point.y-1)!=oldColor) {
                        spanTop = false;
                }
               
                // Below?
                if(spanBot==false && point.y<canvas.height && canvas.GetPixel(point.x,point.y+1)==oldColor)
                {
                        IntVector2 newpoint = new IntVector2(point.x,point.y+1);
                        pixelStack.Push(newpoint);
                        spanBot = true;
                        points++; // for debug
                } else if(spanBot==true && point.y<canvas.height && canvas.GetPixel(point.x,point.y+1)!=oldColor) {
                        spanBot = false;
                }
                point.x++; // next pixet left->right
        }
       
}
time = time - Time.realtimeSinceStartup; // for debug
canvas.Apply(); // Change material (takes rly little time)


print("CalculateTime:"+(-time)+", points detected:"+points);
}

Разрешение полотна: 900х675
Первый тест:
Простое белое полотно

CalculateTime:0.7691972, points detected:674

Второй тест:
Очень сложная фигура, небольшая по площади

CalculateTime:0.3095117, points detected: 19011

(линии оказались быстрее чем точки, может прямоугольники быстрее линий? ;D)

den 20.05.2013 17:58

Ответ: Заливка контура (2д)
 
Цитата:

Первый тест:
Простое белое полотно

:-D

is.SarCasm 20.05.2013 18:20

Ответ: Заливка контура (2д)
 
Texture2D.SetPixels
Using SetPixels can be faster than calling SetPixel repeatedly, especially for large textures. In addition, SetPixels can access individual mipmap levels.

Пытался использовать, но для неё нужен массив WxH, который создается очень долго и результат с 0.7 увеличивается до 0.85... Печаль.

is.SarCasm 20.05.2013 18:51

Ответ: Заливка контура (2д)
 
Хм, не могу придумать как уменьшить кол-во вызовов SetPixel\GetPixel, если это вообще возможно тут.
Думаю сделать второй способ, в котором вместо SetPixel\GetPixel я буду работать с массивом цветов, который скопирую в начале, а потом зарисую это SetPixels'ом, может и будет профит.
На какую скорость вообще стоит расчитывать? У меня даже в Paint.NET'е заливка некоторое время занимает (быстрее конечно чем у меня тут)

pax 21.05.2013 11:31

Ответ: Заливка контура (2д)
 
Читай пиксели в массив перед работой, обновляй массив, потом записывай весь буфер сразу в текстуру.
http://docs.unity3d.com/Documentatio...tPixels32.html
http://docs.unity3d.com/Documentatio...tPixels32.html

impersonalis 21.05.2013 13:15

Ответ: Заливка контура (2д)
 
В чём вопрос темы с позиции алгоритма? В рекурсии при заливке? Тогда:
вот тут рекурсия заменена на работу со списком.


Часовой пояс GMT +4, время: 15:21.

vBulletin® Version 3.6.5.
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Перевод: zCarot