Odświeżam wątek, albowiem rozwiązałem swój problem :]
Skupiłem się jednak na stworzeniu maski, dlatego że "koloryzowanie" powierzchni za jej pomocą będzie o wiele prostsze, a poza tym, bardzo łatwo będzie malować jedynie zadane fragmenty - wystarczy w tle namalować jednokolorowy wielokąt i całość przykryć maską. No i efektywność tego rozwiązania będzie wysoka, co też jest dla mnie ważne.
Niestety Gimpa nie udało mi się zmusić do posłuszeństwa, więc naklepałem trochę kodu. Przygotowałem sobie takie małe, testowe narzędzie, za którego pomocą możliwe jest przekonwertowanie zwykłej, kolorowej i nieprzezroczystej tekstury, na przezroczystą, dwukolorową maskę. Wystarczy załadować bitmapkę, a program wypluje półprzezroczystą maskę w postaci 32-bitowego PNG. Do dyspozycji jest też trochę ustawień, aby móc idealnie dostroić konwerter. Głównie zależało mi na przygotowaniu kafli o wymiarach 148x148
, więc takie ten testowy program obsługuje.
Program wygląda w ten sposób:
Strzałki określają drogę, jaką konwerter pokonuje. Określa się obraz źródłowy (z lewej), który przerabiany jest na skalę szarości (u dołu), ta tekstura łączona jest z kolorem tła (z prawej), czego wynikiem jest półprzezroczysta maska nad kolorem tła (u góry). Ostatnim krokiem jest zapis maski do pliku.
Program składa się z czterech obrazków, jako czterech kroków konwersji:
-
Source image - wejściowa, kolorowa tekstura. Obsługiwane są jedynie 24-bitowe bitmapy o wymiarach
148x148
(większe zostaną przycięte, a dla mniejszych, pusta przestrzeń zostanie wypełniona białym kolorem). Kliknięcie w ten obraz powoduje pobranie koloru piksela i ustawienie go jako Background color.
-
Texture image - wejściowa tekstura, przekonwertowana na skalę szarości. Z racji tej, że wyjściowa maska jest dwukolorowa (czarne piksele przyciemniają kolor, białe rozjaśniają - stopień przyciemnienia/rozjaśnienia na podstawie kanału alpha), wygodniej jest bazować na teksturze w odcieniach szarości (każdy piksel opisują składowe RGB o takiej samej wartości). Kliknięcie w ten obraz powoduje pobranie odcienia szarości i ustawienie go jako Transparent value.
-
Background color - kolor tła dla podglądu maski.
-
Mask preview - podgląd wygenerowanej maski nad wybranym kolorem tła.
Dostępnych jest też kilka opcji:
-
Brightness - stopień jasności tekstury (tej w skali szarości). Wartości ujemne oznaczają przyciemnienie tekstury, a dodatnie jej rozjaśnienie. Zakres jest duży, nieprocentowy, więc można precyzyjnie wybrać jasność. 0
oznacza, że podczas konwersji na odpowiednik w skali szarości, jasność nie zostanie zmieniona.
-
Transparent Value - odcień szarości, który określa piksele całkowicie przezroczyste. Wszystkie piksele o wartościach składowych mniejszych niż Transparent Value zostaną w masce przyciemnione, a o wyższych rozjaśnione (na podstawie odpowiednio obliczonego stopnia przezroczystości).
-
Transparency multiplier - mnożnik stopnia przezroczystości. Wyliczony stopień przezroczystości mnożony jest przez tą wartość, co umożliwia wyostrzenie faktury powierzchni. Im wyższy mnożnik, tym mocniejsze wyostrzenie.
-
Load from file... - otwiera okno dialogowe do wyboru obrazu źródłowego z dysku.
-
Change color... - otwiera okno dialogowe do wyboru koloru tła dla podglądu maski.
-
Save mask to file... - otwiera okno dialogowe do zapisu obrazu maski na dysku.
Jeśli chodzi o możliwości tego narzędzia to tyle - teraz może trochę o kodzie. Za konwersję kolorowego obrazu na teksturkę w skali szarości odpowiada metoda CreateTexture
. Jest ona tylko wrapperem i wywołuje jedną z trzech właściwych metod:
-
CreateDarkerTextureFromImage
- jeśli tekstura w skali szarości ma zostać przyciemniona,
-
CreateOriginalTextureFromImage
- jeśli jasność tekstury w skali szarości nie będzie zmieniana,
-
CreateBrighterTextureFromImage
- jeśli tekstura w skali szarości ma zostać rozjaśniona.
Te metody odróżnia jedynie konwersja kolorowego piksela na odpowiedni odcień w skali szarości - reszta jest chamsko skopiowana. Natomiast za konwersję tekstury w skali szarości na półprzezroczystą maskę odpowiada metoda CreateMask
. Jej kod poniżej:
procedure TMainForm.CreateMask();
var
LTextureLine: PRGBTripleArr;
LMaskLine: PRGBQuadArr;
LLineIdx, LPixelIdx: Integer;
LGrayShade, LTransparentValue: UInt8;
LAlpha: Integer;
LMultiplier: Double;
begin
LTransparentValue := CTransparentValueSpin.Value;
LMultiplier := CTransparencyMultiplierSpin.Value;
FTextureImage.BeginUpdate();
FMask.BeginUpdate();
try
for LLineIdx := 0 to FTextureImage.Height - 1 do
begin
LTextureLine := FTextureImage.ScanLine[LLineIdx];
LMaskLine := FMask.ScanLine[LLineIdx];
for LPixelIdx := 0 to FTextureImage.Width - 1 do
begin
LGrayShade := LTextureLine^[LPixelIdx].R;
with LMaskLine^[LPixelIdx] do
begin
FillChar(B, 3, UInt8(LGrayShade > LTransparentValue) * 255);
LAlpha := Round(Abs(LGrayShade - LTransparentValue) * LMultiplier);
A := Min(Max(LAlpha, 0), 255);
end;
end;
end;
finally
FTextureImage.EndUpdate();
FMask.EndUpdate();
end;
end;
Dla każdego piksela z wejściowego obrazu (czyli FTextureImage
) pobierana jest wartość składowej R
(wszystkie składowe mają taką samą wartość, więc nie ma to znaczenia). Jeśli wartość składowej jest wyższa niż Transparent value to piksel zostaje pomalowany na biało, w przeciwnym razie na czarno. Ostatnim krokiem jest określenie stopnia przezroczystości. Najpierw obliczana jest bezwzględna różnica pomiędzy wartością składowej a Transparent value, wynik mnożony jest o wartość mnożnika. Na koniec tak otrzymana wartość zostaje "upchnięta" w jednym bajcie (jeśli wynik jest mniejszy niż 0
to otrzymuje wartość 0
, jeśli jest większy niż 255
to otrzymuje wartość 255
, a jeśli mieści się w zakresie to pozostaje bez zmian).
To w sumie tyle, jeśli chodzi o funkcjonalność tego narzędzia. Wybrany sposób nie jest idealny, jednak pozwoli mi na wygodne stworzenie dobrych masek - muszę tylko dokładniej pobawić się parametrami i potestować na dużej liczbie kolorów. W załączniku ttmconv.zip podaję pełne źródła narzędzia, gdyby ktoś chciał skorzystać. W środku archiwum jest plik wykonywalny, więc aby się pobawić apką, nie trzeba nic kompilować.
Jeśli ktoś chciałby skorzystać z jakiegoś kawałka kodu to w tym programie znajdzie:
- typy danych umożliwiające odczyt/modyfikację pikseli 24- i 32-bitowych,
- funkcję konwersji koloru na odpowiednik w skali szarości,
- funkcję przyciemniającą i rozjaśniającą kolor,
- funkcję generującą półprzezroczystą maskę na podstawie tekstury w skali szarości,
- inne duperele.