Co powiesz na coś takiego?
Nie rysuj swojego oświetlenia, przyciemniając duszki kafelkowe. Narysuj nieoświetlone kafelki na celu renderowania, a następnie narysuj światła kafelków na drugim celu renderowania, reprezentując każdy z nich jako prostokąt w skali szarości pokrywający obszar kafelka. Aby wyrenderować ostatnią scenę, użyj modułu cieniującego do połączenia dwóch celów renderowania, przyciemniając każdy piksel pierwszego zgodnie z wartością drugiego.
To da dokładnie to, co masz teraz. To ci nie pomaga, więc zmieńmy to trochę.
Zmień wymiary celu renderowania lightmapy, tak aby każdy kafelek był reprezentowany przez pojedynczy piksel , a nie prostokątny obszar. Podczas komponowania końcowej sceny użyj stanu próbnika z filtrowaniem liniowym. W przeciwnym razie pozostaw wszystko inne bez zmian.
Zakładając, że poprawnie napisałeś moduł cieniujący, lightmap powinien być skutecznie „powiększany” podczas komponowania. Dzięki temu uzyskasz ładny efekt gradientu za darmo za pomocą próbnika tekstur urządzenia graficznego.
Być może będziesz w stanie wyciąć moduł cieniujący i zrobić to prościej z „zaciemniającym” stanem BlendState, ale musiałbym z nim poeksperymentować, zanim przedstawię ci szczegóły.
AKTUALIZACJA
Miałem dzisiaj trochę czasu, żeby sobie z tego wyśmiewać. Powyższa odpowiedź odzwierciedla mój nawyk używania shaderów jako mojej pierwszej odpowiedzi na wszystko, ale w tym przypadku nie są one faktycznie konieczne, a ich użycie niepotrzebnie komplikuje rzeczy.
Jak zasugerowałem, możesz osiągnąć dokładnie ten sam efekt za pomocą niestandardowego BlendState. W szczególności ten niestandardowy stan BlendState:
BlendState Multiply = new BlendState()
{
AlphaSourceBlend = Blend.DestinationAlpha,
AlphaDestinationBlend = Blend.Zero,
AlphaBlendFunction = BlendFunction.Add,
ColorSourceBlend = Blend.DestinationColor,
ColorDestinationBlend = Blend.Zero,
ColorBlendFunction = BlendFunction.Add
};
Równanie mieszania jest
result = (source * sourceBlendFactor) blendFunction (dest * destBlendFactor)
Dzięki naszemu niestandardowemu programowi BlendState tak się stanie
result = (lightmapColor * destinationColor) + (0)
Co oznacza, że kolor źródłowy czystej bieli (1, 1, 1, 1) zachowa kolor docelowy, kolor źródłowy czystej czerni (0, 0, 0, 1) przyciemni kolor docelowy do czystej czerni i dowolne odcień szarości pomiędzy nimi przyciemni docelowy kolor o średnią wartość.
Aby zastosować to w praktyce, najpierw zrób wszystko, co musisz zrobić, aby stworzyć lightmap:
var lightmap = GetLightmapRenderTarget();
Następnie po prostu narysuj nieoświetloną scenę bezpośrednio w buforze backbuff, jak zwykle:
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend);
/* draw the world here */
spriteBatch.End();
Następnie narysuj lightmap za pomocą niestandardowego BlendState:
var offsetX = 0; // you'll need to set these values to whatever offset is necessary
var offsetY = 0; // to align the lightmap with the map tiles currently being drawn
var width = lightmapWidthInTiles * tileWidth;
var height = lightmapHeightInTiles * tileHeight;
spriteBatch.Begin(SpriteSortMode.Immediate, Multiply);
spriteBatch.Draw(lightmap, new Rectangle(offsetX, offsetY, width, height), Color.White);
spriteBatch.End();
Spowoduje to pomnożenie koloru docelowego (nieoświetlone płytki) przez kolor źródłowy (lightmap), odpowiednie przyciemnienie nieoświetlonych płytek i stworzenie efektu gradientu w wyniku skalowania tekstury lightmap do wymaganego rozmiaru.
Dobra, tutaj jest jedna bardzo prosta metoda stworzenia prostej i płynnej błyskawicy 2D, renderowanej w trzech przejściach:
W przełęczy 1 narysujesz wszystkie duszki i teren.
W pasażu 2 narysujesz drugą grupę duszków, które są źródłami światła. Powinny wyglądać podobnie do tego:
Zainicjuj cel renderowania za pomocą czerni i narysuj na nim te duszki za pomocą mieszania maksymalnego lub addytywnego.
W pasażu 3 łączysz dwa poprzednie podania. Istnieje wiele różnych sposobów ich łączenia. Ale najprostszą i najmniej artystyczną metodą jest połączenie ich ze sobą za pomocą Multiply. Wyglądałoby to tak:
źródło
Drugi opublikowany link wygląda jak mgła wojny , jest na to kilka innych pytań
Wygląda mi to na teksturę , w której „kasujesz” fragmenty czarnej nakładki (ustawiając alfa tych pikseli na 0), gdy gracz porusza się do przodu.
Powiedziałbym, że ta osoba musiała użyć pędzla „wymazać” w miejscu, w którym badał gracz.
źródło
Lekkie wierzchołki (rogi między płytkami) zamiast płytek. Mieszaj oświetlenie na każdej płytce w oparciu o cztery wierzchołki.
Wykonaj testy linii wzroku dla każdego wierzchołka, aby określić, jak jest ono oświetlone (możesz albo blok zatrzymać światło lub zmniejszyć światło, np. Policzyć ile przecięć każdego wierzchołka w połączeniu z odległością, aby obliczyć wartość światła zamiast używać czysty binarny test widoczny / niewidoczny).
Podczas renderowania kafelka wyślij wartość światła dla każdego wierzchołka do GPU. Możesz łatwo użyć modułu cieniującego fragmenty, aby pobrać interpolowaną wartość światła dla każdego fragmentu w ikonce kafelka, aby płynnie oświetlić każdy piksel. Minęło już tyle czasu, odkąd dotknąłem GLSL, że nie czułbym się komfortowo, podając prawdziwą próbkę kodu, ale w pseudo-kodu byłoby to tak proste, jak:
Moduł cieniujący wierzchołki musi po prostu przekazać wartości wejściowe do modułu cieniującego fragmenty, nic nawet skomplikowanego.
Otrzymasz jeszcze płynniejsze oświetlenie z większą liczbą wierzchołków (powiedzmy, jeśli każda płytka jest renderowana jako cztery sub-płytki), ale może to nie być warte wysiłku w zależności od jakości, której szukasz. Spróbuj najpierw w prostszy sposób.
źródło
line-of sight tests to each vertex
? To będzie drogie.