So erstellen Sie einen 2D-Physikwasserfall

8

Ich versuche, einen Wasserfall mit physikalischen Eigenschaften zu erstellen, der dem ersten Bild unten ähnelt (siehe dieses Video, um eine bessere Vorstellung davon zu erhalten, was ich erreichen möchte), damit er sich auf seinem Kurs um Objekte mit Kollidern bewegen kann (ähnlich wie beim zweites Bild unten). Obwohl der verknüpfte Wasserfall 3d ist, bin ich an einer 2d-Implementierung interessiert.

Beachten Sie, dass die Objekte dynamisch sind und sich einige häufig bewegen, sodass der Wasserfall jedes Bild neu formen muss. Die Objekte bewegen sich langsam, entweder in verschiedene Positionen oder drehen sich. Wie kann das gemacht werden?

Geben Sie hier die Bildbeschreibung ein

Geben Sie hier die Bildbeschreibung ein

OnlyCodeMatters
quelle

Antworten:

13

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.

Animation von Wasserfällen

Jedes Objekt, das den Wasserfall blockieren kann (Objekte mit einem WaterCatcherSkript 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, clipum 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 clipden Teil links vom rechten Wasserfall und rechts vom linken Wasserfall herauslesen kann.

Animation zeigt Wasserhautnetz

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.

Schließen Sie noch vom Wasserfall-Effekt

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 WaterCatcherhat 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 CircleCastnach 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;
DMGregory
quelle
Das ist toll. Haben Sie Pläne, den Code hier oder auf GitHub bereitzustellen, damit die Community zu Verbesserungen beitragen kann? Wenn nicht, ziehen Sie dies bitte in Betracht.
Eindämmung
Derzeit gibt es keine derartigen Pläne. Die obigen Bilder wurden mit einem schnellen und hackigen Proof of Concept erstellt, nicht mit einem eigenständigen Paket, das für diese Art der Verwendung geeignet wäre. Lassen Sie mich wissen, wenn Sie eine Hand benötigen, die etwas davon repliziert, und ich kann Sie durch das führen, was benötigt wird.
DMGregory
Ich konnte die Schaumpartikel herstellen, aber ich brauche Hilfe beim Erstellen des Wasser-Shaders und zweitens beim Abschneiden des Wasser-Shaders um die Formen (WaterCatcher).
Eindämmung
Ich habe einen Ausschnitt aus dem Shader-Code hinzugefügt, der zeigt, wie der Clipping-Shader funktioniert.
DMGregory
@ DMGregory WoooW !!! Entschuldigung, ich war schon eine Weile nicht mehr hier. Arbeitete an anderen Sachen. Ich gehe jetzt Ihre Lösung durch
OnlyCodeMatters
1
  1. Sie können das Wasserfallnetz bei Objektkollision so verformen, dass es dem erforderlichen Kollidermuster entspricht.

  2. Das einfachere und genauere, aber leistungsfähigere Partikelsystem verwendet ein Partikelsystem mit Kollidern und verwendet jedes Partikel als Wassertropfen. Aber das sieht ein bisschen seltsam aus, wenn Sie ein Standard-Sprite haben und wenn die Partikelanzahl klein und zu groß ist. Aber es ist leistungsintensiv, so dass Sie keine Molekülsimulation in Ihrem Spiel wollen.

Ich würde mit 1 gehen.

  • Aber Mesh Deformation CPU - es ist langsam, kann aber für Sie arbeiten.
  • Ich würde Shader verwenden, um dies zu erreichen - Beispiel für einen Water-Shader - Mesh hat Effekte wie Kollisionen mit anderen Meshes und ist viel schneller als Methoden zuvor. Ich denke, es ist möglich, ein Netz zu erstellen, um das Rendern in einer projizierten Form zu stoppen - das ist die Änderung, die Sie am normalen Wasser-Shader vornehmen müssten. Es ist kompliziert zu erreichen, wenn Sie nicht mit Shadern vertraut sind.

Keine einfache Lösung mit guter Leistung.

Ergebnis des Partikelsystems: (Um die Werte zu ändern, musste ich ca. 3-4s warten, es ist langsam) Kollisionsergebnis des Partikelsystems

Candid Moon _Max_
quelle
Eine Alternative zu Punkt 1, die jedoch etwas komplexer sein könnte, besteht darin, ein eigenes "Partikel" -System zu haben, das Punkte / Kugelkollider fallen lässt und sich an die Physik hält. Und dann "einfach" ein Netz basierend auf diesen Punkten erzeugen. ziemlich genau, wie Line Renderer funktioniert. Das einzige, was gelöst werden muss, ist, wie Sie Punkte teilen, um in zwei Richtungen zu gehen, wenn Sie einen Collider treffen, wie es in Ihrem Screenshot der Fall ist. Aber denke nicht, dass es schwer sein muss. ODER Sie können die Punkte einfach statisch platzieren und eine Linie zwischen ihnen ziehen. Du brauchst nur einen hübschen Shader.
Sidar
@ Sidar Ja, interessanter Ansatz. Eine der Methoden wäre auch, mehrere Trail-Renderer zu erstellen und diese relativ vom Split-Punkt zu verschieben. Und über eine Collider-Komponente nach Kollisionen suchen - aber das ist nur eine Problemumgehung.
Candid Moon _Max_
In jedem Fall müssen die Daten dynamisch oder statisch gebacken werden, wenn OP sie nicht manuell einrichten möchte. Ich frage mich, ob Sie ein normales Partikelsystem mit aktivierter Kollision verwenden und dann in der Nähe zwischen Punkten einen Quad-Streifen zeichnen könnten. Die Anzahl der Partikel muss dafür nicht hoch sein.
Sidar
Ist das nicht pro Teilchen? Ich denke, je nach Stil könnte das ziemlich gut funktionieren.
Sidar