Obecnie pracuję nad grą 2D, a moim bieżącym zadaniem jest obrysowanie wybranego obiektu.
Zasadniczo używam modułu cieniującego rozmycie, aby zrobić to w pełni. Najpierw rysuję duszka za pomocą pionowego gaussowskiego shadera rozmycia, następnie rysuję go poziomym gaussowskim shaderem rozmycia, a następnie rysuję duszka normalnie.
Oto mój shader shadera: sampler TextureSampler: register (s0);
#define SAMPLE_COUNT 15
float2 SampleOffsets[SAMPLE_COUNT];
float SampleWeights[SAMPLE_COUNT];
float4 PixelShaderFunction(float2 texCoord : TEXCOORD0) : COLOR0
{
float4 c = 0;
// Combine a number of weighted image filter taps.
for (int i = 0; i < SAMPLE_COUNT; i++)
{
c += tex2D(TextureSampler, texCoord + SampleOffsets[i]) * SampleWeights[i];
}
return c;
}
SampleOffets to przesunięcia pozwalające mi testować zaokrąglanie pikseli. SampleWeights to wagi obliczane za pomocą funkcji gaussa ( http://en.wikipedia.org/wiki/Gaussian_blur )
Oto wynik:
To nie jest takie złe, dość gładkie, ale niewystarczająco widoczne w grze ... Ale chciałbym móc kontrolować grubość (aby ją powiększyć) i dodać pierwszy nieprzezroczysty kontur przed zaniknięciem go w alfa (aby zrobić to bardziej widoczne). I czuję, że rozmycie gaussowskie może nie jest tak dobre, jak myślałem dla mojego zadania :)
Innym pomysłem jest wygenerowanie go automatycznie z .png (za pomocą skryptu photoshopa, aby był automatyczny). Muszę tylko wypełnić piksele konturu niestandardowym kolorem, przechowując na przykład wartość alfa w składniku Czerwonym i ustawić wszystkie pozostałe komponenty na 0. Następnie muszę zastosować moduł cieniujący, który zastępuje przezroczyste piksele wybranym kolorem
float4 PixelShaderFunction2(float2 texCoord : TEXCOORD0) : COLOR0
{
float4 color = tex2D(TextureSampler, texCoord);
float4 newColor = 0;
if (color.a == 0 && color.r != 0)
{
color.a = color.r;
// Blue outline
color.b = 1;
}
}
Problem w tym, że używam kompresji DXT5 dla mojego duszka, więc nie mogę być pewien, że kolor, który otrzymam w moim module cieniującym będzie dokładnie taki sam, jak napisałem. Dlatego nawet tego nie spróbowałem ... Jakieś myśli?
Wszelkie porady będą mile widziane :)
źródło
Odpowiedzi:
Prawdopodobnie szukasz formy wykrywania krawędzi przed, po, a nawet przed i po rozmyciu gaussowskim. Może wersja Sobel Edge Detection mogłaby działać. Wiem, że twoja gra jest 2D, ale jeśli strona wiki jest zbyt szorstka, oto samouczek, jak ją uruchomić w UDK, która może się lepiej tłumaczyć.
Twoje wykrywanie krawędzi naprawdę musi znaleźć krawędzie kanału alfa, jeśli potrzebujesz przyspieszenia.
źródło
To, co zadziałało dla mnie przy opisie tekstu, to:
Możesz zrobić to samo - wszystko, co musisz zrobić, to narysować duszka nieprzezroczystymi pikselami pokolorowanymi konturem. (Zachowaj wartości przezroczystości, aby okrągłe krawędzie nadal wyglądały na okrągłe).
Działa to, wygląda lepiej niż rysowanie wersji skalowanej i ma kilka innych fajnych właściwości (takich jak możliwość kontrolowania zarysu alfa pod kątem pogrubienia i zachowanie wszelkich „dziur” w obrazie duszka) - jedyną wadą jest to, że możesz „ Naprawdę zbyt dobrze kontrolujesz szerokość konturu.
źródło
Jestem trochę nowy w tym wszystkim, ale oto mój pomysł:
Możesz użyć kanału alfa tekstury, aby utworzyć inną teksturę. Każda wartość alfa poniżej wartości progowej zostanie ustawiona na w pełni przezroczystą. Wszelkie powyższe będą całkowicie nieprzejrzyste. Korzystając z tej nowej tekstury, możesz ustawić wartości RGB na dowolny kolor, jaki chcesz. Skaluj tę nową „teksturę”, aby była nieco większa niż tekstura postaci. To da ci ładny jednolity kolor wokół postaci. Następnie użyj tego koloru za pomocą shadera Gaussa, aby nadać przyjemny kontur wokół stworzonej tekstury. Domyślam się, że można to zrobić bez tworzenia kolejnej tekstury, i wszystko opierać się na cieniowaniu opartym na teksturze postaci.
Czy to w ogóle ma sens?
źródło