Raycasting front-to-back
-
Hi,
danke schonmal für den Hinweis. Wenn ich zwei halbtransparente Voxel hintereinander habe müsste die akkumulierte Transparenz ja 0,25 betragen, da das erste Voxel die Hälfte der "Intesität" absorbiert und von dieser Hälfte das zweite Voxel ebenfalls die Hälfte der Intensität absorbiert. Kann aber auch sein, dass ich da einen Denkfehler habe.
Dein Hinweis ist richtig, habe die Zeile auf
accum_transparency = accum_transparency * current_transparency;
aktualisiert, was komischerweise genau das gleiche Bild liefert.
-
mortified_penguin schrieb:
Wenn ich zwei halbtransparente Voxel hintereinander habe müsste die akkumulierte Transparenz ja 0,25 betragen,
Ja, 0.25 sollte richtig sein. Mein Fehler. Muss die ganze Zeit gegen meine Intuition kämpfen, die von Opazität statt Transparenz ausgeht.
Negativ ist natürlich trotzdem falschIn dem Sinne ist "Transparenz" eigentlich auch die richtige Wahl, da es sich nicht um die Transparenz des aktuellen Voxel handelt,
sondern um den Intensitätsanteil des aktuellen Voxel der von den Voxeln die auf dem Strahl "davor" liegen durchgelassen wird.Eine andere Sache die mir noch aufgefallen ist: Bist du sicher, dass du das Voxel-Volumen in der richtigen Richtung durchläufst?
So wie ich das sehe hast du da noch keine View-Projektion oder sowas drin, du durchläufst das Volumen einfach in Richtung
der Z-Achse und zwar von +Z (Länge des Strahls) nach 0 ... ist das richtig so?
Sollte es nicht eher entweder von 0 bis (Länge des Strahls) oder, wenn du aus Richtung +Z auf das Volumen schaust,
von (Tiefe des Volumens) bis (Tiefe des Volumens) - (Länge des Strahls) sein?:int steps = len-1; ... vec4 voxel_curr = texture3D(textures[0] , vec3(coord.x, coord.y, steps/(len*1.0))); ... steps -= step_size;
Keine Ahnung ob das die Ursache ist, aber es sieht mir irgendwie falsch aus.
Finnegan
-
Die Länge des Strahls ist ja gleich der Tiefe des Volumens, also sollte der Durchlauf von len bis 0 richtig sein. Wenn ich aber testweise von 0 bis len laufe, bekomme ich den gleichen Fehler den ich im OP beschrieben hab.
-
Mir gehen grad ein wenig die Ideen aus, daher ein paar allgemeine Fragen:
Habe ich das richtig verstanden? Das ist exakt genau dasselbe Setup, das in der back-to-front-Variante korrekt funktioniert?
Es gibt da noch ein paar Dinge, die mich etwas wundern:vec4 trace_front_to_back(sampler3D volume ... , sampler1D opac_lut , sampler1D color_lut ... vec4 voxel_curr = texture3D(textures[0] , vec3(coord.x, coord.y, steps/(len*1.0))); ... voxel_curr *= texture1D(color_tf, curr_voxel_val); vec4 current_transparency = texture1D(opac_tf, curr_voxel_val); }
Müssten die ersten Argumente von
texture*
nicht die Sampler sein, die du in den Parametern vontrace_front_to_back
übergeben bekommst? Also:... vec4 voxel_curr = texture3D(volume , vec3(coord.x, coord.y, steps/(len*1.0))); ... voxel_curr *= texture1D(color_lut, curr_voxel_val); vec4 current_transparency = texture1D(opac_lut, curr_voxel_val); ...
Sind die
_tf
Variablen global? Sind die korrekt aufgesetzt und verweisen die auf die richtigen Texturen?Eine weitere Sache hier:
voxel_curr *= texture1D(color_tf, curr_voxel_val);
Du modulierst die Intensität des Voxels mit der (via Sampler interpolierten) Farbe für diesen Wert aus dem LUT.
Ist das so gewollt, dass die LUT-Farbe mit der Voxel-Intensität skaliert wird?
Ich hätte jetzt gedacht, dass dass im LUT lediglich ein "Mapping" Intensität->Farbe stehen würde.
So wie es da steht haben z.B. niedrige Intensitäten immer eine "dunkle" Farbe, egal wie "hell" die Farbe im LUT
für die Instensität definiert wurde.Ausserdem hast du im OP von "Slices" gesprochen. Wie machst du das Rendering selbst?
Ich bin bisher davon ausgegangen dass du lediglich ein Quad renderst, bei dem dieser Shader aktiviert ist.
Ist das korrekt? Falls du aus irgendeinem Grund das Volumen stückweise rendern solltest also ein Quad pro "Slice",
die jeweils hintereinander liegen, könnte natürlich auch der Z-Buffer dein Problem sein, da dann nur das erste Quad
gerendert wird und die dahinter liegenden nicht, da für diese dann der Z-Test fehlschlagen würde (wegen dem ersten Quad).Finnegan
-
Ja deine Punkte sind korrekt, das hab ich beim refactorn übersehen. Das ist das selbe Setup, mit dem back-to-front raycasting funktioniert.
Ich render nur einen Quad auf den dann das Volumen projiziert wird.
-
So langsam gehen mir wirklich die Ideen aus
Renderst du das Quad eventuell mit aktiviertem Alpha-Blending? In diesem Fall würdest du z.B. bei voller Deckkraft (transparency=0) den Alphakanal des Voxel-Anteils des Ausgabe-Fragments ebenfalls mit 0 multiplizieren, was dann beim Rendering genau den umgekehrten Effekt wie bei deinem Raycasting hätte: Voxel-Anteile die du als voll transparent und somit schwarz bestimmt hättest würden dann mit maximaler Deckkraft einfließen während die opaken Anteile transparent wären..., das könnte evtl. den beschiebenen Effekt auslösen. Nur so eine Idee. Ich weiss nicht genau wie du das back-to-front implementiert hast, eventuell könnte sich da der Effekt eines zusätzlichen Alpha-Blendings nicht zeigen. Hast du vielleicht mal einen Screenshot zur Hand? Vielleicht wird daran deutlicher wo das Problem liegen könnte.
Finnegan
-
Ich hab kein Alphablending aktiviert. Hier mal ein Bild, zur besseren Sichtbarkeit hab ich beim zweitletzten Slice angefangen. Lila ist die Haut, weiß der Knochen.
http://fs2.directupload.net/images/150809/yqy79z7s.png
-
Eine kurze Info, was in dem Volumen abgebildet ist wäre noch fein gewesen :D. Ich vermute das ist ein Schädel?
Sieht tatsächlich ein wenig so aus als wäre bereits die erste
current_transparency
die du dir für beliebigevoxel_curr
aus demopac_lut
-Sampler ziehst Null. D.h. auch die leere "Luft" scheint eine Transparenz von 0 zu haben, da ich davon ausgehe dass der Schädel in Z-Richtung breiter wird und dann der nicht-schwarze Bereich eigentlich größer sein müsste.Ich würde das mal schrittweise Debuggen und mir de Werte ansehen, die du da aus den verschiedenen Texturen rausziehst. Optimalerweise mit einem geeigneten GLSL-Debugger (kann leider keinen empfehlen) oder die klassische "print"-Methode, wobei "print" im Fall von GLSL natürlich das zurückgeben einer Farbe via
return
istDu könntest dir z.B. mal ganz simpel statt
accum
die erstecurrent_transparency
ausgeben, die du aus dem LUT ziehst. Die sollte ja zumindest in denLuft
-Bereichen nicht 0 sein sondern eher Weiß (1).Die anderen Werte kannst du ähnlich debuggen und so zumindest grob feststellen ob die Werte stimmen. Da dein Shader-Modell ja offenbar Branching unterstützt kannst du natürlich auch noch präziser debuggen: wenn Bedingung zutrifft, dann gib "Grün" zurück, ansonsten "Rot" ... so solltest du dem Problem stückweise auf die Schliche kommen. Ich sehe nämlich jetzt so ad hoc nur durch Code-Starren nichts auffälliges mehr, sofern die ganzen Rahmenbedingungen okay sind (Texturen korrekt, Sampler richtig konfiguriert, Sättigungsarithmetik, Berücksichtigt dass gesampelte Werte gemäss Sampler-Konfiguration interpoliert sind, sinnvolle Behandlung von Rand-Pixeln der Texturen [CLAMP, REPEAT, feste Farbe, etc.] - beachten dass Pixel außerhalb der eigentlichen Textur [ausserhalb von [0,1] \times [0,1\]] via Interpolation in einen gesampelten Randpixel "hineinbluten" können,
len
undstep_size
haben sinnvolle Werte, etc. - vieles davon sollte aber schon beimback-to-front
probleme gemacht haben).Finnegan
-
Was mich wundert ist, wenn ich die Schleife folgendermaßen verkleinere:
for (int i=0; i<16; ++i) { vec4 voxel_curr = texture3D(volume , vec3(coord.x, coord.y, (1.0*33)/(steps))); // random slice accum = voxel_curr; }
Also eine beliebige Schicht wähle und deren Wert an (x,y,33) in einer Schleife in die Variable accum schreibe, bekomme ich ein schwarzes Bild, wenn die Schleife öfter als 22 mal durchläuft. Eventuell ein Treiberbug?
-
mortified_penguin schrieb:
Also eine beliebige Schicht wähle und deren Wert an (x,y,33) in einer Schleife in die Variable accum schreibe, bekomme ich ein schwarzes Bild, wenn die Schleife öfter als 22 mal durchläuft. Eventuell ein Treiberbug?
Ach? Und vorher ist das Bild okay wie du es erwartest? Und
steps
ist auch 33 (beachten: Texturkoordinaten liegen dann ausserhalb der Textur, dann greift die Sampler-Konfiguration für die Ränder)?Wenns nur an der Anzahl der durchläufe liegt könnte es auch kein Treiber-Bug sondern ein Treiber-Feature sein, das einen Shader-Thread abbricht, wenn er zu lange braucht - schonmal ne Endlosschleife in nem Shader programmiert? Bei meiner letzten Erfahrung damit ging gar nix mehr - schon übel wenn das System im Grafiktreiber hängt, der grad auf die GPU wartet :D.
Allerdings klingt 22 für mich noch ziemlich klein. Es gibt da Raycasting-Shader mit aufwändigeren Schleifen die ganz schicke Resultate erzielen und ordentlich laufen.
Finnegan
P.S.: Ich würde bei obiger Schleife ausserdem erwarten, dass der GLSL-Compiler die Schleife komplett wegoptimiert. Ich weiss die sind wahrscheinlich nicht ganz so pfiffig wie ein akueller C++-Compiler, aber das sollte eigentlich simpel genug sein.
-
Scheint in der Tat ein Treiberbug zu sein. Ich arbeite unter Linux mit nouveau; habs jetzt auf meinem Laptop mit proprietärem Treiber probiert, da scheint alles ok zu sein. Warum jetzt allerdings die Version back-to-front geht deren Schleife genauso oft durchläuft und sogar noch geschachtelt ist, versteh ich jetzt auch nicht wirklich.
Danke übrigens für die Hilfe
-
Manchmal sind es relativ simple Dinge die ein Treiber toleriert und ein anderer nicht. Hatte z.B. mal ein fehlendes Padding bei einer uniform-Datenstruktur in Direct3D11... länger nicht bemerkt, da der NVidia-Treiber das kommentarlos geschluckt hat. ATI-Treiber hat einfach nix gemacht und hat nen schwarzen Bildschirm angezeigt. GL_ARB_debug_output könnte bei OpenGL eventuell hilfreich sein Sachen zu finden, wo man sich z.B. nicht genau an die Spezifikation hält. Ansonsten ist der proprietäre Treiber die richtige Wahl wenn man GPU-Programmierung macht. Man mag von dem Laden halten was man will, deren OpenGL-Implementation ist einfach die beste die man für aktuelle GPUs finden kann ... auch wenn ein hinreichend komplexes Programm dann nicht selten auf anderen Treibern schlecht oder gar nicht läuft (liegt aber leider daran dass doch so manche OGL-Implementierungen nicht das gelbe vom Ei sind).
Finnegan