Jump to content
Unity Insider Forum

Blood (shader) system


Zer0Cool

Recommended Posts

Hallo zusammen,

ich wollte euch heute einmal ein System vorstellen, an dem ich zur Zeit arbeite. Ich suche schon seit langem nach einer Möglichkeit "Blut" in Unity realistisch darzustellen. Dafür gibt es aktuell mehrere Möglichkeiten wie beispielsweise Partikeleffekte und Decals. Was aber meiner Meinung noch fehlt, ist ein Bloodshader der Blut auf einer Oberfläche realistisch darstellt und den Blutfluss entsprechend den Gravitationsverhältnissen berechnet.

Daher war mein erster Schritt einen solchen Shader zu entwickeln. Ich habe mir dabei ein Shader von NVidea als Vorbild genommen, der
eine entsprechende Umsetzung gezeigt hat. Nach ersten Schritten dachte ich noch, keine Chance ich bekomme diesen Shader niemals
nach Unity portiert, aber ich habe mich durchgebissen.

Kurz zu der Technik des Shaders. Er erstellt für jedes Objekt (Mesh) anhand der Normalentextur und einer vorgegebenen Gravitation
eine Gravitationsmap die jedes Frame neu berechnet wird. Anhand der Gravitationsmap wird letztendlich die Bluttextur berechnet und auf der Oberfläche dargestellt.

Aktuell habe ich den Shadercode in den Unity-Standardshader übernommen, so daß das Blut nun als PBS-Blood-Shader dargestellt wird (quasi eine Mixtur des Bloodshaderscodes auf Grundlage des Unity-Standardshaders) mit einer berechneten Bumpmap, einem Regler für die Oberflächenbeschaffenheit und die Glanzfarbe.
Die weiteren Schritte sind nun mein System weiter zu verfeinern. Da für die Darstellung des Blutes ja eine Gravitymap erstellt wird, muss jeder Mesh der das Blut darstellen soll zusätzlich gerendert werden. Hier habe ich eine Möglichkeit gefunden den Mesh ohne eine zusätzliche Kamera zu rendern, aber ich muss dieses System nun noch vereinfachen, so daß man quasi nur noch ein Skript an den betreffenden Mesh hängen muss. Das System muss zudem Skinnedmeshes und normale Meshes bei der Verarbeitung unterscheiden. Weitere zu programmierende Ergänzungen sind nun noch die Position der Textur über ein "Treffersystem" einzustellen. Der finale Schritt wäre dann einen Spieler mit mehreren Meshes darzustellen. Aktuell bin ich noch am Testen mit einzelnen Skinnedmeshes oder normalen Meshes.

Hier mal ein Bild des aktuellen Shaders auf einem texturierten Frauenkörper (ist der Skinndedmesh unserer "Spielheldin" ohne ihre Ausrüstung):uSUUdrq.png

Und hier noch ein Video, wie der Shader auf einem Ausrüstungteil arbeitet (einfach anklicken ist ein Stream):
https://streamable.com/w85ej

Link zu diesem Kommentar
Auf anderen Seiten teilen

Danke für das Feedback ;)
Die "Grundzüge" sind relativ einfach zu lernen und auch einen einfachen Shader hat man schnell "zusammenkopiert". Man kann mittlerweile ja sogar Shadercode über diverse Editortools erzeugen, was Sinn macht, wenn man beispielsweise Texturen innerhalb eines Shaders miteinander logisch verknüpfen möchte. Leider wird das Ganze komplex, wenn man nun bestimmte Sachen umsetzen möchte, die nicht den Standardsachen entsprechen. Man jongliert viel mit Transformationen zwischen Worldspace / Objectspace und Tangentspace und verwendet dabei zumeist Matrizenmultiplikationen oder Vektorenrechnung. Leider ist Shadercode nur sehr schwer zu debuggen, was ein Auffinden von Fehlern im Code recht schwer macht (es gibt zwar Möglichkeiten, aber da braucht es wieder spezielle Tools)

Link zu diesem Kommentar
Auf anderen Seiten teilen

  • 2 weeks later...

Ich konnte die Qualität des Shaders noch einmal verbessern und einige Fehler im Code beheben. Zudem sind weitere Einstellungsmöglichkeiten hinzugekommen. Hier der aktuelle Shader auf einem Meshrenderer einer Sphere:
https://streamable.com/2e1bm

Hier die gleiche Szene mit "halber Schwerkraft". Hier kann man schön die entstehenden Wellenberge erkennen:
https://streamable.com/q9rc0

FwkDjY0.jpg

 

Link zu diesem Kommentar
Auf anderen Seiten teilen

  • 2 weeks later...

Sollte relativ performant sein. Jeder Mesh - der das Blut darstellen soll - muss 1x zusätzlich gerendert werden, allerdings mit einem sehr schnellem Shader (ca. wie ein Unlitshader). Dieser zusätzliche Renderschritt erfolgt ohne zusätzliche Kamera (oder sonstiges Hintergrundsetting) und wird "einfach" zwischen den Frames erzeugt. Dieser Shader erzeugt dann eine Rendertextur (hier kann auch die Auflösung gewählt werden), der dann von einem modifizierten Unity-Standardshader für die Darstellung verwendet wird. Zudem habe ich eine Methode eingebaut, so daß das System auch mit einem Simplecollider (Capsule oder Box) anstatt eines Meshcolliders für die Bestimmung der UVs (und somit der Platzierung des Blutpattern) bei einer Kollision arbeitet.
Mal schauen, wenn das System weiter fortgeschritten ist, dann kannst du dich ja mal als Betatester oder als Showcase zur Verfügung stellen ;)

Aktuell bin ich dabei das System noch weiter auszubauen, d.h. ich möchte zusätzlich Blutpartikel über "Metaballs" (Dank an "Mr. 3d" für den Tipp) darstellen, was einer 3D-Darstellung von prozeduralem Blut entspricht. Der Spieler soll dabei in der Lage sein durch die generierten Blutpartikel laufen zu können und dabei das generierte Blut von allen Seiten zu betrachten.
 

Link zu diesem Kommentar
Auf anderen Seiten teilen

  • 2 weeks later...

Hier mal ein Video eines Versuches der Visualisierung von Metaballs (Blobs). Leider musste ich feststellen, daß die Performance der Visualisierung von Metaballs fast exponentiell mit der Menge an Metaballs abnimmt und selbst mit einigen Optimierungstricks (GPU Calculations, Shader im Screenspace ohne Meshdaten) die Performance nicht wesentlich besser wird. Für einen entsprechenden Blutpartikeleffekt - der mir vorschwebt - würde ich vermutlich mindestens 50 Blobs benötigen oder mehr. Auch eine punktuelle Vorberechnung des "Scalarfeldes" innerhalb eines 3D-Grids beansprucht bereits so viel CPU-Zeit, daß es für eine Verwendung in einem Spiel nicht mehr geeignet ist. Wenn man nur 10000 Punkte (10*10 Meter * 100 Auflösung pro Gridcube) innerhalb eines 3D-Raumes "vorberechnet", um ca. 50 Blobs darzustellen (für eine spätere Trilinear-Interpolation innerhalb des Shaders) droppt die FPS bereits auf unter 20 und der Shader der dann das Scalarfeld noch darstellen muss, ist noch gar nicht mit einberechnet (oder eben bei einer anderen Methodik die Erstellung eines Meshes).
Ich habe auch andere im Netz bereits vorhandene Lösungen gesichtet und diese stellen jeweils höchstens 5-10 Blobs dar und das dann auch nur in einem begrenzten 3D-Raum zwischen 1x1 bis 3x3 Meter. Erhöht man hier die Anzahl der Blobs oder erweitert den 3D-Raum entspechend, sinkt die Performance dieser Methoden noch unter der hier gezeigten Variante (25-30 Blobs mit ca. 50-60 FPS).

Video: https://streamable.com/h6h9i

bONPBxn.jpg

Link zu diesem Kommentar
Auf anderen Seiten teilen

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Gast
Auf dieses Thema antworten...

×   Du hast formatierten Text eingefügt.   Formatierung jetzt entfernen

  Only 75 emoji are allowed.

×   Dein Link wurde automatisch eingebettet.   Einbetten rückgängig machen und als Link darstellen

×   Dein vorheriger Inhalt wurde wiederhergestellt.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Lädt...
×
×
  • Neu erstellen...