Wie kann ich in Unity zwei Lightmaps für Tag / Nacht-Zyklen mischen?

16

Bevor ich etwas anderes sage: Ich verwende duale Lichtkarten, was bedeutet, dass ich sowohl nah als auch fern mischen muss.

Ich arbeite also schon eine Weile daran, ich habe einen ganzen Tag / Nacht-Zyklus für Renderer und Beleuchtung eingerichtet, und alles funktioniert gut und nicht prozessintensiv.

Das einzige Problem, das ich habe, ist herauszufinden, wie ich zwei Lightmaps zusammenmischen kann. Ich habe herausgefunden, wie man Lightmaps wechselt, aber das Problem ist, dass es abrupt aussieht und die Erfahrung unterbricht.

Ich habe stundenlang nachgeforscht, alle Arten von Shadern ausprobiert, Pixel für Pixel gemischt und alles andere ohne wirklichen Erfolg. Pixel für Pixel in C # zu mischen hat sich für meinen Geschmack als ein bisschen prozessintensiv herausgestellt, obwohl ich immer noch daran arbeite, es aufzuräumen und es reibungsloser zu machen. Shader sahen vielversprechend aus, aber ich konnte keinen Shader finden, der zwei Lightmaps richtig mischen konnte.

Hat jemand irgendwelche Hinweise, wie ich dies erreichen könnte? Ich brauche nur einen fließenden Übergang zwischen meiner Tages- und Nachtlichtkarte. Vielleicht könnte ich die beiden Texturen überlagern und einen Alphakanal verwenden? Oder etwas ähnliches?

Timothy Williams
quelle
Wenn Sie Pro haben, können Sie vielleicht die beiden Lightmap-Texturen in eine dritte rendern und diese dritte Textur dann als Lightmap verwenden? Das sollte genauso sein wie Pixel Blending, aber massiv schneller.
Nevermind
Ich habe Pro. Wie würde ich vorgehen, um die beiden Lightmap-Texturen zusammen zu rendern? Dies war mein Hauptanhaltspunkt, aber ich habe versucht, den Code / Prozess herauszufinden, um dies zu erreichen.
Timothy Williams
Umm erstellen Sie ein Material, das zwei Texturen mischt, Graphics.Blit()um es zu rendern? Ich habe das noch nie gemacht, aber im Handbuch nachzusehen, sollte funktionieren.
Nevermind
Erstellen Sie also ein neues Material, mit dem zwei Texturen zu einer Ausgabe gemischt werden können, wenden Sie Afar-1 und Bfar-1 an und verwenden Sie dann die ausgehende Textur für die Lightmap-Variable.
Timothy Williams
Genau, so etwas Ähnliches. Ich würde es testen, aber ich habe im Moment keinen Zugriff auf die Pro-Version.
Nevermind

Antworten:

3

Also habe ich mich kürzlich daran versucht und bin auf viele der gleichen Probleme gestoßen, die ihr habt. Die Render-Textur-Lösung ist ein bisschen wie ein roter Hering. Ich konnte es mit Multithreading-Pixel-Manipulation auf einem separaten Thread lösen.

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

graphics.blit()Normalerweise verwendet man die Render-Textur und übergibt sie dort, wo sie benötigt wird, aber Lightmap-Daten unterstützen keine Texturen, sondern benötigen texture2ds. Der nächste logische Schritt wäre, die Daten in eine texture2d zu kopieren und diese dann in die Lightmap-Daten einzuspeisen. Diese Technik ruiniert die Bildraten, da die GPU blockiert, um Daten an die CPU zu senden, anstatt nur auf die Daten zu verweisen.

Die Lösung besteht dann darin, die GPU nicht zu verwenden.

Lichtkartenübergänge finden über einen langen Zeitraum statt, sodass es nicht unbedingt wichtig ist, die Lichtkarte bei jedem Frame zu aktualisieren. In der Tat würden die Spieler wahrscheinlich nicht bemerken, wenn die Lichtkarten nur alle 20-40 Minuten in der Spielzeit aktualisiert würden.

Sie geben die Aufgabe also für jede Light Map in separaten Threads an die CPU aus.

Normalerweise unterstützt Unity kein Multithreading. Aber das ist okay, C # tut es. Dieser Typ macht einen phänomenalen Job, um Multithreading in Unity zu erklären. Wenn Sie noch nie davon gehört haben oder noch nie gewusst haben, wie Multithreading in Unity funktioniert, ist dies das Video:

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

Sie müssen lediglich eine Arbeitsthreadklasse erstellen, die Kopien der Lightmap-Pixeldaten in Farbarrays variiert, und anschließend eine Mischfunktion erstellen.

Ein einfaches Lerp von einer Farbe zur nächsten reicht aus.

Dann erstelle den Thread, starte ihn und wenn alle Lightmaps in den separaten Threads fertig sind, kannst du die Pixeldaten zurück in die Lightmap-Daten-Textur2d kopieren.

Ich habe unten einen Beispielcode gepostet. Es ist sicherlich nicht die vollständig implementierte Version, aber sie zeigt Ihnen die wichtigsten Konzepte zum Erstellen der Klasse, zum Erstellen des Threads und zum Festlegen der Lichtdaten.

Das andere, was Sie tun müssten, ist, ab und zu eine Funktion aufzurufen, um die Aktualisierung der Lightmaps auszulösen. Außerdem müssen Sie entweder alle Pixeldaten beim Start oder beim Kompilieren in die Worker-Klasse kopieren. Viel Glück für alle, die das finden. Ich glaube, die Operation hat ihr Leben fortgesetzt, aber ich weiß, dass andere Menschen mit ähnlichen Problemen darüber stolpern könnten.

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
quelle
1

Es gibt einen Skybox-Shader, der zwischen zwei Sets von Skybox-Texturen mischt. Denken Sie Tag und Nacht Zyklus!

Wenn Sie die Skybox aus einem Skript erstellen oder animieren möchten skyboxmaterial.SetFloat("_Blend", yourBlend), ändern Sie die Überblendung mit. kann auch verwendenSetTexture Materialfunktionen zum Einrichten oder Ändern der Texturen verwenden.

Video-Tutorial zum Tag / Nacht-Zyklus: http://www.youtube.com/watch?v=FTfv9JhkmIA

Der Beispielcode lautet wie folgt:

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
quelle
2
Die Frage stellte sich nach Lightmaps, nicht nach Skybox. Vielen Dank für den Link, das scheint mir nützlich zu sein.
jhocking
0

Wenn Sie wissen, wie man umschaltet, warum nicht mit dem Erstellen einer Reihe von Übergangs-Lightmaps im Hintergrund-Thread fortfahren und dann die Übergänge aktivieren, wenn die Lightmaps fertig sind?

Sie können sich auch ein interessantes Asset im AssetStore ansehen: https://www.assetstore.unity3d.com/en/#!/content/5674

Ich denke, es beinhaltet die Überblendung der Lichtkarten, obwohl ich nicht weiß, wie.

tomekkie
quelle