Jump to content
Unity Insider Forum
  • Announcements

    • Lars

      Allgemeine Forenregeln   03/13/2017

      Forenregeln Nimm dir bitte einen Moment um die nachfolgenden Regeln durchzulesen. Wenn du diese Regeln akzeptierst und die Registration fortsetzen willst, klick einfach auf den "Mit der Registrierung fortfahren"-Button. Um diese Registration abzubrechen, klick bitte einfach auf den "Zurück" Button deines Browsers. Wir garantieren nicht für die Richtigkeit, Vollständigkeit und Brauchbarkeit der Nachrichten und sind auch nicht dafür verantwortlich. Die Beiträge drücken die Meinung des Autors des Beitrags aus, nicht zwangsläufig das, wofür die Forensoftware steht. Jeder Nutzer, der denkt, dass ein veröffentlichter Beitrag unzulässig bzw. störend ist, ist aufgefordert uns unverzüglich per E-Mail zu kontaktieren. Wir haben das Recht störende Beiträge zu löschen und bemühen uns, das in einem realistischem Zeitraum zu erledigen (sofern wir beschlossen haben, dass die Löschung notwendig ist). Du akzeptierst, durchgehend während der Nutzung dieses Services, dass du dieses Forum nicht dazu missbrauchen wirst, Inhalte zu veröffentlichen, welche bewusst falsch und/oder verleumderisch, ungenau, beleidigend, vulgär, hasserfüllt, belästigend, obszön, sexuell belästigend, bedrohlich, die Privatsphäre einer Person verletzend oder in irgend einer Art und Weise das Gesetz verletzen. Des Weiteren akzeptierst du, dass du keine urheberrechtlich geschützte Inhalte ohne Erlaubnis des Besitzers in diesem Forum veröffentlichst. Mit dem Klick auf den "Mit der Registrierung fortfahren"-Button, akzeptierst du zudem unsere Datenschutzerklärung und stimmst der Speicherung deiner IP-Adresse und personenbezogenen Daten zu, die dafür benötigt werden, um dich im Falle einer rechtswidrigen Tat zurückverfolgen zu können bzw. permanent oder temporär aus dem Forum ausschließen zu können. Es besteht keine Pflicht zur Abgabe der Einwilligung, dies erfolgt alles auf freiwilliger Basis.   Zusatzinformationen Der Forenbetreiber hat das Recht, Nutzer ohne Angabe von Gründen permanent aus dem Forum auszuschließen. Des Weiteren hat er das Recht, Beiträge, Dateianhänge, Umfrage, Blogeinträge, Galleriebilder oder Signaturen ohne Angabe von Gründen zu entfernen. Mit der Registrierung verzichtest du auf alle Rechte an den von dir erstellten Inhalten, bzw. treten diese an das Unity-Insider.de und Unity-Community.de ab. Dies bedeutet im Klartext, dass das Unity-Insider.de und Unity-Community.de frei über deine Texte verfügen kann, sofern diese nicht wiederum die Rechte anderer verletzen. Es besteht weiterhin kein Anspruch von registrierten Nutzern bzw. ehemaligen registrierten Nutzern darauf, dass erstellte Inhalte und/oder die Mitgliedschaft (User) wieder gelöscht werden (Erhaltung der Konsistenz dieses Forums).   Einwilligungserklärung Wenn du mit der Speicherung deiner personenbezogenen Daten sowie den vorstehenden Regeln und Bestimmungen einverstanden bist, kannst du mit einem Klick auf den Mit der Registrierung fortfahren-Button unten fortfahren. Ansonsten drücke bitte Zurück. Stand: 07.03.2011
Sign in to follow this  
StefanD

TileMap AlphaBlending

Recommended Posts

Hallo zusammen,

ich versuche mich gerade daran meine Tilemap etwas zu verschönern. Diese wird aktuell mit einem eigenen Shader mit einem TextureArray gezeichnet. Leider sehen damit die Übergänge zwischen den Tiles ziemlich "bescheiden" aus. Daher würde ich gerne immer die benachbarten Tiles mit überblenden um einen sauberen Übergang zwischen den Typen zu haben. Ich habe hier aber das Problem das mir nicht ganz klar ist wie ich das Umsetzen kann.

Hier der Shader Code ohne Anpassungen:

Shader "Custom/TileMap" {
	Properties{
		_MainTex("Texture", 2DArray) = "white" {}
	}
		SubShader{
		Pass{
			CGPROGRAM
				#pragma vertex MyVertexProgram
				#pragma fragment MyFragmentProgram
				#pragma target 3.5
				#include "UnityCG.cginc"

				UNITY_DECLARE_TEX2DARRAY(_MainTex);

				struct VertexData {
					float4 position : POSITION;
					float3 uv : TEXCOORD0;
				};

				struct Interpolators {
					float4 position : SV_POSITION;
					float3 uv : TEXCOORD0;
				};

				Interpolators MyVertexProgram(VertexData v) {
					Interpolators i;
					i.position = UnityObjectToClipPos(v.position);
					i.uv = v.uv;
					return i;
				}

				fixed4 MyFragmentProgram(Interpolators i) : SV_TARGET {
					return UNITY_SAMPLE_TEX2DARRAY(_MainTex, i.uv);
				}
			ENDCG
		}
	}
	FallBack "Diffuse"
}

 

Meine Idee wäre gewesen zum einen jeweils die Texture ID der benachbarten Tiles sowie eine BlendMap an den Shader zu übergeben und die benachbarten Tiles damit zu überblenden. Ich habe das schon für den geraden Übergang von links nach rechts gemacht. Wenn ich das so mache, würde ich aber jeweils 9 Texturen (Haupt Texture + 8 Nachbarn) und 8 BlendMaps für jeden Nachbarn benötigen. Das kommt mir aber etwas viel vor, unabhängig davon ob es überhaupt möglich ist.

 

Shader "Custom/TileMap" {
	Properties{
		_MainTex("Texture", 2DArray) = "white" {}
		_BlendTex("Blend", 2D) = "White" {}
	}
		SubShader{
		Pass{
			CGPROGRAM
				#pragma vertex MyVertexProgram
				#pragma fragment MyFragmentProgram
				#pragma target 3.5
				// #include "UnityCG.cginc"

				UNITY_DECLARE_TEX2DARRAY(_MainTex);
				sampler2D _BlendTex;

				struct VertexData {
					float4 position : POSITION;
					float3 uv : TEXCOORD0;
					float3 left : TEXCOORD1;
				};

				struct Interpolators {
					float4 position : SV_POSITION;
					float3 uv : TEXCOORD0;
					float3 left : TEXCOORD1;
				};

				Interpolators MyVertexProgram(VertexData v) {
					Interpolators i;
					i.position = UnityObjectToClipPos(v.position);
					i.uv = v.uv;
					i.left = v.left;
					return i;
				}

				fixed4 MyFragmentProgram(Interpolators i) : SV_TARGET {
					fixed4 main = UNITY_SAMPLE_TEX2DARRAY(_MainTex, i.uv);
					fixed4 left = UNITY_SAMPLE_TEX2DARRAY(_MainTex, i.left);

					fixed4 blend = tex2D(_BlendTex, i.uv);

					return main.rgba * blend.a + (1 - blend.a) * left.rgba;
				}
			ENDCG
		}
	}
	FallBack "Diffuse"
}

 

Hat jemand ein paar Tipps wie das ganze sonst Umgesetzt werden kann? Oder bin ich mit meinem Versuch prinzipiell schon auf dem richtigen Weg?

Vielen Dank und noch einen schönen Sonntag

Gruß Stefan

Share this post


Link to post
Share on other sites

Meinst du das hier?:
https://docs.unity3d.com/Manual/Tilemap.html

Solltest du obiges meinen, ist der Shader nur ein Teil des Ganzen, da die Tilemap über den Tile-Renderer erzeugt wird. Dem Shader selbst fehlen die Informationen über die umgebenden Tiles (dieser rendert ja nur ein Tile). Der Tile-Renderer sollte diese Information allerdings kennen. Ich habe es nur überfolgen, aber ich denke man kann hiermit den Tile-Renderer erweitern:
https://docs.unity3d.com/Manual/Tilemap-ScriptableTiles.html

Nachdem du den Tile-Renderer angezapft hast, könntest du die umgebenen Tiles auslesen und sie als Parameter an deinen Shader übergeben:
https://docs.unity3d.com/ScriptReference/Material.SetTexture.html

Ist aber ein ziemlicher Aufwand.

Hier ist auch noch einiges an Quellcode und Beispielen zu finden:
https://github.com/Unity-Technologies/2d-extras

Share this post


Link to post
Share on other sites

Hallo Zer0Cool,

nein das meine ich nicht. Ich habe den Shader und die Tiles selbst geschrieben. Aber ich erkläre noch einmal kurz was ich genau versuche zu tun. Ich habe eine Karte auf der sich Gebäude, Einheiten usw. befinden. Mir geht es aktuell um das zeichnen der Karte. Mit dem oberen Shader habe ich angefangen. Darin übergabe ich an das Probertie "MainTex" ein Array mit Texturen (Alle Texturen, welche auf der Karte gezeichnet werden sollen). Hier ist das beschrieben: Unity3D - Texture Arrays

Dabei wird nun aber das gesamte Tile mit der jeweiligen Texture gezeichnet, was theoretisch ja richtig ist aber einfach nicht gut aussieht. Welche Texture gezeichnet wird steht in der Z-Koordinate der uv. Daher wollte ich nun mit einer Alpha Map die benachbarten Tiles überblenden, damit das ganze schöne Übergänge hat und die Tiles nicht mehr ganz so zu sehen sind. Das ganze wird auch in dem Beitrag (Game Map in HTML Canvas) beschrieben. Hier habe ich die Idee her, schaffe es aber nicht wirklich das zu implementieren.

Im unteren Shader übergebe ich dann eine zweite UV "left", in dem ebenfalls in der Z-Koordinate der Type des Linken Nachbarn steht. Nur mit dem linken Nachbarn funktioniert das Vorgehen auch. Jedoch habe ich jetzt das Problem das mir nicht ganz klar ist wie ich das für alle Ränder und Ecken machen kann. 

Theoretisch könnte ich das vorgehen wie für die Linke Seite für jede Seite und Ecke machen, was aber zur Folge hat, das ich nur für die Texture schon 9 Textkoordinaten an den Shader übergeben muss. Zusätzlich dann natürlich auch für die BlendMap. Meine Frage bezieht sich darauf ob das eine Lösung ist die man so umsetzen kann, bzw. wie andere Wege wären das ganze mit maximaler Flexibilität zu implementieren. 

Kann man hier eigentlich irgendwie Bilder hochladen, dann könnte ich mal zeigen was die beiden Shader genau machen. Dann kann man sich das vielleicht noch besser vorstellen.

Danke und Grüße

Stefan

Share this post


Link to post
Share on other sites

Hmm, ok, wie setzt du denn die Z-Koordinate der UVs? Im Shader selbst wird diese ja scheinbar nur übergeben? Es wäre hilfreich zu wissen, wie die UVs deines Meshes sind den du zeichnen willst., davon könnte ja auch abhängen, wie du überblenden musst (und wie dein Mesh aussieht). Ich stelle mir aktuell vor, daß sich die "normalen" UVs einfach von 0..1 über die gesamte Face deines Modells aufspannen und du setzt jeweils die Z-Koordinate pro Quadrant? Ich frag mich halt immer noch, wie du die Z-Koordinate überhaupt setzt?

Ich vermute dein Mesh besteht dann aus Quadranten (= 2 Faces), wobei jeweils ein Quadrant ein Tile darstellt?

PS:
Bild hochladen würde ich mit imgur und dann den Link hier einstellen.

Share this post


Link to post
Share on other sites

Okay hier einmal zwei Bilder die zeigen wie das ganze aktuell aussieht.

Original (1. Shader):

r1JGhtim.png

Mit Alpha Map und Blending (2.Shader)

qsxzvUfm.png

Wie man sieht sind in dem 2 Bild die Übergänge zwischen den Typen schon schöner. Das verhalten würde ich gerne für alle 8 Nachbarn hinbekommen, das es überall gut aussieht. Natürlich sind die Texturen und die AlphaMap noch nicht wirklich gut.

Genau das was du geschrieben hast ist korrekt. Mein Mesh besteht aus lauter Dreiecken, wobei immer 2 Dreiecke ein Tile entsprechen. Diesem gebe ich dann immer die UVs von 0 -1 mit um die Gesamte Texture auf die Dreiecke zu rendern. Ursprünglich war mal jedes Tile ein GameObject, was ich aber in dem selben Zug geändert habe. 

Hier mal der Code wie ich aktuell das Mesh und die Texture Koordinaten erzeuge. Ist leider nicht so richtig gut kommentiert, da ich aktuell am testen bin wie ich das am besten lösen kann. Ich hoffe das man das trotzdem versteht. Sonst bei Fragen einfach Fragen. 

public class TileMesh : MonoBehaviour
{
    Mesh mesh;
    MeshCollider meshCollider;
    MeshRenderer meshRenderer;

    List<Vector3> vertices;
    List<int> triangles;

    Dictionary<ITileType, int> textureMap;
    Texture2DArray textureArray;
    List<Vector3> uv;
    List<Vector3> left;
  
    public void Triangulate(ITile[] tiles)
    {
        // Cleare old data
        mesh.Clear();
        vertices.Clear();
        triangles.Clear();
        uv.Clear();
        left.Clear();

        // Calculate new data
        for (int i = 0; i < tiles.Length; i++)
        {
            Triangulate(tiles[i]);
        }

        // Apply data to mesh.
        mesh.vertices = vertices.ToArray();
        mesh.triangles = triangles.ToArray();
        mesh.SetUVs(0, uv);
        mesh.SetUVs(1, left);
 
        mesh.RecalculateNormals();
        meshCollider.sharedMesh = mesh;
    }

    void Triangulate(ITile tile)
    {
        // Gets the center point and calculaate triangles.
        var tileCenter = new Vector3(tile.Position.X, tile.Position.Y);
        var tileTopLeft = tileCenter + new Vector3(-0.5f, 0.5f);
        var tileTopRigth = tileCenter + new Vector3(0.5f, 0.5f);
        var tileBottomLeft = tileCenter + new Vector3(-0.5f, -0.5f);
        var tileBottomRight = tileCenter + new Vector3(0.5f, -0.5f);

        AddTriangle(tileBottomLeft, tileTopLeft, tileTopRigth);
        AddTriangle(tileBottomLeft, tileTopRigth, tileBottomRight);

        // Get  terrain typ and calculate uvs for it.
        var terrainID = textureMap[tile.TileType];
        var terrainTopLeft = new Vector3(0, 1, terrainID);
        var terrainTopRight = new Vector3(1, 1, terrainID);
        var terrainBottomLeft = new Vector3(0, 0, terrainID);
        var terrainBottomRight = new Vector3(1, 0, terrainID);

        AddUV(terrainBottomLeft, terrainTopLeft, terrainTopRight);
        AddUV(terrainBottomLeft, terrainTopRight, terrainBottomRight);

        // Get  terrain typ of the left tile and calculate uvs for it.
        var leftTile = tile;
        if(tile.Position.X > 0)
            leftTile = WorldController.Instance.World.GetTileAt(tile.Position.Offset(-1, 0));

        terrainID = textureMap[leftTile.TileType];
        terrainTopLeft = new Vector3(0, 1, terrainID);
        terrainTopRight = new Vector3(1, 1, terrainID);
        terrainBottomLeft = new Vector3(0, 0, terrainID);
        terrainBottomRight = new Vector3(1, 0, terrainID);

        AddLeftUV(terrainBottomLeft, terrainTopLeft, terrainTopRight);
        AddLeftUV(terrainBottomLeft, terrainTopRight, terrainBottomRight);
    }

    void AddTriangle(Vector3 v1, Vector3 v2, Vector3 v3)
    {
        int vertexIndex = vertices.Count;
        vertices.Add(v1);
        vertices.Add(v2);
        vertices.Add(v3);
        triangles.Add(vertexIndex);
        triangles.Add(vertexIndex + 1);
        triangles.Add(vertexIndex + 2);
    }

    void AddUV(Vector3 v1, Vector3 v2, Vector3 v3)
    {
        uv.Add(v1);
        uv.Add(v2);
        uv.Add(v3);
    }

    void AddLeftUV(Vector3 v1, Vector3 v2, Vector3 v3)
    {
        left.Add(v1);
        left.Add(v2);
        left.Add(v3);
    }
}

 

Share this post


Link to post
Share on other sites

Ich vermute du kommst mit dem Überblenden so nicht weiter. Ich denke auch du musst das Überblenden auf den Vertex beziehen und nicht auf das Tile selbst.
Jetzt stellt sich die Frage, woher bekommst du die Information im Shader, welche Texturen die umgebenden Vertices verwenden. Eine mögliche Lösung wäre, daß du die Vertexcolors des Meshes verwendest. In deinem Skript könnten beispielsweise die Vertexcolors des Meshes so gesetzt werden:

vertex_xy:        nachbar + texturnummer 
linker Nachbar:   00 + 001 (Textur1) = Vertexcolor = 00001 = 1
rechter Nachbar:  01 + 010 (Textur2) = Vertexcolor = 01010 = 10
oberer Nachbar:   10 + 011 (Textur3) = Vertexcolor = 10011 = 19
unterer Nachbar:  11 + 100 (Textur4) = Vertexcolor = 11100 = 28

https://docs.unity3d.com/ScriptReference/Mesh-colors.html

Jetzt musst du dem Shader noch die Vertexcolor übergeben und dann über eine Bitoperation die jeweiligen Texturen der Nachbarn auslesen und dann überblenden.

struct VertexData {
  float4 position : POSITION;
  float3 uv : TEXCOORD0;
  fixed4 color : COLOR; //  is the per-vertex color, typically a float4
};

Wenn ich richtig liege, brauchst du so nur die MainTex, weil darin sind alle Texturen enthalten die du zum Überblenden brauchst. Die Überblendung selbst kannst du mit lerp() berechnen. Wird noch ein wenig Aufwand bis der Shadercode steht, aber sollte machbar sein.

// lerp between texture1 and texture2
fixed3 mixedColor = lerp(texture1.rgb, texture2.rgb, 0.5);

Kann sein, daß du die 0.5 noch über die aktuelle UV berechnen musst, um einen weichen Übergang zu erhalten, da du dich ja im Fragmentshader befindest, an dieser Stelle wird es leider kompliziert, da bin ich mir auch gerade unsicher.

Share this post


Link to post
Share on other sites

Ich bin mir nicht ganz sicher ob ich das richtig verstanden habe. Glaube eher nicht, weil ich bei mir die Nachbar Nummer nicht brauchen würde. Hier einmal skizziert wie ich mir das jetzt gerade vorstelle.

su5Cr2u.png

Also jedes Vertex (Eckpunkt eines Dreiecks) hat die folgenden Daten.

  • TextureArray mit allen Texturen.
  • BlendMask zum überblenden der Texturen.
  • UV Position der Texturen im Dreieck. 
  • Color Jeder Kanal als ID für die jeweilige Textur.

Mithilfe des "TextureArray" und der Farbinformation in "Color" können dann die einzelnen 4 Texturen im VertexShader bestimmt werden.
Mit "UV" kann die Position der Texture auf dem Vertex ermittelt werden. Z.B. Oben links => UV = 0 / 1
Damit können dann die 4 TexCoords berechnet werden. Diese ergibt sich immer aus "UV" und in der Koordinate Z die TextureID.
Diese 4 TexCoords werden an den Fragment Shader übergeben. Hier wird zusammen mit der BlendMask für jedes Pixel die Farbe bestimmt.

Ist das so richtig und umsetzbar? Oder habe ich etwas falsch verstanden?
Werde ich gleich mal versuchen so umzusetzen.

Share this post


Link to post
Share on other sites

Ich würde es so probieren:

// lerp between texture left and texture right
fixed3 mixedColorU = lerp(texture_left.rgb, texture_right.rgb, i.uv.x);
// lerp between texture top and bottom
fixed3 mixedColorV = lerp(texture_top.rgb, texture_bottom.rgb, i.uv.y);
fixed3 mixedColor = lerp(mixedColorU, mixedColorV, 0.5);


Bei deinem Pfeil hätte ich folgende Werte:
left: 2  (liegt auf dem Rand)
right: 1 
top: 1
bottom: 2 (liegt auf dem Rand)

Die Überblendung wäre so natürlich relativ breit. Man müsste halt schauen, wie das Ergebnis aussieht.
Ansonsten hängt es auch davon ab, mit welcher Logik die Nachbarn gesetzt werden, die sind ja nicht "eindeutig", aber sie sollten immer so gesetzt werden, daß Übergänge entstehen. Ich denke man bestimmt zuerst einen "Rand" und dieser Rand bestimmt die Werte der umgebenden Texturen. Bei deinem Beispiel wäre der Rand TID2. Dabei bekommen alle Vertices auf dem Rand die Textur innerhalb des Randes.

Wenn du ein kleines Exampleprojekt hochlädst, kann ich es mir mal anschauen, oben die Klasse ist ja nur ein Teil des Ganzen wenn ich das richtig sehe.

Share this post


Link to post
Share on other sites

Danke für die ganze Hilfe Zer0Cool. Ich habe jetzt mal eine Test Applikation geschrieben.
Da ich nicht weiß wo ich die hier hochladen kann habe ich die bei Bitbucket als GIT Repository hochgeladen.
Link: https://bitbucket.org/StefanDu/tilemap_example

Ich bin zwar selber auch noch am ausprobieren und habe auch schon alle Möglichen ungewollten Effekte geschafft aber nicht das was ich eigentlich wollte.
Das hier find ich z.B. ganz gut gelungen, obwohl hier eigentlich nur schwarz und dunkelblau drauf sein soll....

o2uovOBm.png

Warum dort die ganzen anderen Farben droben sind bin ich noch am rätseln. Aber wie es aussieht funktioniert das mit den Farben als Index nicht. 

Edit: Was ich noch sagen wollte ist, der Code in dem Repository ist stark vereinfacht was alles außen Rum angeht. ich habe hier nur die Teile hochgeladen die für das Problem relevant sind, falls noch etwas benötig werden sollte einfach schreiben.

Share this post


Link to post
Share on other sites

Habe das Projekt geladen und bin gerade dabei die Vertexcolors in den Shader einzubauen, erst wenn das klappt, kann man mal das Überblenden testen.

AddColor(Color.blue, Color.yellow, Color.white);
AddColor(Color.blue, Color.yellow, Color.white);


Ok, er zeigt sie zumindest schon einmal an:
xukRSNI.png

Share this post


Link to post
Share on other sites

Ich konnte die Vertexfarben nun nach unserem geplanten Algorithmus setzen. Die Texturindices werden dabei "einfach" in die RGBA-Farbkanäle gesetzt:

        // 0 = blue
        // 1 = green
        // 2 = red
        // r(left) / g(right) / b(top) / a(bottom)
        float colorScale = 0.1f;

        Color colorCodeV0 = new Color(textureMap[left.TileType] * colorScale, textureMap[tile.TileType] * colorScale, textureMap[tile.TileType] * colorScale, textureMap[bottom.TileType] * colorScale);
        Color colorCodeV1 = new Color(textureMap[left.TileType] * colorScale, textureMap[tile.TileType] * colorScale, textureMap[top.TileType] * colorScale, textureMap[tile.TileType] * colorScale);
        Color colorCodeV2 = new Color(textureMap[tile.TileType] * colorScale, textureMap[right.TileType] * colorScale, textureMap[top.TileType] * colorScale, textureMap[tile.TileType] * colorScale);
        Color colorCodeV3 = colorCodeV0;
        Color colorCodeV4 = colorCodeV2;
        Color colorCodeV5 = new Color(textureMap[tile.TileType] * colorScale, textureMap[right.TileType] * colorScale, textureMap[tile.TileType] * colorScale, textureMap[bottom.TileType] * colorScale);

Die Vertexfarben sehen dann so aus:
OCUzgYM.png

Share this post


Link to post
Share on other sites

So. alles zusammengebaut, zumindest ein Teilerfolg, aber es gibt immer noch harte Übergänge, ich vermute hier sind die Vertexcolors noch nicht richtig gesetzt. Auch ist auch die Breite des Übergangs zu stark, daher wird aus dem rot ein lila:
h81tcDP.png

Share this post


Link to post
Share on other sites

Hier noch einmal das Kontrollbild (unverändert):
h2KkfZk.png

So nun bin ich mit meinem Latein auch am Ende, mehr bekomme ich mit dieser Lösung nicht zusammen.
Ich musste die Meshsegmente verdoppeln, damit ein Übergang zu sehen ist. Was ich auch nicht verstehe, warum der blaue Anteil ständig so dominant ist.
z83nItq.png


Ebenfalls scheint ein Überblenden zwischen Vertikal und Horizontal nicht wie gewollt zu funktionieren, schaltet man beides ein, dann sieht es so aus:
HzzPA8F.png

Wenn man sich das Ergebnis anschaut, wird dies allerdings verständlich, daß das Überblenden von Links nach Rechts beispielsweise immer von rot nach rot verläuft und dadurch wird die Farbe rot ins Tile gemixed, welches eigentlich gerade von blau nach rot überblendet und damit entsteht wieder ein harter Übergang.

So sieht es dann mit Texturen aus:
Kontrollbild:
4KXH4bM.png
7JoZCfX.png

Share this post


Link to post
Share on other sites

Ich habe die ganze Szenerie mal vergrößert. Und hier wird ein Problem deutlich, ich verstehe nicht, wo dieser "Sand-Zwischensteifen" herkommt, der unter dem grünen Streifen ist:

d7KSrsi.png

Share this post


Link to post
Share on other sites

Hab die Ursache gefunden, der Shader interpoliert die Vertexfarben und dadurch läuft die Bestimmung des Texturindex im Shader schief ...

So hier ein letztes Ergebnis, mehr kann ich aus dem Ganzen nicht mehr rausholen:
RfY3BgX.png

Ich befürchte viel mehr ist aus der Technik nicht mehr rauszuholen. Die Überblendung über die Vertices war zwar eine nette Idee, aber durch die Interpolation der Vertexfarben werden die Texturen nicht sauber getrennt. Vielleicht braucht man eine Routine, die die Texturen zusätzlich anhand der Vertexfarben mischt.

Share this post


Link to post
Share on other sites

Puh, ich habe es letztendlich doch hinbekommen, ich habe die Interpolation der Vertexfarben mit einbezogen und einen Texturmix damit berechnet:

0K7ORJm.jpg

Render mit den original Farbtexturen:
hlaqcZy.png

Das einzige was nun noch stört sind die "Kanten", aber ich befürchte, daß liegt an der aktuell verwendeten "Technik".
Zudem schaue ich mir jeweils nur die 4 umgebenden Tiles an und ermittle damit einen Texturmix, ich vermute wenn man 8 Seiten einbezieht wird der Mix "runder" und die Kanten vermischen sich besser.

So sehen die "Kanten" aus der Nähe aus:
lxKeJfW.png


PS:
Würde Unity diese Technik beim Terrainshader verwenden, dann würde es kaum noch ein sichtbares Tiling bei den Terraintexturen geben, aber ihr sehr ja selbst, nicht ganz so einfach das Ganze umzusetzen.

  • Like 1
  • Thanks 1

Share this post


Link to post
Share on other sites

Oha, das sieht ja so aus als hätte ich dich mit meinem Problem den ganzen Tag beschäftigt. Vielen Danke erst mal für die Unterstützung. Das Ergebniss ist ja auch schon beeindruckend. ich habe gestern auch ewig versucht das hinzubekommen,  bin aber immer schon daran gescheitert, das ich die Indizies nicht als Farbe übergeben bekommen habe.

Alleine damit, dass das ganze so umsetztbar ist hast du mir schon viel geholfen. Jetzt muss ich mich dann hinsetzen und das ganze auch noch soweit hinbekommen. :-)
Was ist den aktuell deine Einschätzung. Ist das Vorgehen so brauchbar oder ist das eher zu umständlich / kompliziert und ressourcenintensiv (aus Performancesicht)?

Gibt es deine aktuelle Version irgendwo zum runterladen? Zumindest den Shader, bzw. wie du aus der Farbe den Index gebildet hast?
Falls ich dich mal bei irgendetwas unterstützen kann, dann schreib einfach, wobei meine Kentnisse hier bei weitem nicht so gut sind wie deine.

Gruß Stefan

Share this post


Link to post
Share on other sites

So ganz zu 100% ist der Shader immer noch nicht korrekt. Man kann es sehen, wenn man nur in eine Richtung überblendet. Dabei entsteht beispielsweise eine Überblendung von oben nach unten und beim darüberliegenden Vertex entsteht die selbe Überblendung nochmal.
fY889ai.png

Wie man sehen kann, überblenden die Vertices 2x. Ich habe nun versucht dies zu beheben, leider verschlechterte dies wiederum die Überblendung. Ich habe in den Shader nun beide Varianten eingebaut, so daß man Testen kann.Ich lade dir die Version mal hoch... siehe EMail

Am Shader kann man nun Version 1 und Version 2 einstellen. In Version 2 kann man zusätzlich noch einmal die Überblendung für Vertikal und Horizontal getrennt nachregeln.

Also die allgemeine Einschätzung:
Die Ressourcen sind minimal und der Performanceimpact ist minimal.
Das Hauptproblem habe ich oben beschrieben, bei einer kompletten Überblendung (Version 1) wird über 2 Zeilen überblendet. Über den Versuch dies zu beheben verschwindet zwar die doppelte Zeile, aber die Überblendung wird schwächer (verschlechtert).

PS:
Ich habe die Größe des Grids vervierfacht, ist ein Aufruf in der World class.

Share this post


Link to post
Share on other sites

Nach einiger Überlegung, ich denke das Problem liegt nicht am Shader, sondern am Setzen der Ränder (Version 1 des Shaders wäre somit richtig).
Dafür müssen die Übergange allerdings von der Breite und von der Höhe her aus mehreren Tiles bestehen! Daher hatte ich auch das Grid vergrößert.

Nun müsste man an der Stelle wo wir die Vertexfarben setzen die Ränder beachten. Am Rand müssten jeweils die Farben auf den gleichen Wert gesetzt werden:

        Color colorCodeV0 = new Color(textureMap[left.TileType] * colorScale, textureMap[tile.TileType] * colorScale, textureMap[tile.TileType] * colorScale, textureMap[bottom.TileType] * colorScale);
        Color colorCodeV1 = new Color(textureMap[left.TileType] * colorScale, textureMap[tile.TileType] * colorScale, textureMap[top.TileType] * colorScale, textureMap[tile.TileType] * colorScale);
        Color colorCodeV2 = new Color(textureMap[tile.TileType] * colorScale, textureMap[right.TileType] * colorScale, textureMap[top.TileType] * colorScale, textureMap[tile.TileType] * colorScale);
        Color colorCodeV3 = colorCodeV0;
        Color colorCodeV4 = colorCodeV2;
        Color colorCodeV5 = new Color(textureMap[tile.TileType] * colorScale, textureMap[right.TileType] * colorScale, textureMap[tile.TileType] * colorScale, textureMap[bottom.TileType] * colorScale);

Der horizontale Rand besteht dabei aus:
V1 & V2/V4
und
V0/V3 & V5

Der vertikale Rand besteht dabei aus:
V0/V3 & V1
und
V2/V4 & V5

Soll ein Rand definiert werden, dann müssen diese Ränder den gleichen Farbcode bekommen.
Da wird momentan Tiles mit nur einer Vertexkantenlänge haben, können wir keine Ränder definieren.
Weil aktuell der Anfang und das Ende einer "Kante" zusammenfallen, bekommen wir quasi 2 Ränder und keinen sauberen Übergang.

Share this post


Link to post
Share on other sites

Okay, dann sage ich nochmal vielen Dank. :-)
Ich habe leider gerade kein Unity dabei, kann daher erst am Freitag mit deinem Beispiel spielen. Du bist mir aber mit deinen Beiträgen zu schnell XD, da komm ich ja gar nicht mehr mit.
Habe mir aber jetzt den Code schon mal angeschaut. Hab das ganze aber noch nicht so wirklich verstanden. Ich glaube auch nur anhand des Codes komme ich da auch nicht wirklich dahinter. Ich muss das ganze dann mal sehen und an paar Werten drehen. Bin aber auch erst ganz am Anfang mit den ganzen Shader Sachen.

Wo kommen den in dem Shader die Variablen (_border1, border2, ...) her? Müssten die nicht als Property definiert sein?
Mit der Farbe sehe ich das du das genauso wie ich versuchst und den Wert auf 0 ... 1 normierst. Ich habe durch 100 geteilt und du multplizierst mit 0,1. Wie aber dann die Farbe im Shader wieder zu einer Texture ID umgewandelt wird finde ich nicht. Oder soll das immer dieser Teil sein und mit _border wird bestimmt im welchem Bereich die Texture ID = 0,1,2 oder 3 ist?

uvTop.z = 3;
if (i.color.b <= 0.2) uvTop.z = 2;
if (i.color.b > _border1 && i.color.b < _border2) uvTop.z = 1;
if (i.color.b < _border3) uvTop.z = 0;

Wie gesagt im Detail kann ich mir das leider erst am Wochenende anschauen.

Gruß Stefan

Share this post


Link to post
Share on other sites

Ich habe das ganze System noch einmal auf den Kopf gestellt, da die Technik wegen der Interpolation der Vertexfarben (im Fragmentshader) so überhaupt nicht funktionierte, da über die Interpolation ebenfalls andere Texturen in den Übergang hinein interpoliert wurden.
Als Beispiel:
- Farbe 0.2 für Textur 2
- Farbe 0,1 für Textur 1 und
- Farbe 0.0 für Textur 0
Wenn nun von Textur 2 nach Textur 0 überblendet werden sollte, dann wurde über den den Shader die Textur 1 mit hinein interpoliert, obwohl der Übergang eigentlich nur zwischen den Texturen 2 und 0 stattfinden sollte...

Ich habe das Projekt und den Shader nun so umgestellt, daß alle Vertexfarben eines Tiles auf die gleiche Farbe gesetzt werden, damit wird im Fragmentshader nur zwischen 2 gleichen Werten interpoliert (was egal ist). Ein Tile hält dabei die aktuelle Farbe und ein angrenzendes Teil definiert quasi den Übergang.

Die Programmlogik der C#-Klasse und der Shader ist einfacher als vorher.

Ein Tile muss mindestens 8 Faces (2x2) haben, damit ein Übergang gezeichnet werden kann. 

Ein Problem bleibt immer noch bestehen, der Übergang zwischen Horizontal und Vertical.

Hier ist das Ergebnis:

Variante 1) Hier werden die vertikalen und horizontalen Texturen einfach zusammengemischt: lerp(mixedColorU, mixedColorV, 0.5);

0ERQE8d.png

 

Variante 2: "Dependent Mix" (je nachdem ob Vertikal oder Horizontal überhaupt Texturänderungen vorhanden sind)

YxUh5pc.png

Beide Varianten haben immer ein Problem mit Kanten, da beim Überblenden nur in 4 Richtungen geschaut wird. Ich vermute, wenn man in alle 8 Richtungen schauen würde, dann könnte man diese Kanten zumindest abschwächen. Allerdings haben wir für die 4 Richtungen bereits die 4 Farbkanäle der Vertexfarben verbraucht. Man müsste die 8 Richtungen nun in diese 4 Farbkanäle verpacken.

Aber ich sehe dieses Ergebnis zumindest als Teilerfolg, da nun zumindest die Texturen extrem sauber überblendet werden.

 

Share this post


Link to post
Share on other sites

So letztes Ergebnis, ich glaube die Grenzen dieser Technik sind erreicht. Ich habe noch einmal die Kanten verbessert über die Zuweisungen der Vertexfarben der Tiles, aber wie man sieht macht sich die Überblendung der Faces als "Muster" bemerkbar. Der "diagonale" Übergang wird nun aber beachtet. Ich denke man sollte auch noch einmal nach einer Lösung forschen, die die Überblendung über die UVs der Texturen realisiert. Ich dachte das Überblenden über die Kanten der Faces wäre ein idealer Weg, aber bei zu vielen verschiedenen Nachbarn wird die Überblendung etwas "kantig", da eben entlang der Facevertices überblendet wird.

Np5xlqP.png

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this  

×