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
-
I nadal chyba zbytnio nie mam pojęcia o grafice 2D i 3D w kontekście matematycznym i programistycznym ;) ↩︎
Komentarze (2)
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 :)
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…