GDI+ - przezroczyste warstwy z cieniowanymi obiektami

0

Witam,

Zgadanienie jest nastepujace. Pisze program graficzny, ktory dziala na warstwach. Kazda warstwa to bitmapa (konkretnie HBITMAP). Bitmapy trzymane sa w wektorze.

Przezroczystosc warstw jest realizowana poprzez uzycie prezroczystego koloru tla bitmapy. Czyli: jedna warstwa to bitmapa z figurą i odpowiednim kolorem tła, który przyjąłem jako przezroczysty.

Takie podejście sprawdza się, dopóki obiekty na warstwach nie posiadają rozmytego cienia. Jeżeli cień jest rozmyty, to tło nie zostanie dokładnie "odfiltrowane" i cień będzie zamazany kolorem tła.

Innymi słowy, warstwa stanie się przezroczysta a cień nie - bo tam, gdzie był blur kolor jest już inny i cień zostanie zamazany.

Wygląda to tak (poprzednia warstwa to białe tło):
user image

Jezeli dam warstwe nieprzezroczysta (czyli biale tlo) i nie uzywam kolor przezroczystosci, jest OK:
user image

Tyle ze mnie to nie urzadza, bo to co jest na poprzednich warstwach tez powinno byc widoczne.

Nie mam pojecia jak z tego wybrnac :| Moze ktokolwiek by mial jakis pomysl? Jezeli trzeba, wkleje troche kodu ale mysle ze wiadomo o co chodzi.

0

Prawdę mówiąc, to ten cień powinien być "rozmywany" za pomocą maski alfa, a nie blur'a itp.

0

Faktycznie, zapodalem blura na caly obrazek i na to obiekt cieniowany.

Tyle ze w ten sposob nie osiagne przezroczystosci warstwy, bo albo zostaje mi tło jak wyżej albo rozmywam poprzednia warstwe razem z cieniem

Prawdę mówiąc, to ten cień powinien być "rozmywany" za pomocą maski alfa, a nie blur'a itp.

Hmm mozesz cos wiecej na ten temat powiedziec? W jaki sposob ma mi pomoc maska alpha? Na dobra sprawe caly czas uzywam maski alpha, bo w ten wlasnie sposob definiowany jest kolor przezroczystosci. (SetColorKey w GDI+). Jak mam tego uzyc do rozmywania cienia? :|

W tej chwili jedyne co mi przychodzi do glowy to nanoszenie cienia piksel po pikselu... przekopałem całą dokumentację GDI+ i nie znalazlem nic co mogloby mi pomóc...

P.S. skad wiesz ze uzywalem blura?

0

Bo w tej chwili jedyne co mi przychodzi do glowy to nanoszenie cienia piksel po pikselu...

W sumie podobnie wyglądałoby to w przypadku maski alfa, z tą różnicą, że przy kopiowaniu takiego cienia-bitmapy uwzględniane byłyby regiony. Jeżeli problemu regionów nie ma - rysuj od razu kolorem.

Na dobra sprawe caly czas uzywam maski alpha, bo w ten wlasnie sposob definiowany jest kolor przezroczystosci. (SetColorKey w GDI+).

Nie, maska alfa to jest tablica z wartościami alfa dla każdego piksela. Poszukaj w dokumentacji GDI+ czy jest możliwość stworzenia takiej maski.

P.S. skad wiesz ze uzywalem blura?

No przecież napisałeś :>

0

W sumie podobnie wyglądałoby to w przypadku maski alfa, z tą różnicą, że przy kopiowaniu takiego cienia-bitmapy uwzględniane byłyby regiony. Jeżeli problemu regionów nie ma - rysuj od razu kolorem.

Hmm teraz to juz wydaje mi sie jeszcze bardziej zagmatwane... :| Mozesz napisac mi krok po kroku jak nanieść rozmyty cień na obrazek, nie ruszając tła? Region cienia oczywiscie mam (trzymany w klasie Region z GDI+ - jezeli wypelnie ten region kolorem to otrzymam cień nie rozmyty)

Ręczne nanoszenie piksel po pikselu wydaje mi się dość karkołomnym zadaniem :| MSDN milczy w sprawie maski alpha, jedyne co znalazlem to: http://www.codeproject.com/useritems/alphamaskgen.asp

Ale ciagle nie wiem, jak tego uzyc do rozmywania cienia, a nie tylko do ustawienia koloru przezroczystosci bitmapy.

0

Mozesz napisac mi krok po kroku jak nanieść rozmyty cień na obrazek, nie ruszając tła?

Najprostsza metoda to najpierw narysować prostokąt/wielokąt z odpowiednim "gradientem" alfa na dolnym i prawym boku. Dopiero później, na narysowanym już cieniu, rysujesz właściwą figurę. Oczywiście to wszystko odbywa się przy renderingu wszystkich warstw.

Ręczne nanoszenie piksel po pikselu wydaje mi się dość karkołomnym zadaniem

Piszesz w końcu program graficzny, więc dłubanie w pikselach to oczywistość...

MSDN milczy w sprawie maski alpha

Przejrzałem dokumentację i faktycznie nie ma takiej opcji - dziwne :/ Chociaż można pokombinować z bitmapami RGBA lub z LinearGradientBrush i PathGradientBrush.

PS. ten program to do grafiki wektorowej czy rastrowej???

0

Najprostsza metoda to najpierw narysować prostokąt/wielokąt z odpowiednim "gradientem" alfa na dolnym i prawym boku. Dopiero później, na narysowanym już cieniu, rysujesz właściwą figurę.

No tak, tylko jak narysowac rozmyty cień używając poleceń grafiki wektorowej ?

Bo jest tak: mam wielokąt - po jego wypełnieniu powstaje cień. Mogę wypełniać kolorem jednolitym, teksturą lub gradientem.

Ale to mi nic nie daje, bo żeby uzyskać rozmycie, muszę przekonwertować to na bitmapę i "potraktować" blurem. A jeżeli tak zrobię, to utracę całe tło, czyli np. obrazek, który był na poprzedniej warstwie.

Jednym słowem, mając cień jako bitmapę nie widzę sposobu, jak mogę narysować najpierw poprzednią warstę a potem cień, który jest również bitmapą - ale w ten sposób, że dodany zostanie tylko cień, a kolor tła będzie odfiltrowany (bo bitmapa oczywiśie ma kształt prostokąta).

Piszesz w końcu program graficzny, więc dłubanie w pikselach to oczywistość...

No tak, ale jak wymyślić algorytm generujący cień, o odpowiednim rozmyciu, kolorze itd. Poza tym cień ma być jeszcze bardziej skomplikowany, np. powinien istnieć pewien obszar nigdy nie rozmywany (ustawiany przez użytkownika), odpowiedni stopień rozmycia itd.

Czyli np. cos takiego:

user image

można pokombinować z bitmapami RGBA lub LinearGradientBrush i PathGradientBrush.

Hm próbowałem. Ale wypełnienie regiony gradientem nic nie pomoże - po pierwsze nie uzyskam rozmycia, po drugie region jest niereguralrny, a rozmycie powinno postępować równolegle do boków obiektu.

Próbowałem kombinować z gradienten o kolorach od Color(255,0,0,0) do (0,0,0,0) ale to nadaje się co najwyżej do zrobienia efektu cienia na prostokątnym wycinku ściany (np cień od lewej do prawej).

PS. ten program to do grafiki wektorowej czy rastrowej???

Ogólnie rzecz biorąc, grafika rastrowa. Działa mniej więcej tak, że mamy zdjęcie. Na zdjęciu zaznaczamy obszar i wypełniamy go teksturą, a obszar możemy wycieniować (cień zewnętrzny i wewnętrzny). Oprócz tego ustawienia tekstury (gęstość, kąt itd). Każdy nowo dodany obszar to automatycznie nowa warstwa. Oprócz tego przezroczystość warstw, kontrast jasność itd.

Wszystko bardzo proste w sumie - gdyby nie ten cień, to nie byłoby problemu, bo wszystko załatwia za mnie GDI+.

0

A próbowałeś zrobić tak:

  • stwórz bitmapę PixelFormat32bppARGB
  • wypełnij ją kolorem z alfa=0
  • narysuj cień z alfa=255
  • blur
  • skopiuj do właściwego Graphics (tego z tłem)

kto wie, może zadziała...

0

Działa - moglem sam na to wpasc [wstyd]

Gdyby kogos interesowalo, przykladowy kod jest taki:

HDC hdc = Image1->Canvas->Handle;
int width = Image1->Width;
int height = Image1->Height;

Gdiplus::Graphics graphics(hdc);

Bitmap tlo(L"test.gif");
graphics.DrawImage(&tlo,0,0); //Rysowanie tła

Bitmap *tmp = new Bitmap(width, height, PixelFormat32bppARGB);
Gdiplus::Graphics *graphics_cien = new Gdiplus::Graphics(tmp);
graphics_cien->Clear(Gdiplus::Color(0,128,128,128));

SolidBrush b(Gdiplus::Color(240,255,100,0));        //Brush obiektu
SolidBrush *bCien = new SolidBrush(Gdiplus::Color(160,0,0,0));       //Brush cienia

/*


*/

GraphicsPath *g = new GraphicsPath();
GraphicsPath *g_cien = new GraphicsPath();

g_cien->AddPolygon(points2,5);
g->AddPolygon(points,5);
Region *r = new Region(g);
Region *r_cien = new Region(g_cien);
r_cien->Exclude(g);

//Rysowanie obiektu - bezpośrednio
graphics.FillPolygon(&b,points,5);

//Rysowanie cienia na tymczasowej bitmapie
graphics_cien->FillRegion(bCien,r_cien);

//Rozmywanie cienia -  blur
BlurParams *myBlurParams = new BlurParams();
myBlurParams->expandEdge = FALSE;
myBlurParams->radius = 4;
Blur *myBlur = new Blur();
myBlur->SetParameters(myBlurParams);
tagRECT rc = {0,0,tmp->GetWidth(), tmp->GetHeight()};
tmp->ApplyEffect(myBlur,&rc);

//Rysowanie tymczasowej bitmapy z cieniem
graphics.DrawImage(tmp,0,0);

Image1->Repaint();

//Czyszczenie
delete tmp;
delete graphics_cien;
delete bCien;
delete g;
delete g_cien;
delete r;
delete r_cien;
delete myBlurParams;
delete myBlur;

Przykładowy wynik działania powyższego kodu:

user image

Dzieki za naprowadzenie [browar]

0

Dziwne, najpierw rysujesz obiekt a później cień, a powinno być chyba odwrotnie. Dodatkowo jest tam dziwna "łuna" na krawędziach obiektu i nie ma cienia pod obiektem (wszak jest półprzeźroczysty).

0

Dziwne, najpierw rysujesz obiekt a później cień, a powinno być chyba odwrotnie.

W tym wypadku to nieistotne, bo cien i tak nie przykryje obiektu.

nie ma cienia pod obiektem (wszak jest półprzeźroczysty).

No nie ma, bo nie mialo byc, wlasnie dlatego ze jest polprzezroczysty. Cały myk polega na tym:

r_cien->Exclude(g);

Czyli rysuje tylko samo odbicie. Dlaczego? Ano wlasnie dlatego, ze obiekt ma byc polprzezroczysty i nie ma pod nim dalszej części cienia - w każdym razie to celowe działanie.

Dodatkowo jest tam dziwna "łuna" na krawędziach obiektu

No wlasnie jest, a wynika to z tego, ze cien nie jest rysowany ani rozmywany cały. Łuna powstaje z rozmycia wewnętrznych krawędzi... Masz jakis pomysl jak to zlikwidowac? :|

[edit]
głupie pytanie - przeciez wystarczy narysowac cień a potem obiekt i łuny nie ma - obiekt przykryje rozmytą krawędź.

1 użytkowników online, w tym zalogowanych: 0, gości: 1