Eine offene Welt im Browser bauen, Teil 28: Gras bis zum Horizont und ein Boden, der sich selbst verbirgt
Von Oleg Sidorkin, CTO und Mitgründer von Cinevva
Neu hier? Nutze den Serienleitfaden. Er erklärt, was ein Spike ist, und verlinkt alle Teile.
Teil 27 baute die Insel und gab ihr einen Boden, der nicht gekachelt aussieht. In diesem Teil geht es um die beiden Dinge, durch die sich Terrain bewohnt statt leer anfühlt. Spike 56 behandelt Gras – das Oberflächendetail, das einen texturierten Hang in einen Ort verwandelt, durch den man laufen möchte – und die Herausforderung, ein Feld wie ein Feld statt wie verstreute Streifen wirken zu lassen. Spike 57 befasst sich mit dem Gegenteil von mehr Zeichnen: Es geht darum, nicht zu zeichnen, was ein Hügel ohnehin bereits verdeckt. Das interessante Ergebnis ist, dass sich die schnelle Prüfmethode zugleich als die korrekte erwies.
Gras, das wie ein Feld wirkt, nicht wie Konfetti
Spike 56 in einem neuen Tab öffnen ↗ · Quellcode ansehen
Die grundlegende Entscheidung betrifft die Geometrie. Ein einzelner dünner, sich verjüngender Grashalm ist aus den meisten Kamerawinkeln kleiner als ein Pixel, sodass eine halbe Million flacher Halme eher wie verstreutes grünes Konfetti als wie ein Feld wirkt. Die Lösung ist ein Cross-Quad-Büschel: drei sich verjüngende Quads, die um jeweils sechzig Grad versetzt um die lokale Hochachse gedreht sind. Dadurch steht aus jeder Blickrichtung mindestens ein Quad annähernd senkrecht zur Kamera, und jede Instanz deckt auf dem Bildschirm ungefähr die tatsächliche Fläche von drei Halmstärken ab. Das ist der Unterschied zwischen grünen Streifen und erkennbarem Gras.
Ein WebGPU-Compute-Kernel platziert beim Initialisieren jedes Büschel genau einmal. Er hasht den Instanzindex in fünf dekorrelierte Zufallsströme, wählt eine XZ-Position innerhalb des Bereichs, liest die Bodenhöhe aus demselben FBM aus, das auch das CPU-Bodennetz verwendet – eine TSL-Portierung mit vorzeichenerhaltendem Modulo, damit die Werte exakt übereinstimmen und die Halme auf der Oberfläche stehen, statt darüber zu schweben –, berechnet eine Normale über zentrale Differenzen und bestimmt Breite, Höhe und Farbton jedes Büschels. Auf der Renderseite umgeht ein TSL-Vertexgraph die Instanzmatrix vollständig und schreibt direkt in den Clip-Space: Er skaliert das Cross-Quad in Einheitsgröße, dreht die lokale Hochachse mit der Rodrigues-Formel auf die Bodennormale und verschiebt es an die Position des Büschels. Entfernungsabhängiges LOD gibt es ohne zusätzlichen Culling-Durchlauf, weil der Vertexgraph die Höhe des Büschels mit
Das Farbrezept stammt aus dem Breath-of-the-Wild-URP-Shader von NedMakesGames: Flat Shading, bei dem die Halmfarbe entlang des Höhenanteils von einem Wurzelton zu einem Spitzenton interpoliert wird. Wurzel- und Spitzenton werden ihrerseits anhand des Farbtonwerts jedes Büschels zwischen zwei Paletten interpoliert. So entsteht der gesprenkelte Zweifarb-Look eines echten BotW-Grasfelds. Für die diffuse Beleuchtung wird die Bodennormale gegen die Sonne mit einem Mindestwert für das Umgebungslicht verwendet, da die einzelnen Quad-Normalen des Cross-Quads für einen stilisierten Look zu unruhig wären, wenn sie separat schattiert würden. Das gesamte Feld wird mit einem einzigen Draw Call gezeichnet und vollständig auf der GPU platziert und animiert.
Vier Methoden, um auszublenden, was ein Hügel verbirgt
Spike 57 in einem neuen Tab öffnen ↗ · Quellcode ansehen
Spike 57 vergleicht vier Culling-Pfade über derselben prozeduralen Welt, die der Produktionsclient streamt. Sie ist vertikal um den Faktor 1,8 skaliert, damit Hügel Vegetation tatsächlich verdecken. T0 berücksichtigt nur die Entfernung und entspricht damit der bereits im ausgelieferten Client verwendeten Chunk-Sichtbarkeitsprüfung. T1 ergänzt Frustum Culling – die mit Abstand größte günstige Optimierung –, das alles außerhalb des Sichtkegels entfernt. T2 fügt einen terrainabhängigen Horizonttest hinzu: Von der Kameraposition zu jeder Instanz wird ein Strahl abgetastet. Die Instanz wird verworfen, wenn die Heightmap irgendwo entlang des Wegs über den Strahl steigt. So wird ein Baum hinter einem Bergrücken ausgeblendet, obwohl er sich innerhalb des Frustums befindet. T3 behält denselben Horizonttest bei, beschleunigt ihn aber mit einer Max-Height-Pyramide. T4 portiert den gesamten Entfernungs-, Frustum- und Horizonttest in einen TSL-Compute-Kernel, der für jede Instanz einen Sichtbarkeitsskalierungswert schreibt. Das Vegetationsmaterial liest diesen Wert und lässt die Vertices verborgener Instanzen kollabieren. Ein zweiframeslanger Sichtbarkeitszähler glättet das kurzzeitige Flackern, das entsteht, wenn ein Abtastpunkt bei kleinen Kamerabewegungen knapp innerhalb oder außerhalb eines Texels landet. Er bleibt absichtlich kurz, denn eine längere Dauer würde algorithmische Fehler kaschieren, statt sie zu beheben.
Die Pyramide ist der entscheidende Teil dieses Spikes, und die Lehre daraus lautet, den Test an das anzupassen, was tatsächlich auf dem Bildschirm dargestellt wird. Das gerenderte Terrain ist ein Dreiecksnetz mit Vertices auf einem festen Zwei-Meter-Raster. Zwischen den Vertices interpoliert der Rasterizer linear, daher entspricht die tatsächliche gerenderte Höhe innerhalb eines Rechtecks dem Maximum der darin enthaltenen Vertices – niemals einer Spitze des kontinuierlichen Rauschens zwischen ihnen. Wenn die Verdeckungspyramide das Rauschen auf einem feineren Raster abtastet, findet sie Phantomspitzen, die das Mesh nie darstellt, und blockiert Strahlen, durch deren Verlauf die Kamera offensichtlich sehen kann. Deshalb liegen die Basis-Texel der Pyramide exakt auf dem Vertexraster, wobei jedes das Maximum seiner vier Eck-Vertices speichert. Die höheren Ebenen entstehen durch klassische 2x2-Maximumsreduktionen, wodurch die Pyramide in Bezug auf das gerenderte Mesh exakt ist. Beim schrittweisen Strahltest tastet der Code das Mesh bewusst punktweise mit bilinearer Interpolation ab, statt die Pyramide abzufragen. Eine AABB-Abfrage unterhalb der Texelgröße liefert nämlich das Maximum des gesamten Texels und erhöht die angenommene Höhe an steilen Bergrücken um mehrere Meter. Genau diese Überverdeckung würde sichtbare Requisiten verbergen.
Das überraschende Ergebnis ist, dass T2, die Brute-Force-Referenz, falsch liegt. Da T2 das kontinuierliche Rauschen direkt punktweise abtastet, erfasst es Spitzen zwischen den Mesh-Vertices, die gar nicht gerendert werden. Dadurch verdeckt es geringfügig zu viel und blendet Vegetation aus, die der Spieler tatsächlich sehen kann. Der Pyramidenpfad ist sowohl schneller – dank der
In diesem Kapitel erwähnte Technologie
Cross-Quad-Gras auf der GPU. Drei sich verjüngende Quads, die pro Büschel um jeweils sechzig Grad versetzt sind, garantieren aus jedem Winkel ein annähernd senkrecht zur Kamera stehendes Quad. Dadurch wirken eine halbe Million Instanzen wie ein Feld statt wie Subpixel-Konfetti. Ein Compute-Kernel platziert jedes Büschel – FBM-Bodenhöhe, abgetastet mit demselben vorzeichenerhaltenden Modulo wie beim CPU-Mesh, Normale aus zentralen Differenzen sowie individuelle Größe und Farbton je Büschel. Ein TSL-Vertexgraph umgeht die Instanzmatrix, um zu skalieren, mit der Rodrigues-Formel auf die Normale zu drehen, zu verschieben und höhenabhängig begrenzten Wind anzuwenden. Entfernungsabhängiges LOD ist kostenlos: Büschel kollabieren durch
Terrain-Horizont-Occlusion-Culling. Vier verglichene Pfade über der Produktionswelt: Entfernung, zusätzlich Frustum, zusätzlich ein Heightmap-Strahltest, der Instanzen hinter einem Bergrücken verwirft, zusätzlich eine beschleunigende Max-Height-Pyramide sowie eine Portierung in einen TSL-Compute-Kernel. Die Pyramide tastet exakt auf dem Zwei-Meter-Vertexraster ab, auf dem das Mesh tesselliert wird – Basis-Texel = Maximum der vier Eck-Vertices, darüber schrittweise 2x2-Maximumsreduktionen. Dadurch liefert sie ausschließlich Höhen, die der Rasterizer tatsächlich darstellt.
Beschleunigt und korrekt, kein Kompromiss. Das punktweise Abtasten kontinuierlichen Rauschens – der Brute-Force-Pfad T2 – findet Spitzen zwischen Mesh-Vertices, die nie gerendert werden, und verdeckt dadurch sichtbare Vegetation übermäßig. Die Vertexraster-Pyramide ist sowohl schneller –
Teil 28 von 29. Zurück: Teil 27 – Eine Insel aus Rauschen und Boden, der wie Boden aussieht Weiter: Teil 29 – Ein Controller für jeden Körper Serienleitfaden: /de/blog/2026-02-25-open-world-browser-series-guide