Shadow Volumes mit beliebiger Geometrie, Teil 2



  • Also zu dem kkrieger nochmal. Anhand der Screenshots hab ich mir mal zusammengereimt, wie es so ungefähr funktionieren müsste. Erstmal ist alles aufgeteilt in die Wände/Boden, und in Säulen/Gegner. Auf ersterem (A) sind die Schatten, zweitere (B) werfen die Schatten. Dann wird das ganze Schattenzeug in ein zweites Rendertarget, welches lediglich 512x256 ist, reingezeichnet. Dort werden also dann nach der Methode von oben die Lichter nacheinander reingehauen. Dabei gibts wohl auch Lichter, die gar keinen Schatten machen (z.b. unten an den Säulen). Bei der Aktion besteht die Geometrie erstmal nur aus A. Da kommt dann 'ne Textur raus, welche die Schatten auf A repräsentiert (z.b. voll Licht=undurchsichtig, kein Licht = durchsichtig). Dann wird A normal gezeichnet, und mit der Textur die Schatten draufgebracht. Zum Schluss wird B und dann noch die Waffe gezeichnet.

    Bye, TGGC \-/



  • rapso schrieb:

    heftig, ich komme mit weitaus weniger texturen und passes hin, aber ich spiel auch mit den ps2.0 🙂

    Bei den Anforderungen schreib ich dann hin "Wer Geforce4 oder kleiner benutzt ist selbst schuld."
    Ich glaub D3 macht das ziemlich genauso wie ich. Und das macht mir Sorgen. Dann brauch ich 2 Passes pro Licht obwohl meine Graka ja eh schon etwas lahm ist 😞

    zudem möchtest du softshadows, die bekommst du mit 512*512 ziemlich gut hin, schau dir einfach das unreal video an, die arbeiten viel mit shdowmaps, mit ps2.0 kannst du locker 20mal aus den texturen lesen und somit ein wirklich gutes antialiasing herstellen.

    joa...also das Unreal Video ist jetzt mal ein wirklich überzeugendes Argument für Shadow-Maps 😉 (Wenns denn auch welche sind, aber ich denk das hast Du recherchiert.)
    Hm Anialiasing der Schatten? Was ich möchte ist folgendes:
    In der Nähe des Schattenwerfers soll der Schatten eine harte kante haben, und je weiter weiter man wegkommt desto weicher soll der Schatten sein. Wie schnell das geht sollte von der größe der Lichtquelle abhängig sein.
    Ich habe aber noch nichts gefunden was das kann, außer diese Smoothies. Aber die brauchen Kantenberechnung. (An den Modellkanten werden da Quads vom Licht aus gesehen aufgespannt, und die dann in eine 2. Shadowmap gerendert). Geht das auch auf Pixelbasis? Und wenn ja, Link? 🤡

    So weit es das kommende Semester und anderes Zeugs zulässt werde ich jetzt endlich mal drangehen das Zeugs einzubauen. (Zwischen)Ergebnisse sowie weitere Fragen werden dann hier präsentiert 🕶


  • Mod

    das ist nicht schwer zu realisieren, du hast pro pixel
    -die position im worldspace vom pixel
    -position der lichtquelle (ist ja const)
    -aus der shadowmap den abstand der lichtquelle in diese richtung zum object (also den zbuffer wert der shadowmap)

    nun berechnest du den abstand von lichtquelle zur aktuellen pixelposition, dann teilst das durch den wert aus der shadowmap (nennen wir das mal 'delta')

    falls nun der pixel im shatten ist, kannst du im kreis drumherum die entfernungen auslesen, dabei ist der radius des kreises * 'delta' und schon hast du den gewünschten effekt.

    du kannst den effekt verbessern indem du den ersten wert aus der shadowmap mittelst aus 4 oder 5 werten die du aus der shadowmap ausließt. das lesen aus der map ist dabei nicht teuer da die pixel ja alle recht nah beieinander liegen und somit im cache sind, du solltest mit 2texeln/takt hinkommen.

    den kreis um den schattenpunkt kannst du mit den restlichen freien texturereads bekommen, müßten ca 10 sein.

    in pixelshader 3.0 sind da durchaus mehr reads drinne.

    das schöne an pixelshader 3.0 ist, dass du am anfang testen kannst ob ein pixel bzw triangle zum pointlight backfacing ist und dafür im pixelshader die berechnung gleich abbrechen, das kann sehr viel performance bringen die für die anderen pixel bleibt. (kann man im vertexshader heutzutage auch schon zum teil machen,aber das ist um einiges aufwendiger weil die geometrie angepasst werden müßte (wie bei den SVs)

    rapso->greets();



  • Jetzt muss ich aber doch nochmal fragen (denn in dem alten Thread wurde das eigentlich nie beantwortet). Warum kann ich die ZFunc nicht einfach umdrehen? Ich sehe da höchstens ein Problem, wenn die SVs bis hinter die far clipping plane reichen.

    Bye, TGGC \-/



  • Ich habe jetzt mal eine Frage zur Implementierung. Und zwar habe ich Probleme mit dem z-Vergleich. Die Shadowmap wird korrekt erzeugt und in den Level zurückprojeziert (mit normaler textur getestet). Wenn ich allerdings die Shadowmap benutze, bleibt der ganze Level schwarz, bis auf einen dünnen Streifen. Dieser Streifen liegt genau "in der Ebene des Lichts", hier mal ein Screen

    An was kann das liegen? Muss man etwas bestimmtes bei den Projektionsmatrizen vom Licht und von der Kamera beachten? Darin ist ja jeweils der z-Bereich festgelegt, und ich habe in beiden Matrizen die gleichen Werte angegeben.

    Was auch seltsam ist: Wenn ich in die Shadowmap nichts reinrendere, sondern die nur auf 1.0f Clear()e, dann ist nicht etwa alles im Licht, sondern es gibt diesen Grieseleffekt. Ca. die Hälfte der Pixel ist dann zufällig schwarz, die andere Hälfte farbig.

    Weiß jemand Rat?



  • Ich verstehe nicht so recht, was du mit "Ebene des Lichts" meinst? Für mich sieht das fast so aus, als würden nur noch ein paar Polygone gezeichnet, pixelgenau dürfte der Schatten ja nicht sein.

    Bye, TGGC \-/



  • Also die Position des Lichtes ist ein Punkt in der Ebene, und der Normalenvektor der Ebene entspricht dem Richtungsvektor des Lichts.
    Der sichtbare Streifen ist aber unabhängig von irgendwelchen Polygonen, hier nochmal ein Bild mit dem Wireframe in grün.

    Es scheint so, als ob der ganze z-Bereich in diesen dünnen Streifen gequetscht wird. Dadurch dann wohl auch die Pixelgenauigkeit.

    Wie kann ich denn am einfachsten mal testen, ob der z-Buffer der Shadowmap (also die Shadowmap selbst) richtig erzeugt wird? Am besten als schwarzweiß Bild anzeigen lassen. Geht das?

    Ansonsten sieht es so aus, als ob mir wieder einige glückliche Stunden mit Rumprobieren bevorstünden. Ist irgendwie jedesmal so, wenn ich was neues mit D3D machen will.... ich hoffe weiterhin auf Ratschläge von Euche.


  • Mod

    fang doch mal mit einer einfachereren scene an z.b. zwei planes/boxen, eine kleine auf einer grossen und ne lichtquelle davor.

    so ist das echt schwer zu sagen woran es liegen könnte, gibt unheimlich viel was man bei shadowmaps beachten muss und zudem viele implementationsvariationen...

    rapso->greets();



  • Ich kriegs einfach nicht hin. Habe versucht, die Beispielprogramme, die ich habe mehr oder weniger direkt zu kopieren, aber es will nicht gehen.
    Ich denke, dass es am Projezieren der Shadowmap in den Level liegt. Die Shadowmap selbst sollte eigentlich soweit richtig sein.

    Ich dachte ja erst, dass das Projezieren schon funktioniert, da ich ein Testbild korrekt aus der Sicht des Lichtes in die Geometrie projeziert habe. Aber anscheinend ist es so, dass nicht nur die ersten beiden Einträge der Texturkoordinate benötigt werden, sondern auch die anderen beiden Ausschlag gebend sind (was ich bei einer 2D Textur nicht unbedingt erwartet hätte).

    @rapso: Wenn ich das richtig verstanden habe, dann machst Du ja auch viel bzw. alles mit Shadern. Ich denke mal dann wirst Du mir helfen können. Ich will einfach die Position jeder Vertize(?) im Vertex Shader mit einer Matrix multiplizieren, und das Ergebnis als Texturkoordinate speichern. Also komplett auf dieses EYE_LINEAR_TEXCOORD_ODER_SO Zeugs verzichten.

    Bisher sieht diese Matrix M so aus:

    matTexAdj = \[ \left( \begin{array}{cccc} 0.5 & 0 & 0 & 0 \\ 0 & -0.5 & 0 & 0 \\ 0 & 0 & fZScale & 0 \\ 0.5 & 0.5 & fBias & 1\end{array} \right)\] fZScale = 2^2^4-1 fBias = -0.0002 \\ matLicht = matLichtView * matLichtProj \\ M = (matLicht * matTexAdj)^T

    Damit kann man wie gesagt eine Textur in den Level projezieren, nur mit den z-Werten klappt es eben nicht so ganz. Es entsteht dann dieser oben beschriebene Streifen (der von der Breite her übrigens genau der NearPlane der Lichtprojektion entspricht).
    In dem NVidia Paper "Hardware Shadow Mapping" wird auch noch irgendwas mit der Kameramatrix gemacht. Habe ich auch schon versucht, aber es hat nicht funktioniert. Und um ehrlich zu sein: Ich hab überhaupt keinen Plan, wie diese ganzen Matrizen letztendlich arbeiten. Und somit kann ich höchstens ein wenig an den Werten rumdrehen, was ich da tue weiß ich aber nicht.

    Ich hoffe Du (oder jemand anderst) weißt, wie die Matrix aussehen muss 😋



  • Also die Theorie hinter der Schadowmap ist mir klar. Man hat den Z-Buffer quasi in der Textur und alles was "tiefer" ist, ist im Schatten. Praktische Anwendungen habe ich mir aber noch nicht angeschaut. Aber ich nehme mal an, da gibts jetzt auch verschiedene Methoden, wie du sowas renderst. Davon hängt deine Matrize dann sicher auch ab. Also zeig doch mal, was du für Renderstates usw. benutzt. Es muss ja irgendwie ein Test pixel.z < texel.rgb auf der GraKa gemacht werden.

    Bye, TGGC \-/


  • Mod

    0x00000001 schrieb:

    Ich kriegs einfach nicht hin. Habe versucht, die Beispielprogramme, die ich habe mehr oder weniger direkt zu kopieren, aber es will nicht gehen.
    Ich denke, dass es am Projezieren der Shadowmap in den Level liegt. Die Shadowmap selbst sollte eigentlich soweit richtig sein.

    Ich dachte ja erst, dass das Projezieren schon funktioniert, da ich ein Testbild korrekt aus der Sicht des Lichtes in die Geometrie projeziert habe. Aber anscheinend ist es so, dass nicht nur die ersten beiden Einträge der Texturkoordinate benötigt werden, sondern auch die anderen beiden Ausschlag gebend sind (was ich bei einer 2D Textur nicht unbedingt erwartet hätte).

    @rapso: Wenn ich das richtig verstanden habe, dann machst Du ja auch viel bzw. alles mit Shadern. Ich denke mal dann wirst Du mir helfen können. Ich will einfach die Position jeder Vertize(?) im Vertex Shader mit einer Matrix multiplizieren, und das Ergebnis als Texturkoordinate speichern. Also komplett auf dieses EYE_LINEAR_TEXCOORD_ODER_SO Zeugs verzichten.

    Bisher sieht diese Matrix M so aus:

    matTexAdj = \[ \left( \begin{array}{cccc} 0.5 & 0 & 0 & 0 \\ 0 & -0.5 & 0 & 0 \\ 0 & 0 & fZScale & 0 \\ 0.5 & 0.5 & fBias & 1\end{array} \right)\] fZScale = 2^2^4-1 fBias = -0.0002 \\ matLicht = matLichtView * matLichtProj \\ M = (matLicht * matTexAdj)^T

    Damit kann man wie gesagt eine Textur in den Level projezieren, nur mit den z-Werten klappt es eben nicht so ganz. Es entsteht dann dieser oben beschriebene Streifen (der von der Breite her übrigens genau der NearPlane der Lichtprojektion entspricht).
    In dem NVidia Paper "Hardware Shadow Mapping" wird auch noch irgendwas mit der Kameramatrix gemacht. Habe ich auch schon versucht, aber es hat nicht funktioniert. Und um ehrlich zu sein: Ich hab überhaupt keinen Plan, wie diese ganzen Matrizen letztendlich arbeiten. Und somit kann ich höchstens ein wenig an den Werten rumdrehen, was ich da tue weiß ich aber nicht.

    Ich hoffe Du (oder jemand anderst) weißt, wie die Matrix aussehen muss 😋

    ich schätze du hast da die oGL sachen von nvidia durchstöbert, dort macht man das damit, bei d3d kannst du dafür versuchen den zbias zu benutzen (SetRenderState...). das problem ist, dass es quasi zfighting zwischen der shadowmap und der geometrie gibt, schliesslich steht in der shadowmap die entfernung zum licht und du berechnest dir ja auch die entfernung zum licht und vergleichst die beiden werde, je nach nachkommerstelle ist dann das ergebniss zufällig. deswegen multipliziert man die entfernung ||licht-pixelposition|| mit einem kleinen skalierungsfaktor (man addiert nicht nur, weil der zbuffer nicht linear ist) und bei d3d addiert man mit zbias dann nen wert drauf für den zcompare, und zwar sind das die zbuffer einheiten und nicht wirkliche entfernungen, weil wie gesagt, wegen des nicht linearen zbuffers würde das anders mit dem addieren nicht funzen.

    es gibt leute die auch einen shadowmap pass für die backfaces und einen für die frontfaces machen, wenn man geschlossene objekte hat, dann kann man einen mittelwert bekommen, der immer genau durch die objekte hindurch geht und umgeht so das z-fighting.

    rapso->greets();



  • TGGC schrieb:

    Also zeig doch mal, was du für Renderstates usw. benutzt. Es muss ja irgendwie ein Test pixel.z < texel.rgb auf der GraKa gemacht werden.

    Hm Renderstates brauche ich da so gut wie keine. Nachdem man die Shadowmap gerendert hat, setzt man sie in einen Texturkanal und erstellt die Texturkoordinaten durch geeignete Projektion. Die Textur ist ja ein Z-Buffer, und wenn daraus gesampelt wird, kann das ergebnis nur 0 oder 1 sein ( das Ergebnis des z-Vergleiches). Man muss also nix spezielles einstellen, das sollte automatisch funktionieren. So hab ich das zumindest verstanden.

    @rapso: Du bist mir schon wieder voraus, mit dem Bias oder mit z-Fights habe ich noch garkeine Probleme weil bis jetzt überhaupt nichts funktioniert :p
    Es geht mir im Moment nur darum, wie ich die Texturkoordinaten für die Shadowmap bekomme. Bei diesen Koordinaten scheint aus irgendweinem Grund die z und w Komponente wichtig zu sein.
    Ich habe mal wieder 2 Screenshots gemacht, die mein Problem hoffentlich besser erklären: Bilder
    Wie man dort sieht, funktioniert die Projektion für ein normales Bild ganz gut, d.h. die x und y Komponenten der Texturkoordinaten sind richtig. Bleibt nur noch z und eventuell w. Vielleicht muss ich ja doch noch irgendwelche Renderstates bzw. Texturestagestates anmachen. Im VShader transformiere ich einfach nur die Vertexposition mittels der oben beschriebenen Matrix, sonst mache ich damit garnix.
    Sag doch mal bitte, wie Du das machst. Du musst ja auch irgendwas mit der Lichtprojektionsmatrix usw. gemacht haben.



  • @rapso: Schade, dass Du nicht geantwortet hast. Ist aber nicht so schlimm, denn 1. hab ich den Fehler mittlerweile selbst gefunden und 2. lag er eh ganz wo anderst 😉
    Es ist ganz einfach: Ich habe für die Shadowmap einen 24Bit z-buffer genommen und als Farbpuffer eine 16 Bit Textur. Das geht nicht.

    Gut, sowas muss man erstmal wissen. Ich ärgere mich aber trotzdem stark über mich selbst, weil ich mal wieder am Optimieren war bevor überhaupt irgendwas funktioniert hat 🙄

    Vielen Dank nochmal für eure Hilfe (besonders rapso), ich denke mit den Shadowmaps werde ich glücklicher als mit den Volumes. (vor allem wegen der Shader 2.0 Karte die ich bald anlässlich Doom3 kaufe 👍 )



  • It is easier to optimize correct code than to correct optimized code.

    Bye, TGGC \-/


  • Mod

    0x00000001 schrieb:

    @rapso: Schade, dass Du nicht geantwortet hast. Ist aber nicht so schlimm, denn 1. hab ich den Fehler mittlerweile selbst gefunden und 2. lag er eh ganz wo anderst 😉
    Es ist ganz einfach: Ich habe für die Shadowmap einen 24Bit z-buffer genommen und als Farbpuffer eine 16 Bit Textur. Das geht nicht.

    Gut, sowas muss man erstmal wissen. Ich ärgere mich aber trotzdem stark über mich selbst, weil ich mal wieder am Optimieren war bevor überhaupt irgendwas funktioniert hat 🙄

    Vielen Dank nochmal für eure Hilfe (besonders rapso), ich denke mit den Shadowmaps werde ich glücklicher als mit den Volumes. (vor allem wegen der Shader 2.0 Karte die ich bald anlässlich Doom3 kaufe 👍 )

    naja, mir viel auch nichts zu deinem problem ein, da wollte ich net dumm rumspinnen.

    auf der nvidia konferenz hatten die neue paper zu shadowmapping vorgestellt (laut nvidia sind shadowmaps besser als shadowvolumes) und die wird es bald auf deren hp geben, die werden ein paar z-fighting probleme von dir lösen.

    rapso->greets();


Anmelden zum Antworten