Shadow Volumes mit beliebiger Geometrie


  • Mod

    nein, reicht nicht, zumal niemand wirklich weiß wie doom3 das macht, das basiswissen haben viele, aber es stecken sicherlich unmengen an optimierungen drinne.
    das was da ist ist ein teil vom setup zum rendern, das rendern selbst ist da nicht drinne.

    rapso->greets();



  • welche für schritte bracht man, denn um shadow volumes von irgendwelchen objekten zu rendern?


  • Mod

    man muss die kanten herausfinden die das shadowvolume generieren und dann muss man von den kanten, entsprechen dem shadowvolume, die geometrie generieren. danach werden die vorderseiten gezeichnet und im stencil-buffer für jeden gesetzten pixel der wert um 1 erhöcht. danach werden die backfaces gezeichnet und für jeden pixel der wert im stencilbuffer um 1 erniedrigt. an den stellen, an denen ein pixel nicht wieder den ausganzswert hat, wurde eine vorderseite gezeichnet ohne passende rückseite, weil dazwischen ein objekt ist, dass den schatten "fängt". am ende wird nun die scene mit der lichtquelle beleuchtet, aber nur an den stellen an denen es keinen schatten gibt.

    naja, das so grob gesehen.

    rapso->greets();



  • Hört sich ziemlich langsam an, vorallem wenn man mehrere Lichtquellen verwenden will 😃

    Wie findet man, denn die Kanten von Objekten heraus? Bei einem Würfel dürfte es ja nicht so schwer sein, aber wie macht man das bei komplexen Objekten, und dann erst mit einem ganz "Raum"?


  • Mod

    ja das ist langsam, dabei ist das langsammste, dass man den vertexbuffer immer neu zur grafikkarten schicken muss und da die am besten laufen, wenn sie asynchron laufen dürfen und man durch den lock des buffers das verhindert, ist das wohl das langsammste dabei ... die menge der vertexdaten könnte aber auch zuviel für den bus sein.

    volumeshadows haben eben viele nachteile auch wenn deren theorie um so einfacher ist.

    wenn ich dir nun jede frage beantworte, wäre das ein tutorial für sich 😉 und davon gibt es schon genug.

    schau bei www.nvidia.com in der developer sektion nach papern, da bekommste auch nen source für z.B. shadowvolumes an quake models.

    rapso->greetS();



  • okay, danke!!!



  • TGGC schrieb:

    Selfshadowing für eine Kugel ist doch unsinnig, das sie konvex ist?

    Ja schon, aber es ist ja nicht immer eine Kugel. Aber auch die Kugel sollte sich beschatten, weil ich habe reflektierende Flächen, und in ungünstigen Winkeln reflektieren die auch auf der Schattenseite. Das wäre aber ausgeschlossen, wenn diese Bereiche auch im StencilSchatten wären.

    rapso schrieb:

    du kannst für jede "kante" (also die zwei dreiecke) die du generierst noch die zwei normalen abspeichern von den dreiecken die sich die kante teilen, im vertexshader könntest du mittels der normalen und der richtung der zur lichtquelle (von dem vertex aus) prüfen ob beide normalen abgewand oder zu lichtquelle zugewand sind. falls sie verschieden sind, dann extrudierst du die kante, falls nicht, dann ist das keine siluetten-kante von der lichtquelle aus gesehen.

    das würde aber nur bei objekten wie z.B. der kugel funktionieren, weil du ja nicht weißt ob eine kante front oder backfaced ist.
    ansonsten muss das alles per cpu gemacht werden (ist dementsprechend langsam), es gibt gute paper auf der nvidia seite.
    rapso->greets();

    Hm ich will das aber lieber nicht mit der CPU machen. Der Vertexshader ist so schön schnell. Und außerdem schreckt mich das 'Kantenfinden' ab. Ich dachte mir, dass man die Modelle einfach in die Länge ziehen kann und gut ist.
    Beim Beispiel der Kugel würde sich die eine Hälfte der Kugel dann vom Licht entfernen, und die andere bliebe da, wo sie ist. Die Polygone, die in der nähe der Kante liegen, weüden dann lang gezogen.
    Gut, so funktioniert das auch, aber eben nicht bei offenen Körpern.

    ... ich könnte die Räume so modellieren, dass die Wände immer eine Rückseite und Seiten haben. So wie man sie in echt auch kennt 😉 . Die zusätlichen Polygone würden dann beim Farbenrendern durchs Backface-Culling durchfallen oder wären nur sehr schmal.

    Ja ich glaube, das wird das beste sein. Ich kann nicht so gut programmieren dass ich die notwendigen Polygone automatisch erzeugen könnte. Manuell kann ich optimieren, aber automatisch könnte ich es nur so machen, wie ich oben schonmal geschrieben habe (also jedes Polygon in einen extra Körper verwandeln). Und da kämen deutlich mehr Polygone bei raus.

    Schon ärgerlich wenn man als Programmierer an so einem Problem scheitert, aber das Info-Studium hab ich noch vor mir. Hoffentlich bin ich danach schlauer als jetzt 🙄

    Danke, rapso und die anderen, für Eure Hilfe.

    P.S: Immer mehr wird mir bei meinem lächerlichen Versuch hier klar, dass Carmack wirklich der Gott sein muss 😮 Nicht nur, dass er es implementieren kann ;), nein, er kann es sogar noch bis in die Perfektion optimieren.


  • Mod

    so ganz kann ich dir net folgen.

    du hast zwar manchmal backfaces und manchmal frontfaces, aber die vertices können von einem front und einem backface gleichzeitig benutzt werden. ich würde mich also fragen wie du das extrudieren möchtest?

    carmack bekommt es deswegen so gut hin, weil er nichts anderes macht (und zu tun hat) als coden. was ihn ausmacht ist nicht genialität, sondern sehr viel fleiss und die daraus resultierende erfahrung, ich finde, dass das sehr viel mehr anerkennung verdient.

    da die cpu-graka-auslastung bei seiner doom3-alpha sehr hoch in richtung cpu ging, wird es wohl auch mit der cpu seine volumes generieren. als optimierung setzt er eine ebene höcher an. z.B. prüft er erst ob ein objet von einer lichtquelle aus überhaupt zu sehen ist, dazu nutzt er portale.
    bei den doom3 videos kann man sehen dass die meißte zeit nur eine lichtquelle einen schatten wirft, der rest beleuchtet, aber diese lichtquellen scheinen keine schatten werfen zu lassen.
    für statische lichtquellen kann man die volumes vorberechnen.
    optimieren kann man indem man z.B. mit der cpu die front und backfaces eines objektes bestimmt und sich das innerhalb eines bitfields speichert und mit dem bitfield für das objekt vom vorframe vergleicht, falls sich nix geändert hat, muss man das volume nicht neu generieren, weil die kanten gleich sind, man muss lediglich die transformation mittels vertexshader neu durchrechnen.

    das generieren der volumes kann man in zwei durchläufen generieren (also zwei durchgänge des meshes), die zeit ist also linear bei steigender polygonmenge.

    rapso->greets();



  • [qote]du hast zwar manchmal backfaces und manchmal frontfaces, aber die vertices können von einem front und einem backface gleichzeitig benutzt werden. ich würde mich also fragen wie du das extrudieren möchtest?"[/quote]

    Ja das stimmt, deßhalb werde ich wahrscheinlich alles aus Blöcken bauen müssen. Eine glatte Wand ist dann zB eine einfache Box. Man kann die Rückseite der Box dann zwar nie sehen, sie ist aber wichtig für die Shadow-Volumes. Außerdem kann ich immernoch normale, einseitige Wände bauen, wenn ich genau weiß dass die sowieso nie einen Schatten auf andere Sachen werfen kann.

    Bei den statischen Lichtquellen: Wäre es da besser, die Volumes dann am Anfang vorzuberechnen und in einen extra Vertexbuffer zu schreiben oder doch alles im VertexShader machen? Der Nachteil an ersterem wäre halt höherer Speicherverbrauch und man müsste die Vertexbuffer wechseln. Zweiteres käme meiner Faulheit sehr willkommen 😉 KA, ob der Shader sooo viel langsamer ist als die Standardvertexpipeline. Und da ich schon Dot3Bumpmapping eingebaut habe, werde ich wohl auch nicht so viele Polygone brauchen (ähnlich Doom3)

    Dass immer nur ein Licht in Doom3 Schatten wirft stimmt nicht ganz:

    http://doom3maps.ngz-network.de/images/news/reicht1.jpg

    Wie das mit den 'richtigen' Wänden funktioniert würde ich gern ausprobieren, muss jetzt aber erstmal formatieren 😋

    Ich meld mich dann nochmal, falls Windows mitmacht.



  • rapso schrieb:

    was ihn ausmacht ist nicht genialität, sondern sehr viel fleiss und die daraus resultierende erfahrung

    ...und Genialität! 🤡 👍



  • Was er einprogrammiert gibt es schon lange, hat nur niemand in Spieleengines eingebaut und das auch noch in der Kombination.



  • Sicher. "Akalabeth" hatte ja quasi auch schon 'ne 3D-Engine, vor Wolfenstein 3D etc. 😃

    Aber er bringt es in ph477er Quali in akzeptabler Geschwindigkeit auf HomeUser-Möhren zum Laufen. Das ist die Kunst!

    Und wenn man bald 3DMax-Renderbildchen oder PovRay-likes, an denen eure Möhren z.Z. noch Stunden rechnen, in ähnlicher Quali und in Echtzeit auf handelsüblichen Systemen bewundern kann... ➡ Er wird der Erste sein! 😃 😉 😋


  • Mod

    wobei wird er der erste sein?

    bumpmapping wie "expandeble" zu haben? schatten mit stencilbuffern wie schon fussballsimulationen? wüste gerne was du meinst.

    vielleicht sind ja auch die grafiker das, was deren hype ausmacht, ziemlich gut was die aus den bescheidenen möglichkeiten zaubern, die sie haben, mit max2 lichtquellen jedes objekt auszuleuchten und zumeinst nur eine im raum die schatten wirft...

    rapso->greets();



  • Hi,

    Hm ich will das aber lieber nicht mit der CPU machen. Der Vertexshader ist so schön schnell. Und außerdem schreckt mich das 'Kantenfinden' ab. Ich dachte mir, dass man die Modelle einfach in die Länge ziehen kann und gut ist.

    man sollte beachten, dass Shader==schnell nicht automatisch true ergibt. Es kommt darauf an, was Deine GPU und CPU sonst noch zu tun haben. 😉

    Das einfache Ausziehen des Modells in einem Shader funktioniert nur für sehr runde, weiche Modelle halbwegs und setzt voraus, dass die Vertices für mehrere Triangles verwendet werden. Sobald man für angrenzende Triangles auf derselben Position zwei Vertices verwendet oder sehr kantige Modele hat geht das so nicht in einem Shader.

    Wenn man auf der CPU "lästig" Kanten suchen muss, dann muss man für einen Shader eine andere lästige Setup Arbeit machen. Nämlich das einfügen degenerierter Quads. An jeder Kante des Modells ein zu einer Linie degeniriertes Viereck einfügen. Was das für den Vertex-Count des Modells bedeutet dürfte klar sein. Im Shader kann man dann tatsächlich einfach alle Backfacing Verts in Lichtlaufrichtung ausziehen. Die degenrierten Quads sorgen dann dafür, dass an der Silouhette keine Löcher entstehen weil sie dort zu richtigen Quads ausgezogen werden.

    Bei ATI gibt es ein Sample mit Code zum Download wo das so gemacht ist.

    Ciao,
    Stefan



  • Stefan Zerbst schrieb:

    Hi,
    An jeder Kante des Modells ein zu einer Linie degeniriertes Viereck einfügen. Was das für den Vertex-Count des Modells bedeutet dürfte klar sein.

    So wie du es erklärst, bleibt er dabei gleich. Für degenerierte Vierecke bräuchte man nur neue Indizes, weil die Vertizen ja gleich sein müssen. (Ich weiss nicht wie es funktioniert, nur das was du hier geschrieben hast.)



  • rapso schrieb:

    wobei wird er der erste sein?

    bumpmapping wie "expandeble" zu haben? schatten mit stencilbuffern wie schon fussballsimulationen? wüste gerne was du meinst.

    vielleicht sind ja auch die grafiker das, was deren hype ausmacht, ziemlich gut was die aus den bescheidenen möglichkeiten zaubern, die sie haben, mit max2 lichtquellen jedes objekt auszuleuchten und zumeinst nur eine im raum die schatten wirft...

    "expandeble"? OMG... 🙄

    Stimmt, Fußball-Sims sehen einfach genial aus... 🙄

    Klar, die Grafiker können et. Und Paul und Tim als Leveldesigner waren auch immer schon genial...

    Tja, nur der Romero fehlt...
    Aber der macht ja jetzt in PDAs... 😃
    DOS-Setup-Routinen werden halt nit mehr gebraucht... :p


  • Mod

    Stefan Zerbst schrieb:

    man sollte beachten, dass Shader==schnell nicht automatisch true ergibt. Es kommt darauf an, was Deine GPU und CPU sonst noch zu tun haben. 😉

    wenn man die GPU machen lässt ohne "Lock" dann kann man mit hocher sicherheit davon ausgehen, dass es schneller ist als mit der cpu. alleine schon 2M vertices/s mit allen nötigen daten zu übertragen kann schnell die 512MB/s eines AGP4 sprengen, was nur 40kVertices bei 50fps wären, die bei degenerierten quads also nur ~10k kanten (6.7k bei strips) bedeuten würden... obwohl volumes so sehr fillrate limitiert sind, dass du recht haben könntest, dass es mit nicht schnell laufen _muss_ bloss weil ein shader benutzt wird. Aber auf heutigen Grakas ist ein aufwendiger shader schneller als cpu, nicht weil die cpu langsam sein wuerde, sondern weil der transfer langsam ist und die graka nicht asynchron arbeiten kann. (schliesslich muessen alle vertices bearbeitet worden sein bevor man mit einem lock alle aendert).

    Stefan Zerbst schrieb:

    Das einfache Ausziehen des Modells in einem Shader funktioniert nur für sehr runde, weiche Modelle halbwegs und setzt voraus, dass die Vertices für mehrere Triangles verwendet werden. Sobald man für angrenzende Triangles auf derselben Position zwei Vertices verwendet oder sehr kantige Modele hat geht das so nicht in einem Shader.

    😮
    irgendwie kann ich dir hier nicht folgen, koenntest du das anders umschreiben was du sagen moechtest ?

    Stefan Zerbst schrieb:

    Wenn man auf der CPU "lästig" Kanten suchen muss, dann muss man für einen Shader eine andere lästige Setup Arbeit machen. Nämlich das einfügen degenerierter Quads. An jeder Kante des Modells ein zu einer Linie degeniriertes Viereck einfügen. Was das für den Vertex-Count des Modells bedeutet dürfte klar sein. Im Shader kann man dann tatsächlich einfach alle Backfacing Verts in Lichtlaufrichtung ausziehen. Die degenrierten Quads sorgen dann dafür, dass an der Silouhette keine Löcher entstehen weil sie dort zu richtigen Quads ausgezogen werden.

    *quizmaster*
    - wie soll man mit dem vertexshader quads einfügen? ist das irgendwie anders gemeint?
    - "Kante des Modells ein zu einer Linie degeniriertes" meinst du mit linie die kante jedes dreiecks oder der silouhette oder etwas anderes?
    - mit Lichtlaufrichtung meinst du den vektor von der lichtquellen position zum vertex? (das "lauf" macht mich confused)

    so wie ich das jetzt glaube verstanden zu haben möchtest du um jedes dreieck herum, an jede kante ein quad einfügen und falls es ein backface ist dann extrudieren... hmm.. oder?

    wuerde das frontface-backface prüfen nicht eigentlich automatisch passieren und man könnte sogar die seperaten operationen für back und frontface für den stencilbuffer nutzen?

    hätte man mit der cpu nicht die gleiche arbeit? würde das nicht eventuell langsammer sein, weil z.B. die GPU zum prüfen ob eine kante auch wirklich silouhette ist nur 2 Dotoperationen macht (2takte) und die cpu dafür einiges mehr braucht?

    ok, das war's auch scho was mich beschäftigt 😃
    hoffe du kannst mich zu deinen gedanken aufklären

    rapso->greets();



  • Hi,

    @TGGC
    Als Der Große Game Coder hast Du sicherlich keine Schwierigkeiten aus meiner wagen Beschreibung zu verstehen wie das funktioniert.

    Aber natürlich hast Du recht ich habe mich hier sehr kurz gefasst was ja sonst die Spezialität von anderen Leuten ist 😃

    Die einzufügenden degenerierten Quads bringen natürlich je vier neue Vertices in das Mesh mit ein, das ist ja Sinn der Sache damit man Vertices zum Ausziehen hat ohne Risse im Mesh zu erzeugen.

    Ohne Shader macht man dasselbe. Der Unterschied für die Shader Version ist nur, dass man alle potenziell benötigten zusätzlichen Rechtecke für die Extruierung der Silouhette zur Initialisierungs-Zeit in das Mesh einfügen muss.

    Ciao,
    Stefan



  • @rapso
    Ich meinte mit der CPU und GPU Auslastung was das Programm den jeweiligen Prozessoren noch aufdrückt. Wenn das Programm bereits GPU limited ist, dann wäre es besser die Volumes über die CPU zu machen.

    Natürlich kann man in einem Shader keine Vertices erzeugen, daher muss man die degenrierten Quads zur Initialisierungszeit dem Mesh einmalig hinzufügen, und zwar für jede Kante. Im Shader werden dann alle Vertices extruiert die von der Lichtquelle wegschauen. Die Backcap verschwindet nach hinten und die degenrierten Quads an der Silouhette werden ausgezogen um die Front- und Back-Cap zu verbinden.

    Was die "runden" Modelle angeht so kann man das Mesh einer Kugel z.B. extruieren ohne dass es zu Fehlern kommt, wenn es keine Vertices auf derselben mit unterschiedlichen Normalen gibt so dass angrenzente Triangle verschiedene Vertices verwenden würden. Dann würde man beim Ausziehen einen Riss zwischen Front- und Backcap erhalten.

    Bei eckigen Modellen wie z.B. einem Würfel geht das nicht so gut weil der Normalenvektor der Vertices eben nicht dem der Ebene der angrenzenden Triangle halbwegs entsprechen kann. 🙂

    Ciao,
    Stefan

    vgl. Dempski, K.; Premier Press; S. 537
    vgl. Brennan, C.; Wordware; Figure 1, S. 190; in Engel, W. (Hrsg.)
    vgl. www.gamedev.net/columns/hardcore/shadowvolume/page5.asp , Abschnitt "Shadow Volumes Powered By Vertex Shaders"


  • Mod

    Stefan Zerbst schrieb:

    Ich meinte mit der CPU und GPU Auslastung was das Programm den jeweiligen Prozessoren noch aufdrückt. Wenn das Programm bereits GPU limited ist, dann wäre es besser die Volumes über die CPU zu machen.

    zwar hat man eine bessere lastenverteilung, aber hauptsächlich deswegen weil die cpu beim lock auf die gpu wartet. es seiden man hat nun wirklich sehr viele polys die man mit der cpu verarbeitet, doch dann wird der traffic wieder limitierend und cpu+gpu warten auf den datentransfer.

    Stefan Zerbst schrieb:

    Natürlich kann man in einem Shader keine Vertices erzeugen, daher muss man die degenrierten Quads zur Initialisierungszeit dem Mesh einmalig hinzufügen, und zwar für jede Kante. Im Shader werden dann alle Vertices extruiert die von der Lichtquelle wegschauen. Die Backcap verschwindet nach hinten und die degenrierten Quads an der Silouhette werden ausgezogen um die Front- und Back-Cap zu verbinden.

    hmm.. anhand von was definiert man denn die blickrichtung der vertices die bei dem cap sind? anhand des dreiecks zu dem sie gehören? dann dürfte man aber kein einziges vertex sharen zwischen den dreiecken, oder?

    Stefan Zerbst schrieb:

    Was die "runden" Modelle angeht so kann man das Mesh einer Kugel z.B. extruieren ohne dass es zu Fehlern kommt, wenn es keine Vertices auf derselben mit unterschiedlichen Normalen gibt so dass angrenzente Triangle verschiedene Vertices verwenden würden. Dann würde man beim Ausziehen einen Riss zwischen Front- und Backcap erhalten.

    das mesch selber? ohne die seiten des volumes? dann müßte man ja das volume wirklich auf unendlich-weit extrudieren damit das nicht auffällt *kopfkratz*

    Stefan Zerbst schrieb:

    Bei eckigen Modellen wie z.B. einem Würfel geht das nicht so gut weil der Normalenvektor der Vertices eben nicht dem der Ebene der angrenzenden Triangle halbwegs entsprechen kann. 🙂

    wenn man das ebenfalls so ziemlich unendlich weit extrudiert, könnte das stimmen wenn man die box hoch genug tesseliert, or?

    Stefan Zerbst schrieb:

    vgl. Dempski, K.; Premier Press; S. 537
    vgl. Brennan, C.; Wordware; Figure 1, S. 190; in Engel, W. (Hrsg.)
    vgl. http://www.gamedev.net/columns/hardcore/shadowvolume/page5.asp , Abschnitt "Shadow Volumes Powered By Vertex Shaders"

    "We need to create a quad for every edge (2 vertices) that is shared by exactly 2 faces. The quad can be viewed as a "degenerate" quad formed by the original edge shared by 2 different faces. Both the faces contribute the same edge to the degenerate quad. Since the edges from both faces are similar, positional wise, the degenerate quad is "zero length". The only difference is that the edges hold the normal information of their respective face. Once in the vertex program, we dot the light vector and the vertex normal. If the result is positive, the vertices pass through the vertex program untouched. If the result is negative, we extrude it in the direction of the light vector. This technique would elegantly generate a closed shadow volume as light facing geometries are left untouched to form the front capping while geometries that faces away from the light are extruded to form the sides of the shadow volume and the back capping."

    da frage ich mich, wenn man ein quad generiert pro kante und die kante von zwei triangles geshared wird, wie will man dann rausfinden ob das quad front oder backfaced ist, da die kanten der triangles selbst gegenläufig sind (falls sie richtig gemodellt sind).

    rapso->greets();


Anmelden zum Antworten