Einheit Terrane und Mesh Blending

Hallo allerseits, im Juni startet OTUS erneut den Unity Games Developer- Kurs . Im Vorfeld des Kursbeginns haben wir eine Übersetzung von interessantem Material zum Thema vorbereitet.



Heute werden wir darüber sprechen, wie ein terranes Netz (oder ein anderes Netz) in Unity gemischt wird. Diese Anleitung ist ziemlich fortgeschritten, aber ich habe versucht, sie in separate Schritte aufzuteilen. Es wird davon ausgegangen, dass Sie über allgemeine Unity-Kenntnisse und C # -Grundkenntnisse verfügen. Die Anleitung ist für die Verstärkung konzipiert, aber ich denke, sie kann auch auf das Shader-Diagramm angewendet werden. Dies ist mein erster Leitfaden, daher hoffe ich, dass er klar genug ist. Wenn Sie etwas hinzufügen möchten, lassen Sie es mich wissen. Ich habe hier ein Starter-Kit mit einigen zusätzlichen Shadern für dieses Projekt sowie ein Basis-Kit für den Einstieg beigefügt. Alle Projektdateien aus dem heutigen Handbuch stehen meinen Kunden für 5 US-Dollar zur Verfügung, aber in naher Zukunft werden sie allen zur Verfügung stehen.

Starter Kit
Das gesamte Projekt

: , , . . , , , . ( ) unity . , , .

Also fangen wir an. Zunächst werde ich das Problem herausgreifen und mich mit der Theorie befassen, auf der die Lösung basieren wird. Um eine Mischung zwischen dem Terran und anderen Maschen herzustellen, müssen Sie dem Shader irgendwie mitteilen, wo der Schnittpunkt mit dem Terran auftritt. Sprechen ist einfacher als tun, aber es gibt einen Weg. Und woraus besteht es? Render Texture hilft uns !

Was ist eine Rendertextur?


Die Rendertextur ist in der Tat die Position der Kamera, die in der Asset-Datei gespeichert wird. Rendertextur in Spielen wird am häufigsten zum Erstellen von Videoüberwachungsbildschirmen verwendet. Wir können die Render-Textur verwenden , um die Kameraansicht im Editor zu speichern, damit diese Textur dann als Shader verwendet werden kann. Dies ist nützlich, da wir Informationen über unser Gelände wie Höhe, Normalen und Farben in eine Textur backen können, die dann zur Laufzeit zum Mischen zwischen Maschen und Terran verwendet werden kann.


Textur-Rendering zum Anzeigen von Gänsebildern auf Fernsehgeräten in Untitled Goose Game

Anpassung


Lassen Sie uns zunächst eine neue Szene und einen neuen Terran erstellen. Stellen Sie eine geeignete Größe für die Arbeit ein, z. B. 200 x 200. Jetzt können Sie den Terraner so arrangieren, wie Sie möchten. Erstellen Sie dann eine neue Ebene, nennen Sie sie "Terrain" und weisen Sie dieser Ebene ein Terrain zu. Dies ist erforderlich, damit die Kameramaske Terrane in der Render-Textur aufnehmen kann .


Mein Meisterwerk Terrane

Die Projektquelldateien haben ein Fertighaus namens „BlendBakingCamera“ - ziehen Sie es auf die Bühne. Sie erhalten eine einfache orthografische Kamera. Vor der Kamera müssen Sie eine Keulungsmaske auf eine neue Terranebene legen . Positionieren Sie die Kamera in der Mitte des Terrans etwas über dem höchsten Punkt des Geländes. Stellen Sie dann die entfernte Clip-Ebene so ein, dass die Kamera den terranen Boden sieht. Am Ende sollte die Szene ungefähr so ​​aussehen:


Ersatz-Shader


Nachdem die Kamera eingerichtet ist, müssen Sie einen Weg finden, um terrane Daten aufzuzeichnen. Dafür benötigen wir Ersatz-Shader. Der Ersatz-Shader scheint eine zweifelhafte Aussicht zu sein, ich selbst habe lange nicht verstanden, wie er funktioniert. Tatsächlich ist jedoch alles sehr einfach und effektiv. Die Verwendung des Ersatz-Shaders bedeutet im Wesentlichen, dass jedes Objekt im Sichtfeld der Kamera mit einem einzigen Shader gerendert wird, unabhängig davon, welcher Shader den Objekten überlagert ist. Infolgedessen werden alle Objekte mit dem ausgewählten Ersatz-Shader gerendert , der eigentlich nur ein normaler Shader ist.

Der Shader, den wir zum Mischen benötigen, ist der Tiefen-Shader. Es rendert die Tiefe der Szene und ist eine Schlüsselkomponente bei der Erzeugung unseres Überblendungseffekts, da es die Tiefenwerte unserer Kamera in die Textur schreibt, damit wir sie später lesen können. Um mehr über diesen Shader und den Ersatz-Shader im Allgemeinen zu erfahren , empfehle ich Ihnen, dieses Handbuch unter Making Stuff Look Good in Unity zu lesen .


Beispiel für einen Tiefen-Shader

Lass uns anfangen zu backen


Erstellen wir eine neue Klasse und nennen sie "TerrainBlendingBaker" . Beginnen wir mit der Implementierung einer Tiefenmaske für den Basis-Terraner. Später werden wir zu diesem Skript zurückkehren, um Farben und Normalen hinzuzufügen.

Definieren Sie mehrere Variablen.

//Shader that renders object based on distance to camera
public Shader depthShader;
//The render texture which will store the depth of our terrain
public RenderTexture depthTexture;
//The camera this script is attached to
private Camera cam;

Erstellen wir nun eine neue Methode und nennen sie "UpdateBakingCamera" . Bei dieser Methode ermitteln wir die Kameradaten, die der Shader möglicherweise zum Rendern von Überblendungen in globalen Variablen benötigt.

private void UpdateBakingCamera()
    {
        //if the camera hasn't been assigned then assign it
        if (cam == null)
        {
            cam = GetComponent<Camera>();
        }
 
        //the total width of the bounding box of our cameras view
        Shader.SetGlobalFloat("TB_SCALE", GetComponent<Camera>().orthographicSize * 2);
        //find the bottom corner of the texture in world scale by subtracting the size of the camera from its x and z position
        Shader.SetGlobalFloat("TB_OFFSET_X", cam.transform.position.x - cam.orthographicSize);
        Shader.SetGlobalFloat("TB_OFFSET_Z", cam.transform.position.z - cam.orthographicSize);
        //we'll also need the relative y position of the camera, lets get this by subtracting the far clip plane from the camera y position
        Shader.SetGlobalFloat("TB_OFFSET_Y", cam.transform.position.y - cam.farClipPlane);
        //we'll also need the far clip plane itself to know the range of y values in the depth texture
        Shader.SetGlobalFloat("TB_FARCLIP", cam.farClipPlane);
 
        //NOTE: some of the arithmatic here could be moved to the shader but keeping it here makes the shader cleaner so ¯\_(ツ)_/¯
    }

Nun backen wir die Tiefe des Terrans in die Textur.

// The context menu tag allows us to run methods from the inspector (https://docs.unity3d.com/ScriptReference/ContextMenu.html)
[ContextMenu("Bake Depth Texture")]
public void BakeTerrainDepth()
{
    //call our update camera method 
    UpdateBakingCamera();
 
    //Make sure the shader and texture are assigned in the inspector
    if (depthShader != null && depthTexture != null)
    {
        //Set the camera replacment shader to the depth shader that we will assign in the inspector 
        cam.SetReplacementShader(depthShader, "RenderType");
        //set the target render texture of the camera to the depth texture 
        cam.targetTexture = depthTexture;
        //set the render texture we just created as a global shader texture variable
        Shader.SetGlobalTexture("TB_DEPTH", depthTexture);
    }
    else
    {
        Debug.Log("You need to assign the depth shader and depth texture in the inspector");
    }
}

Die Werte werden klarer, wenn wir mit dem Shader arbeiten. Hier ist ein kleines Bild, das etwas Licht ins Dunkel bringen könnte:


Wir werden das Terran in die Tiefenstruktur übertragen, um es später zu lesen und zu verstehen, wo das Mischen durchgeführt werden muss.

Jetzt haben wir alles, was wir brauchen, um den grundlegenden Mischungseffekt im Shader zu erzeugen. Zu diesem Zeitpunkt sieht das Skript ungefähr so ​​aus: pastebin.com/xNusLJfh

Okay, jetzt, da wir das Skript haben, können wir es der Backkamera hinzufügen, die wir zuvor hinzugefügt haben. Die Anfangsvermögen haben einen Shader namens 'DepthShader' (Inresin / Shaders / DepthShader) und eine Render - Textur namens 'DepthTerrainRT' (Inresin / RenderTextures / DepthTextureRT) , müssen Sie sie in die entsprechenden Felder in den Inspektor setzen.

Führen Sie danach die Methode einfach über das Kontextmenü aus, um unsere Geländetiefe in der Rendertextur zu backen .


Shader


Lassen Sie uns endlich einen Shader zum Mischen erstellen. Erstellen Sie einen neuen Standard -Amplify- Shader und öffnen Sie ihn. Nennen Sie ihn "TerrainBlending" oder so.

Jetzt müssen wir eine UV-Strahlung für die Rendertextur erstellen . Dadurch wird die Differenz zwischen dem Punkt sein, der wiedergegeben wird, und die Backkameraposition zur Gesamtfläche relativ skaliert. Die drei globalen Variablen hier sind diejenigen, die wir gerade im Code deklariert haben. Wir setzen worldY auch als lokale Variable, wir werden es später brauchen.



Nehmen wir die Tiefenstruktur, die wir als globale Variable zugewiesen haben (für diesen Beispielknoten zum Hinzufügen von Texturen machen Sie sie global und nennen sie 'TB_DEPTH'.), wenn wir die Ausgabe in das Feld debug amplify shader 'a setzen, können wir sehen, was passiert. Erstellen Sie eine Ebene mit dem Material, auf das unser neuer Shader angewendet wird.


Im Shader haben wir also Informationen über die Tiefe. Jetzt müssen wir einen Versatz in y hinzufügen, um eine Überblendung zu erhalten.



Dieser Block skaliert die y-Position der Maske der Fernclip-Ebene , subtrahiert diesen Wert von der Weltposition entlang der y-Achse des gerenderten Punkts und verschiebt ihn schließlich auf die Unterseite des Begrenzungsrahmens der Kamera (y-Position der Kamera abzüglich der Farclip-Ebene ).

Schon was! Wir sehen, wie die Kanten des Flugzeugs mit dem Terran verschmelzen.



Ok, lassen Sie uns das Mischen kontrollierter machen.



Jetzt können wir die Dicke und Fläche des Mischterrans steuern.



Ich denke, wir können sogar ein wenig Lärm hinzufügen. Verwenden wir die Weltposition , um Rauschen aus der Textur zu erzeugen.



Rauschtexturen befinden sich im Texturordner des Startprojekts. Sie können im Inspektor oder als Konstante im Shader selbst zugewiesen werden.

Endlich ist es Zeit, einige Texturen hinzuzufügen! Um zu beginnen, verwenden wir einige einfache einfarbige Texturen. Ich habe dem Ordner zwei Texturen mit Textur-Assets hinzugefügt. Machen Sie die 'SingleColorGrass'- Textur zu einer terranen Textur. Dann müssen Sie im Shader eine terrane Textur und einen Objekttexturknoten erstellen . Wir werden zwischen ihnen auf dem roten Kanal der Maske wechseln, die wir gerade erstellt haben.




Und hier ist der komplette Shader:



Das Hinzufügen von benutzerdefinierten Toon- Beleuchtungs- oder unbeleuchteten Beleuchtungsmodellen liefert die besten Ergebnisse für diesen Shader. Ich schaltete mich unbeleuchtet einTerrane Shader und unbeleuchtete Version des Shaders im Gesamtpaket für Sponsoren.


Unbeleuchtete Terrane und Meshes

Ich empfehle außerdem, dem Terrane und möglicherweise anderen Meshes einen triplanaren Shader hinzuzufügen. Ich kann dieses Problem im nächsten Handbuch behandeln.

Nun, wir sind fast fertig mit dem Hauptthema des heutigen Leitfadens. Ich habe einige Abschnitte hinzugefügt, die bei der Shader-Erweiterung helfen können.

Shader-Erweiterung - Normal


Ich habe den Dateien einen regulären Shader hinzugefügt. Sie können damit Normalen auf die terrane Oberfläche schreiben und auch Blending verwenden. Für mein Spiel brauche ich kein normales Mischen, also habe ich nur ein bisschen experimentiert und es sieht so aus, als ob das Experiment ein Erfolg war. Meine Idee eignet sich gut für Gelände ohne großen Höhenunterschied. Ich habe den normalen Mapping-Shader in das Verzeichnis mit den Startsatz-Shadern aufgenommen. Hier sehen Sie meine grundlegende Implementierung der normalen Karte:



Der Code ist fast der gleiche wie bei der Tiefenkarte, aber dieses Mal verwenden wir die normale Karte als Ersatz-Shader . Ich habe auch eine Reihe von Rendertexturen für die normale Aufnahme hinzugefügt (hier benötigen Sie möglicherweise eine zusätzliche Konfiguration).

Damit die Normalen gut funktionieren, ist möglicherweise ein wenig mehr Aufwand im Zusammenhang mit der Abstimmung erforderlich, und es kann auch eine Einschränkung bei Terranen mit niedrigem Pegel geben (aber ich habe nicht genügend Tests durchgeführt, um dies zu bestätigen).

Shader-Erweiterung - Alle Farben


Ich werde nicht näher auf die Details dieses Themas eingehen, da es über das hinausgeht, was für mein Spiel erforderlich ist, aber ich habe beim Schreiben dieses Handbuchs daran gedacht. Um das Mischen vieler Farben hinzuzufügen, können wir unbeleuchtete terrane Farben auswählen und sie als Texturen speichern. In diesem Fall sind wir durch eine relativ niedrige Auflösung eingeschränkt, aber diese Methode funktioniert gut, wenn Sie einfarbige Geländetexturen und Texturen mit niedriger Auflösung verwenden oder wenn Sie schwach bluten . Mit geringfügigen Anpassungen können sie auch auf terrane Netze angewendet werden.

Hier ist der Code für die Mehrfarbenoption:

[Header("The following settings are only if using the multi-color terrain shader")]
//Shader that renders the unlit terraom of an object
public Shader unlitTerrainShader;
//The render texture which will store the normals of our terrain
public RenderTexture surfaceTexture;
//An unlit terrain material used to capture the texture of our terrain without any lighting
public Material unlitTerrainMaterial;
//The terrain you want to capture the textures of
public Terrain yourTerrain;
 
[ContextMenu("Bake Surface Texture")]
public void BakeTerrainSurface()
{
    UpdateBakingCamera();
 
    //return if there is no terrain assigned
    if (yourTerrain == null)
    {
        Debug.Log("You need to assign a terrain to capture surface texture");
        return;
    }
 
    StartCoroutine(BakeColors());
}
 
IEnumerator BakeColors()
{
    Material tempTerrainMaterial = yourTerrain.materialTemplate;
 
    yourTerrain.materialTemplate = unlitTerrainMaterial;
 
    yield return 0;
 
    cam.SetReplacementShader(unlitTerrainShader, "RenderType");
    cam.targetTexture = surfaceTexture;
    Shader.SetGlobalTexture("TB_SURFACE", surfaceTexture);
 
    yield return 0;
 
    cam.targetTexture = null;
    yourTerrain.materialTemplate = tempTerrainMaterial;
 
    yield return null;
 
}

Die einzige Änderung im Shader besteht darin, dass anstelle einer vordefinierten Textur eine global definierte Geländeoberflächentextur verwendet wird, bei der die relative Position als UV verwendet wird. Eine zusätzliche Erweiterung ermöglicht es Ihnen, Texturen angenehmer zu mischen.


Mischen mehrerer Texturen

Hier ist ein vollständiges mehrfarbiges Diagramm mit einem normalen Misch-Shader:




Fazit


Herzlichen Glückwunsch, wenn Sie bis zu diesem Punkt gelesen haben! Wie gesagt, dies ist mein erster Leitfaden, daher würde ich mich über Feedback sehr freuen. Wenn Sie mich beim Erstellen von Spielen und Tutorials unterstützen möchten, schauen Sie hier oder abonnieren Sie mein Twitter .



Erfahren Sie mehr über den Kurs

All Articles