Jak mieszać 2 mapy świetlne dla cyklu dzień / noc w Unity?

16

Zanim powiem cokolwiek innego: używam podwójnych map świetlnych, co oznacza, że ​​muszę połączyć zarówno bliski, jak i daleki.

Pracuję nad tym już od jakiegoś czasu, mam ustawiony cały cykl dzień / noc dla rendererów i oświetlenia, i wszystko działa dobrze i nie wymaga dużego przetwarzania.

Jedynym problemem, jaki mam, jest wymyślenie, jak mogę połączyć ze sobą dwie mapy świetlne, wymyśliłem, jak przełączać mapy świetlne, ale problem polega na tym, że wygląda to tak nagle i przeszkadza.

Przeprowadziłem wiele godzin badań nad tym, wypróbowałem wszelkiego rodzaju shadery, mieszanie pikseli po pikselach i wszystko inne bezskutecznie. Mieszanie piksel po pikselu w C # okazało się dla mnie trochę intensywnym procesem, choć wciąż pracuję nad jego czyszczeniem i poprawianiem płynności. Shadery wyglądały obiecująco, ale nie mogłem znaleźć shadera, który mógłby odpowiednio połączyć dwie mapy świetlne.

Czy ktoś ma jakieś wskazówki, jak to osiągnąć? Potrzebuję tylko pewnego rodzaju płynnego przejścia między moją świetlną mapą w dzień i w nocy. Może mógłbym nałożyć dwie tekstury i użyć kanału alfa? Czy jakoś tak?

Timothy Williams
źródło
Jeśli masz wersję Pro, być może możesz przekształcić dwie tekstury lightmapy w trzecią, a następnie użyć tej trzeciej tekstury jako lightmapy? To powinno być jak mieszanie pikseli, ale znacznie szybsze.
Nevermind
Mam Pro. Jak miałbym przejść do renderowania dwóch tekstur lightmap razem? To był mój główny trop, ale starałem się znaleźć kod / proces, aby go osiągnąć.
Timothy Williams
Umm stworzyć materiał, który łączy dwie tekstury, użyć Graphics.Blit()do renderowania? Nigdy tego nie robiłem, ale patrząc na instrukcję, powinna działać.
Nevermind
Więc stwórz nowy materiał, który może łączyć dwie tekstury z wyjściem, zastosować Afar-1 i Bfar-1, a następnie użyć tekstury wychodzącej dla zmiennej lightmap?
Timothy Williams
Tak, coś takiego. Testowałbym to, ale w tej chwili nie mam dostępu do wersji Pro.
Nevermind

Odpowiedzi:

3

Niedawno więc spróbowałem swoich sił i napotkałem wiele takich samych problemów, jakie macie. Rozwiązaniem do renderowania tekstury jest trochę czerwony śledź. Udało mi się to rozwiązać za pomocą wielowątkowej manipulacji pikselami w osobnym wątku.

https://www.youtube.com/watch?v=T_zpFk1mdCI

Zwykle używa się graphics.blit()i przekazuje teksturę renderowania tam, gdzie trzeba, ale dane lightmap nie obsługują tekstur, wymagają texture2ds. Kolejnym logicznym krokiem byłoby skopiowanie danych do texture2d, a następnie przekazanie ich do danych lightmap. Ta technika rujnuje liczbę klatek na sekundę, ponieważ opóźnia procesor graficzny, aby wysłać dane do procesora, a nie tylko odniesienie do danych.

Rozwiązaniem jest wtedy, aby nie używać GPU.

Przejścia jasnej mapy następują przez długi czas, więc aktualizowanie jasnej mapy co klatkę nie musi być ważne. W rzeczywistości gracze prawdopodobnie nie zauważyliby, gdyby lekkie mapy były aktualizowane tylko co 20-40 minut w czasie gry.

Więc to, co robisz, wysyłasz zadanie do CPU osobnymi wątkami dla każdej mapy świetlnej.

Zwykle jedność nie obsługuje wielowątkowości. Ale to dobrze, C # robi. Ten facet wykonuje fenomenalną robotę wyjaśniając wielowątkowość w Unity, więc jeśli nigdy o tym nie słyszałeś lub nigdy nie wiedziałeś, jak wielowątkowość w Unity to ten film:

https://www.youtube.com/watch?v=ja63QO1Imck

Wszystko, co musisz zrobić, to utworzyć roboczą klasę wątków, która zmienia kopie danych pikseli lightmap w tablicach kolorów, a następnie utworzyć funkcję mieszania.

Wystarczy prosty lerp z jednego koloru do drugiego.

Następnie utwórz wątek, uruchom go, a gdy wszystkie lightmapy zostaną ukończone w osobnych wątkach, możesz skopiować dane pikseli z powrotem do danych lightmap texture2d.

Poniżej zamieściłem przykładowy kod. Z pewnością nie jest to w pełni zaimplementowana wersja, ale pokazuje główne koncepcje tworzenia klasy, tworzenia wątku, a następnie ustawiania lightdata.

Inną rzeczą, którą musisz zrobić, to wywoływać funkcję co jakiś czas, aby uruchomić aktualizację map świetlnych. Musisz także skopiować wszystkie dane pikseli do klasy procesu roboczego na początku lub w czasie kompilacji. Powodzenia dla każdego, kto to znajdzie. Myślę, że operacja przeszła z ich życiem, ale wiem, że inni ludzie z podobnymi problemami mogą się na to natknąć.

public class work
{
    Color[] fromPixels;
    Color[] toPixels;

    public float LerpValue = 0;
    public bool Finished = false;
    public Color[] mixedPixels;

    public work(Color[] FromPix, Color[] ToPix)
    {
        fromPixels= FromPix;
        toPixels= ToPix;
        Finished = false;
        mixedPixels = new Color[FromPix.Length];
    }
    public void DoWork()
    {
        for (int x = 0; x < fromPixels.Length; x++)
        {
            mixedPixels[x] = Color.Lerp(fromPixels[x], toPixels[x], LerpValue);
        }
        Finished = true;
    }
}

IEnumerator LightMapSet()
{
    Thread workerThread = new Thread(someworker.DoWork);
    someworker.LerpValue = lerpValue;
    workerThread.Start();
    yield return new WaitUntil(() => someworker.Finished);
    mixedMap.SetPixels(someworker.mixedPixels);
    mixedMap.Apply(true);
    LightmapData someLightmapData;
    someLightmapData.lightmapColor = mixedMap;
    lightDatas = { someLightmapData};
    LightmapSettings.lightmaps = lightDatas;
}
Douglas Potesta
źródło
1

Istnieje moduł cieniujący skybox, który łączy dwa zestawy tekstur skybox. Pomyśl o cyklu dziennym i nocnym!

Jeśli chcesz zbudować lub animować skybox ze skryptu, użyj, skyboxmaterial.SetFloat("_Blend", yourBlend)aby zmienić mieszanie; może także używać SetTexturefunkcji materiałowych do ustawiania lub zmiany tekstur.

Samouczek wideo na temat cyklu dzień / noc: http://www.youtube.com/watch?v=FTfv9JhkmIA

Przykładowy kod wygląda następująco:

Shader "RenderFX/Skybox Blended" {
Properties {
    _Tint ("Tint Color", Color) = (.5, .5, .5, .5)
    _Blend ("Blend", Range(0.0,1.0)) = 0.5
    _FrontTex ("Front (+Z)", 2D) = "white" {}
    _BackTex ("Back (-Z)", 2D) = "white" {}
    _LeftTex ("Left (+X)", 2D) = "white" {}
    _RightTex ("Right (-X)", 2D) = "white" {}
    _UpTex ("Up (+Y)", 2D) = "white" {}
    _DownTex ("Down (-Y)", 2D) = "white" {}
    _FrontTex2("2 Front (+Z)", 2D) = "white" {}
    _BackTex2("2 Back (-Z)", 2D) = "white" {}
    _LeftTex2("2 Left (+X)", 2D) = "white" {}
    _RightTex2("2 Right (-X)", 2D) = "white" {}
    _UpTex2("2 Up (+Y)", 2D) = "white" {}
    _DownTex2("2 Down (-Y)", 2D) = "white" {}
}

SubShader {
    Tags { "Queue" = "Background" }
    Cull Off
    Fog { Mode Off }
    Lighting Off        
    Color [_Tint]
    Pass {
        SetTexture [_FrontTex] { combine texture }
        SetTexture [_FrontTex2] { constantColor (0,0,0,[_Blend]) combine texture lerp(constant) previous }
        SetTexture [_FrontTex2] { combine previous +- primary, previous * primary }
    }
    Pass {
        SetTexture [_BackTex] { combine texture }
        SetTexture [_BackTex2] { constantColor (0,0,0,[_Blend]) combine texture lerp(constant) previous }
        SetTexture [_BackTex2] { combine previous +- primary, previous * primary }
    }
    Pass {
        SetTexture [_LeftTex] { combine texture }
        SetTexture [_LeftTex2] { constantColor (0,0,0,[_Blend]) combine texture lerp(constant) previous }
        SetTexture [_LeftTex2] { combine previous +- primary, previous * primary }
    }
    Pass {
        SetTexture [_RightTex] { combine texture }
        SetTexture [_RightTex2] { constantColor (0,0,0,[_Blend]) combine texture lerp(constant) previous }
        SetTexture [_RightTex2] { combine previous +- primary, previous * primary }
    }
    Pass {
        SetTexture [_UpTex] { combine texture }
        SetTexture [_UpTex2] { constantColor (0,0,0,[_Blend]) combine texture lerp(constant) previous }
        SetTexture [_UpTex2] { combine previous +- primary, previous * primary }
    }
    Pass {
        SetTexture [_DownTex] { combine texture }
        SetTexture [_DownTex2] { constantColor (0,0,0,[_Blend]) combine texture lerp(constant) previous }
        SetTexture [_DownTex2] { combine previous +- primary, previous * primary }
    }
}

Fallback "RenderFX/Skybox", 1
}
JA Corbal
źródło
2
Pytanie o lightmapy, a nie Skybox. Dzięki za link, wygląda na to, że będzie dla mnie przydatny.
jhocking
0

Jeśli wiesz, jak się przełączać, dlaczego nie kontynuować tworzenia wielu przejściowych map świetlnych w wątku tła, a następnie włączyć przejścia, gdy mapy świetlne będą gotowe?

Możesz także obejrzeć interesujący zasób w AssetStore: https://www.assetstore.unity3d.com/en/#!/content/5674

Wydaje mi się, że obejmuje mieszanie lightmap, chociaż nie wiem jak.

tomekkie
źródło