Alpha blending

tech • 426 słów • 2 minuty czytania

Potrzebowałem jak najprostszym sposobem uzyskać efekt alpha blending (przezroczystość). Z racji, że nie miałem o tym większego pojęcia1 to próbowałem zaczerpnąć informacji w niezliczonych zasobach sieciowych ;)

Szukałem jakiegoś prostego sposobu wyznaczania średniej wartości składowej koloru danego piksela. W różnych źródłach znalazłem kilka różnych działań obliczających tę wartość, od bardzo prostych i wydajnych, to złożonych i ociężałych. Poniżej kilka znalezionych przykładów ;)

Na początek mała legenda używanej w dalszej części symboliki. Litera r to wynikowa średnia wartość danej składowej koloru, s jest składową źródłową, a d docelową. Zmienna blend określa stopień przenikalności z przedziału 0..255.

Pierwszy znaleziony wynik to chyba najbardziej rozbudowane działanie:

$$ r = (blend * ((s + 64) - d)) / 256 + d - (blend / 4) $$

Jak widać czyste samobójstwo i zarzynanie procesora, tyle operacji i w tym dwa dzielenia.

Następnie było kilka innych ciekawych wyników, ale nie różniły się one jakoś specjalnie od tych znalezionych przypadkiem w kodach źródłowych biblioteki graficznej Mesa 3D.

Szybkie, mniej dokładne, zoptymalizowane pod kątem użycia przesunięć bitowych (>> 8) zamiast dzielnie przez 256:

$$ r = (s * blend + d * inv + 1) / 256 $$

A tu oryginalna, powolniejsza, ale dokładniejsza wersja:

$$ r = (s * blend + d * inv) / 255 $$

Używana wyżej zmienna inv to “odwrócony” blend, czyli

$$ inv = 255 - blend $$

Idąc dalej, typowe działanie szeroko stosowane:

$$ r = ((s - d) * blend) / 255 + d $$

Jak wiadomo dzielenie jest dosyć kosztowną operacją w porównaniu do pozostałych prostych działań matematycznych, dlatego niektórzy zamiast dzielenia wykorzystują przesunięcia bitowe, które są o wiele szybsze w tym zastosowaniu.

x / 255 == ((x << 8) + x + 256) >> 16

No i wreszcie dochodzimy do najbardziej optymalnej metody:

$$ r = (s - d) * (blend/255) + d $$

Wartość blend/255 jest stała dla danej wartości przeźroczystości, przez co można ją zbuforować i w pętli obliczającej kolory wszystkich pikseli obrazka wykonywać tylko bardzo proste i szybkie działanie - interpolację liniową:

$$ (s - d) * x + d $$

Warto wspomnieć, że obecnie w kartach graficznych interpolacja liniowa wykonywana jest w jednym cyklu/rozkazie GPU.

O ten temat zahaczyłem głównie z powodu braku w wxImage jakiejś prostej funkcji umożliwiającej uzyskanie blendingu danego obrazka z innym, bądź jakimś kolorem, co bardzo by mi się przydało. Może jakiegoś patcha napiszę, bo aktualnie można jedynie pokombinować z alpha i nakładaniem dwóch obrazków na kontekście urządzenia ;)


Przypisy

  1. I nadal chyba zbytnio nie mam pojęcia o grafice 2D i 3D w kontekście matematycznym i programistycznym ;) ↩︎

Komentarze (2)

mi-ku avatar
mi-ku
20080626-191231-mi-ku

Hej, co do liczenia na procesorze to możesz również się skusić na użycie jednostek SSE. W bibliotekach Microsoftu są intrinsic’i do tego: MMX, SSE, and SSE2 Intrinsics - może się przyda.

Ogólnie to masz ciekawy blog :)

Malcom avatar
Malcom
20080626-200126-malcom

Ciekawe, choć w asmie się mało bawię :(

A blog jak devblog, w sumie też nic ciekawego się ostatnio nie dzieje, bo nie mam czasu i tematów…

Dodaj komentarz

/dozwolony markdown/

/nie zostanie opublikowany/