Panel użytkownika
Nazwa użytkownika:
Hasło:
Nie masz jeszcze konta?

Generowanie gradientów

Ostatnio zmodyfikowano 2013-03-10 00:39
Autor Wiadomość
Chlorek
Temat założony przez niniejszego użytkownika
Generowanie gradientów
» 2013-03-09 01:08:56
No i jakiś czas temu zapowiadany przeze mnie problem (przeszkoda) pojawia się na tym forum. Dotarłem do miejsca w moim programie, gdzie bez generowania gradientów na bitmapie ani rusz. Tak więc przeglądałem internet w poszukiwaniu jakiegoś algorytmu na generowanie gradientów radialnych. Wychodzi na to, że zbyt obszernie tego nigdzie nie opisano, a jeśli już opisano to tu akurat trochę moje zdolności nie wystarczyły, by na podstawie jakiegoś artykułu z przeważającą ilością teorii napisać taką funkcję (a nigdzie nie mogę znaleźć przykładowego kodu, max 2 linijki kodu na obliczenie czegoś to jedyne co mogę znaleźć).
Ogólnie potrzebuję tylko, lub aż sposób na generowanie gradientu radialnego (chodzi o taki okrągły, nie liniowy), który będzie przechodził między kolorami biały i czarny, czyli generalnie szarość. Do tego bardzo potrzebna jest możliwość ustawienia promienia gradientu od jego środka do najdalej położonych pikseli.
Nie myślałem początkowo, że będzie to aż tak złożone, bynajmniej nie dla mnie, bo różne łamigłówki już rozwiązywałem. Tu jednak potrzebuję sporo pomocy, bo się całkiem w tym gubię.
Dodam jeszcze, że wydajny algorytm jest mile widziany w moim programie, gdyż program będzie momentami tworzył dziesiątki (może nawet setki) gradientów jeden po drugim (co prawda w wątku, ale opóźnienie i tak wystąpi, gdyż będzie trzeba czekać na ukończenie operacji).
P-77954
Mrovqa
» 2013-03-09 15:23:25
Liczysz odległość piksela od środka okręgu i w zależności od niej określasz liniowo kolor. Tzn. ja tak bym to zrobił :)
P-77973
Chlorek
Temat założony przez niniejszego użytkownika
» 2013-03-09 17:28:47
Matołem nie jestem i tyle na razie sam wiem, na razie udało mi się wyczarować rysowanie okręgów i spróbuję teraz jakoś to przerobić na gradient... co i tak jest dla mnie wielkim wyzwaniem.

#Edit
Sprawa jest o tyle trudniejsza, że wiele gradientów radialnych będzie się znajdowało obok siebie (ich środki mogą leżeć nawet jeden obok drugiego), ale przejście musi być gładkie tak by jeden gradient łączył się płynnie z drugim, to jeszcze bardziej mnie przerasta, mam pomysły ale zupełnie nie potrafię tego napisać.

#Edit 2
Chyba udało mi się zrobić coś co przypomina gradient, spróbuję to poprawić na ile potrafię, jak efekt nie będzie dalej zadowalający to się do was zwrócę o pomoc. Wcześniej rysowałem okręgi prostą metodą, która przy użyciu do generowania kół dawała dziury w środku (białe piksele), teraz używam jednej bazowanej na trygonometrii i jakoś działa.
P-77988
Chlorek
Temat założony przez niniejszego użytkownika
» 2013-03-10 00:14:49
Mam już niemal wszystko czego potrzebuje. Pozostała kwestia płynnych przejść między gradientami (nie wiem jak to dokładnie nazwać). W każdym razie wpadłem na pomysł, aby "dodawać" do siebie kolory. Aby przybliżyć o co mi chodzi powiem tak:
Mój program tworzy height-mapę, generując na niej według podanego kodu gradienty i inne elementy używając szarości, im ciemniejszy kolor tym wyższy oznacza punkt. Tak więc czysta czerń to najwyższy, a biel najniższy punkt. Jednak do dobrego wyglądu brakuje płynnego łączenia się gradientów nachodzących na siebie, w tym celu przetwarzam stary kolor na wysokość, następnie przetwarzam kolor na jaki chcę pomalować piksel również na wysokość i na koniec dodaję te wartości (+ sprawdzenie czy nie wychodzi ponad 255). Wysokość zamieniam znowu na kolor i maluję piksel. Tylko teraz wyszedł na jaw ukryty problem, mianowicie gradient rysuję zwiększając promień i rysując kolejne okręgi, aby uniknąć "dziur" robię to dość gęsto, efekt jest taki, że podczas zwykłego generowania gradientu wszystko wygląda świetnie, natomiast gdy "dodaję kolory" to okazuje się, że te same piksele należą do wielu różnych okręgów rysowanych podczas generowania gradientu, efekt jest taki, że kolory dodają się tyle razy, że widzę tylko czarne koło z lekkim gradientem na obwodzie. Jak teraz zrobić, by okręgi nie "nadmalowywały się"? I tak generowanie jednej takiej bitmapy z gradientami i wykonanie na niej jeszcze wszystkich innych obliczeń (których będzie na koniec kilkakrotnie więcej niż jest) pożera dużo czasu, nawet na moim komputerze który jest raczej szybki. Z tego powodu zapamiętywanie jakie piksele były malowane podczas generowania jednego gradientu odpada (a gradienty bywają bardzo duże, co oznacza wiele pikseli).
Każdy pomysł przyjmę jeśli tylko będzie z miarę wydajny i działał. Jak będzie potrzeba mogę wstawić kod.
P-78033
Gabes
» 2013-03-10 00:28:27
taki stary program z Allegro4, rysowanie za pomocą circlefill.

kolory
P-78034
Chlorek
Temat założony przez niniejszego użytkownika
» 2013-03-10 00:39:57
Nie zrozumiałeś mnie najwidoczniej, ja napisałem własny algorytm (oczywiście pomagając sobie różnymi stronami z sieci), który wylicza pozycję pikseli w okręgach, a one z kolei zapisywane są przez bibliotekę EasyBMP do pliku jako bitmapa. Funkcja rysująca okrąg z allegro nic mi tu nie pomoże:

#Edit
Udało mi się! Efekt który chciałem osiągnąć mam, niby nienajwydajniej, ale wychodzi i tak dość szybko, użyłem tablicy tablicy bool. Kod podam w całości, bo kiedyś może się komuś przydać, a głowienia się przy tym nie mało:
C/C++
#include <EasyBMP.h>

bool paintedPixels[ 512 ][ 512 ] = { };

bool isPainted( int x, int y )
{
    return paintedPixels[ y ][ x ];
}

void setPainted( int x, int y, bool painted )
{
    paintedPixels[ y ][ x ] = painted;
}

void resetPaintedStatus()
{
    for( int i = 0; i <= 511; i++ )
    {
        for( int j = 0; j <= 511; j++ )
        {
            paintedPixels[ i ][ j ] = false;
        }
    }
}

int wrapHeightColor( RGBApixel color )
{
    int c = color.Red;
    int h = 0;
   
    h = 255 - c;
   
    return h;
}

RGBApixel wrapHeightColor( int height )
{
    char c = 255 - height;
   
    RGBApixel pixel { c, c, c, 0 };
   
    return pixel;
}

bool paintPixel( BMP & file, int x, int y, RGBApixel color, bool addColors )
{
    if( isPainted( x, y ) ) return false;
   
    bool over = false;
   
    if( x < 0 || x >= file.TellWidth() ) return false;
   
    if( y < 0 || y >= file.TellHeight() ) return false;
   
    if( addColors )
    {
        int oldHeight = wrapHeightColor( file.GetPixel( x, y ) );
        int heightToAdd = wrapHeightColor( color );
       
        int newHeight = heightToAdd + oldHeight;
        if( newHeight > 255 )
        {
            newHeight = 255;
            over = true;
        }
       
        file.SetPixel( x, y, wrapHeightColor( newHeight ) );
    }
    else
    {
        file.SetPixel( x, y, color );
    }
   
    setPainted( x, y, true );
   
    return over;
}

void fillChunk( BMP & file )
{
    RGBApixel pixel = wrapHeightColor( 20 );
   
    for( int i = 0; i < 512; i++ )
    {
        for( int n = 0; n < 512; n++ )
        {
            file.SetPixel( i, n, pixel );
        }
    }
}

void drawCircle( BMP & file, int rx, int ry, int r, RGBApixel color, double pi )
{
    int x, y;
    double d;
    //const double pi = 3.14159265;
   
    for( d = 0; d <= 2 * pi; d += 0.001 )
    {
        x = rx + sin( d ) * r;
        y = ry + sin( d +( pi / 2 ) ) * r;
       
        paintPixel( file, x, y, color, true );
    }
}

void generateGradient( BMP & file, RGBApixel from, RGBApixel to, int x, int y, int r, double pi )
{
    resetPaintedStatus();
   
    double dr = r;
   
    for( double radius = 0; radius <= r; radius++ )
    {
        if( radius > 0 )
        {
            int fromHeight = wrapHeightColor( from );
            fromHeight = fromHeight *( 1 -( radius / dr ) );
           
            RGBApixel color = wrapHeightColor( fromHeight );
            drawCircle( file, x, y, radius, color, pi );
        }
        else
        {
            paintPixel( file, x, y, from, true );
        }
    }
}

Trochę długie więc wrzuciłem na pastebin. Odnośnie podawania liczby PI przy generowaniu gradientu, ja mam zmienną tą wartość (nie zawsze generuję idealne koła, gdyż nawet taki efekt nie jest pożądany przeze mnie). Ale w razie gdyby ktoś nie widział to w funkcji drawCircle() jest w komentarzu poprawna wartośc liczby PI.

A i wartość (kolor/argument 'RGBApixel to') jest nieużywany więc można wywalić, zapomniałem to zrobić wcześniej.
P-78035
« 1 »
  Strona 1 z 1