Ich wollte sehen, ob ich das schaffen kann, ohne das Netz für den Wasserfall in jedem Frame dynamisch zu regenerieren. Es stellt sich heraus, dass es einen Weg gibt. : D.
Jedes Objekt, das den Wasserfall blockieren kann (Objekte mit einem WaterCatcher
Skript in meinem Prototyp), hat ein Umrissnetz, das sich um seinen Umfang wickelt. (Dies kann im Voraus automatisch anhand der Form des Colliders generiert werden.)
Durch dieses Umrissnetz fließt das Wasser entlang des Objekts. Ich benutze einen Shader, clip
um den Teil herauszuholen, der sich unter dem Objekt befindet. Ich verfolge auch einen linken und rechten "Fangpunkt", an dem ein Wasserfall auf dem Objekt landet und nach links bzw. rechts fließt, sodass ich clip
den Teil links vom rechten Wasserfall und rechts vom linken Wasserfall herauslesen kann.
Dann sind die vertikalen Stürze nur einfache Quad-Primitive, die auf die entsprechende Länge gedehnt sind. Ich benutze einen anderen Shader, um die Wasserfalltextur über die Wasserfälle zu scrollen und sie am oberen und unteren Ende auszublenden. Dann schichte ich am Aufprallpunkt ein Schaumpartikelsystem auf, um die Mischung zu bedecken.
Hier ist eine Nahaufnahme, damit Sie die Komponenten sehen können.
Oben habe ich einen "Wurzel" -Wasserfall, um die Dinge anzukurbeln. Jedes Bild, nachdem alle Update()
Skripte ausgeführt wurden, um Dinge zu bewegen CircleCast
, wird nach unten ausgelöst, um zu sehen, ob das Wasser auf etwas trifft. Wenn es auf a trifft WaterCatcher
, weist es es an, seine Wasserhaut stromabwärts des Trefferpunkts zu zeigen.
Ich bestimme "stromabwärts" mit der Treffer-Normalität - wenn es sehr nahe an der Vertikalen liegt oder wenn der ankommende Wasserfall Kanten überspannt, die in beide Richtungen geneigt sind, dann verschütten wir sowohl links als auch rechts.
Jeder WaterCatcher
hat einen eigenen linken und einen rechten Wasserfall, den er aktiviert und am anderen Rand positioniert, wenn er in diese Richtung verschüttet wird - andernfalls bleiben sie verborgen. Diese Wasserfälle wiederum feuern CircleCast
nach unten, um herauszufinden, worauf sie verschüttet werden, und so weiter ...
Der Prototyp weist noch einige visuelle Störungen auf, die verbessert werden könnten - der Wasserfluss entlang eines Objekts wird auf einmal angezeigt, anstatt zu animieren, und die Flussregeln könnten eine zusätzliche Toleranz oder Hysterese verwenden, sodass er nicht so leicht abschneidet rotierende Objekte. Ich denke, dies sollten jedoch ziemlich lösbare Probleme sein.
Hintergrund, Felsen und rotierende Plattformtexturen über Kenney
Hier sind die Tricks, die ich in meinem Water Catcher Fragment Shader verwende:
// My wraparound geometry is build so the "x+" UV direction
// points "outward" from the object.
// Using derivatives, I can turn this into a vector in screen space.
// We'll use this below to clip out water hanging off the bottom.
float2 outward = float2(ddx(i.uv.x), ddy(i.uv.x));
// i.worldX is the worldspace x position of this fragment
// (interpolated from the vertex shader)
// _LeftX is a material property representing the worldspace x coordinate
// of the rightmost water flow that's spilling left,
// and _RightX the wold x of the leftmost water flow that's spilling right.
float left = _LeftX - i.worldX; // +ve if we're to the left of a left spill.
float right = i.worldX - _RightX; // +ve if we're to the right of a right spill.
float limit = max(left, right); // +ve if we're in the path of either flow.
// If the "outward" vector is pointing down, make this negative.
limit = min(limit, outward.y + 0.001f);
// If any of the conditions above make limit <= 0, abort this fragment.
clip(limit);
// Otherwise, scroll the water texture!
// Counter-clockwise if we're in the left flow, clockwise otherwise.
i.uv.y -= sign(left) * _Time.y;