Ich habe ein generiertes Gelände mit sechseckiger Geometrie, wie im folgenden Screenshot gezeigt:
Ich generiere dann Biome, aber wie Sie sehen können, sind die Grenzen zwischen ihnen wirklich hässlich und gerade. Um diesen hexagonalen Ursprung zu verbergen, müsste ich die Grenzen zwischen den Biomen glätten. So sieht es jetzt im Drahtmodell mit echten dreisprachigen Flächen aus:
Was ich anstrebe, ist eher so etwas:
Jeder Scheitelpunkt hat ein Attibut, das den Biomtyp enthält. Ich kann den Scheitelpunkten am Rand zwischen zwei Biomes auch spezielle Attribute hinzufügen, aber ich scheine einfach nicht in der Lage zu sein, dies im Shader-Code zu erreichen, offensichtlich Rauschen ist hier beteiligt, aber wie mache ich es kontinuierlich über mehrere Gesichter und die gesamte Grenze mehrerer Biome?
Ich rendere mit WebGL mit THREE.js
Antworten:
Andere Antworten hier schlagen vor, eine Textur zu verwenden. Hier ist eine Technik, bei der keine Texturen verwendet werden.
Sie möchten, dass die Grenzen zwischen Sechsecken interessant sind. Es ist einfacher, interessante Grenzen zu setzen, wenn Sie sie in die Mitte des Zeichens verschieben. Anstatt die Kacheln direkt zu zeichnen, zeichnen Sie das „Dual“ der Kachel. Diese Technik wird als "Eckplättchen" bezeichnet ( hier und hier und hier ). Das Dual eines Sechsecks ist ein Dreieck, also würden wir diese Dreiecke anstelle der Sechsecke zeichnen:
Die Grenzen zwischen den Sechsecken befinden sich jetzt in der Mitte der gerenderten Dreiecke, sodass wir interessantere Dinge mit ihnen machen können. Bonus: Sie müssen nur zwei Dreiecke pro Sechseck zeichnen , anstatt sechs (oder vierundzwanzig, wie Sie es jetzt tun).
In jedem dieser Dreiecke soll der Fragment-Shader die Sechsecke zeichnen. Wir können das mit Schwerpunktkoordinaten tun . Setzen Sie (1,0,0), (0,1,0) und (0,0,1) an jeden Scheitelpunkt des Dreiecks. Innerhalb des Dreiecks werden diese Koordinaten interpoliert. Der Fragment-Shader empfängt (a, b, c) und kann sehen, welcher Wert am größten ist - das sagt uns, welches der drei Sechsecke an dieser Stelle gezeichnet werden soll.
float max_n = max(barycentric.r, max(barycentric.g, barycentric.b)); if (max_n == barycentric.r) { color = v_color0; } else if (max_n == barycentric.g) { color = v_color1; } else if (max_n == barycentric.b) { color = v_color2; }
Das ist für gerade Linien.
Wenn Sie verrauschte Kanten wünschen, können Sie den Schwerpunktkoordinaten Rauschen hinzufügen:
Wenn Sie mit der Amplitude Wellenlänge / Frequenz des Rauschens spielen, können Sie einige coole Effekte erzielen:
Sie müssen mit dem Rauschen vorsichtig sein und sicherstellen, dass es über Dreiecksgrenzen hinweg konsistent ist. Eine Möglichkeit, dies zu tun, besteht darin, eine Hex-ID einzugeben und diese als Startwert für jeden der drei Rauschwerte zu verwenden, die zu den Schwerpunktkoordinaten hinzugefügt werden.
Ich machte eine interaktive Demo hier . (Für die Demo habe ich weder die Hex-ID noch einige andere Dinge implementiert, die Sie möglicherweise benötigen, wenn Sie diese Arbeit in einem echten Projekt ausführen möchten - es ist nur eine schnelle und schmutzige Demo.)
quelle
Ich bin sicher, dass "mit einem Bildalgorithmus" gelöst werden könnte, aber wenn ich es wäre, würde ich es wahrscheinlich mit Texturen lösen. Ich würde sechseckige Texturen erstellen, sie alle in einen Texturatlas einfügen, dann für jedes Sechseck die Nachbarn betrachten und entscheiden, welche Textur angewendet werden soll.
Die Texturen müssten Versionen für jeden Geländetyp sowie Versionen für jeden Übergangstyp enthalten.
Dies ähnelt der Anzahl der kachelbasierten Systeme im Gelände. Hier ist ein Beispiel aus 2D-Spielen .
Eine andere Möglichkeit wäre, einfach Ihre Texturen für Ihre verschiedenen Geländearten (Wasser, Schnee, Schmutz, Gras) zu haben und jedem Scheitelpunkt des Sechsecks Mischmengen hinzuzufügen, um zu entscheiden, wie sie gemischt werden sollen.
Dieser Artikel zeigt die Idee, Geländetexturen zu mischen. Ich schlage nicht vor, ihrer Implementierung zu folgen, aber es zeigt die Idee.
quelle
Rendern Sie zuerst Ihre Biome zu einer Textur. Ordnen Sie die Dreiecke Texcoords zu. Sie können dies mit einer Mercator-Projektion oder besser mit einer Würfelkarte tun . Führen Sie nun im Fragment-Shader Folgendes aus:
Wo
noise
ist eine Pseudozufallsfunktion (unter Verwendung von beispielsweise Sinuskurven) an der 3D-Position des Scheitelpunkts im Modellraum, die einen verrauschten Versatz zur Texturkoordinate zurückgibt. Probieren Sie die Textur mitGL_NEAREST
, um scharfe Ränder zu erhalten.quelle