3D-(Voxel-/)Schnittbilder(MRT) Visualisieren (OpenGL 4.3)



  • Heyho Osbios, heyho Gregor, heyho Community,

    ich hab jetzt ein wenig weiter Recherchiert und gelesen und habe mich dazu entschieden beide Vorschläge von Euch zu Implementieren und in meiner Arbeit auf zu nehmen.

    Das generelle Vorgehen bei den beiden Verfahren habe ich auch soweit verstanden.
    Lediglich zu Implementierung hätte ich noch eine Frage.

    Als Daten habe ich einen Stapel von 2D-Bildern vorliegen.
    Dieser würde beim 2D-Texture-Based-Volume-Rendering ja exakt den Textur-Daten einer Achse entsprechen.

    Wie Berechne ich mir aus diesem Datensatz sinnvolle Datensätze für die anderen beiden Achsen?

    Da steh ich grad noch was auf dem Schlauch 😉

    Wäre gut, wenn mir da jemand weiterhelfen könnte ^^

    Lieben Gruß


  • Mod

    JangoK schrieb:

    Wie Berechne ich mir aus diesem Datensatz sinnvolle Datensätze für die anderen beiden Achsen?

    auch fuer den fall dass ich mich wiederhole:

    raps schrieb:

    eigentlich renderst du nicht die schichten der textur, sondern schichten in die tiefe vom view-cone. du passt dabei die indizierung der textur so an, dass die UVWs inverse rotiert sind zur camera rotation. natuerlich benutzt du dafuer dann eine 3d textur, keine z * 2d texturen.



  • Hallo rapso,

    meine Frage setzt allerdings etwas früher an (wenn ich mich nicht Irre).

    Meinen Recherchen zufolge ist es notwendig die durch die Aufnahme vom MRT diskretisierten Daten des Objektes wieder zurück zu Rechnen, da gegebenenfalls auch Daten zwischen den Abtast-Schichten des MRT benötigt werden.
    Unabhängig von 2D oder 3D Textur.

    Methoden zur Rekonstruktion der Daten habe ich mittlerweile allerdings auch gefunden. Beschrieben und verglichen werden einige im Paper von Marschner et. al. "An Evaluation of Reconstruction Filters for Volume Rendering".

    Tut mir leid, falls die Frage unklar formuliert war.

    Lieben Gruß


  • Mod

    ich dachte dir ging es darum den existierenden scan zu visualisieren. daten zwischen den pixeln zu interpolieren klingt nach einem ganz anderem topic.

    wie waere es wenn du erst die visualisierung loest? wenn das geht, kannst du die daten immer noch erweitern. zuviel auf einmal kann am ende dazu fuehren dass nichts da ist 😉



  • Heyho rapso,

    du hast schon recht, mir geht es darum verschiedene Visualisierungs-Verfahren für MRT-Schichtdaten zu implementieren und zu vergleichen.

    In der Literatur steht allerdings beschrieben, dass zur Visualisierung mittels Direct-Volume-Rendering vorher eine Rekonstruktion und Klassifikation der Schichtdaten vorgenommen werden muss. Ansonsten kann Beispielsweise das 2D und/oder 3D-Texture-Based-Rendering garnicht vorgenommen werden, da Werte fehlen um die notwendigen Render-Schichten zu erzeugen.

    Daher muss ich scheinbar um das Problem der Visualisierung zu lösen, erst einmal das Problem der Rekonstruktion und Klassifizierung lösen. ^^



  • Du musst nicht unbedingt interpolieren.

    Wenn Du Direct Volume Rendering betreibst und dafür einen Raycasting-Algorithmus verwendest, dann ist letztendlich die Frage, wie Du den "Strahl" diskretisierst. Du kannst natürlich sagen, dass Du einen Strahl hast, der die Voxel nicht genau trifft und deshalb muss immer zwischen verschiedenen Voxeln interpoliert werden. Du könntest aber auch einen Bresenham Linienalgorithmus zur Erzeugung des Strahls verwenden. Der liefert Dir einen Strahl in Form von einer Menge diskreter Koordinaten, an denen sich jeweils ein Voxel befindet. Das Resultat davon ist möglicherweise um Nuancen schlechter als ein Algorithmus, der mit Interpolation arbeitet, dafür ist er aber auch wesentlich schneller. Du brauchst dort eben keine Interpolation und zudem läuft das Erzeugen der Linie mit Ganzzahlarithmetik.

    Ich habe vor langer Zeit auch mal etwas mit Direct Volume Rendering rumgespielt und dafür so einen Bresenham Algorithmus verwendet. Herausgekommen sind Darstellungen wie die da:

    https://i.imgur.com/i7oXNBq.png

    Ist vielleicht etwas grobpixelig. Andererseits wird das pixelige nicht direkt etwas mit dem Bresenham-Algorithmus zu tun haben.


  • Mod

    @JangoK

    mir ist nicht ganz klar was du rekonstruieren bzw klassifizieren willst. fuer die visualisierung sind eigentlich nur die schnittbilder noetig und die hast du, wie du sagtest.
    dann muss man das nur auf die GPU laden und raycastern wie z.B. bei http://demos.vicomtech.org/volren/ zu sehen (ein browser mit WebGL ist noetig).



  • @rapso

    Generell hast du recht.
    Angenommen ich möchte Raycasten kann ich das wie Gregor auch schon beschrieben hat vollkommen ohne Interpolation/Rekonstruktion machen.

    Allerdings geht es mir weniger darum irgend einen Algorithmus zu implementieren.
    Sondern mehr darum mehrere mögliche Verfahren zu beschreiben, zu testen und dann Anhand der Ergebnisse zu Vergleichen um begründen zu können warum ich mich für Verfahren XY entschieden habe.

    Zu den Verfahren gehört unter anderem auch das Raycasting, welches als Bildbasiertes Verfahren gilt.

    Allerdings gibt es im Bezug auf Direct-Volume-Rendering noch verfahren wie Splatting, welches Objektbasiert ist, oder Shear-Warp und Texture-Mapping, welche Mischformen sind.

    Bei diesen Verfahren ist dann eine Interpolation/Rekonstruktion der Daten notwendig.

    Und bei allen Verfahren ist eine Klassifikation notwendig, auch beim Raycasting.
    Denn die Definition der Objekteigenschaft (Grauwert XY ist transparent etc) ist ein Teil der Klassifikation.

    Des Weiteren gibt es auch noch das Indirect-Volume-Rendering. Wo dann Verfahren wie Marching-Cubes eine Rolle spielen um Oberflächen Approximationen zu erzeugen.

    Gruß

    Jango


  • Mod

    ich nehme an mit klassifizierung meinst du die transfer function, die wird oft nicht vor dem rendern gemacht, sondern waehrend des rendern, da grauwerte sehr viel kompakter sind und der zugriff auf das volume das performance kritischte ist (meistens). natuerlich ist das resultat etwas anders, je nachdem ob erst die transfer function oder erst die interpolation durchgefuehrt wird.

    wenn du also verfahren vergleichst, beachte die reihenfolge bei denen (vielleicht ist pre- und post- klassifizierung sogar etwas, was wert waere verglichen zu werden).

    und vergiss nicht ein paar schoene bilder davon in unseren screenshot thread zu posten 😉

    http://www.c-plusplus.net/forum/191889-160



  • Heyho, ich schon wieder 😉

    Ich hab den Theorie-Teil jetzt soweit abgeschlossen und bin gerade dabei (zu versuchen) das 3D-Based-Texture-Mapping zu implementieren.

    Allerdings habe ich keine Idee wie ich auch nur an nährend diese Blickrichtungsorientierten 2D-Schichten berechnen soll...

    Ich hab dazu viel theorie gefunden, aber kA wie ich das jetzt in die Praxis umsetzten kann. wäre nett wenn jemand mir da helfen könnte.

    Die Fragen sind also:

    Wie bestimme ich die bounding-Box um meine Textur?

    Wie berechne ich die Schichten auf die ich meine Textur ziehe aus dieser bounding-Box?

    Ich habe einen Ansatz mit Marching-Cubes gefunden.
    Den verstehe ich aber auch nicht so ganz um ihn selbst nach implementieren zu können..

    http://www.vmg.cs.bangor.ac.uk/Papers/05CGGM.pdf

    z.B. was bedeuten die Zahlen im Index bei GL_MODELVIEWMATRIX und woher kommt diese magische Tabelle die auf all meine Probleme Lösungen bietet? ^^

    Ich hoffe ihr könnt mir auch hier behilflich sein 🙂



  • Moin,

    ich beschäftige mich schon seit Jahren mit dem Thema und ich würde Dir raten das Rad nicht neu zu erfinden wenn Du nicht unbedingt musst.

    Es gibt da ein sehr gutes Toolkit namens VTK von Kiteware. Das basiert auf OpenGL ist auch noch OpenSource. Das bietet Dir alles was Du brauchst.
    Damit kannst Du Surfacerendern mit MarchingCubes, Raycasten und Schnittbilder erzeugen. Die haben sehr viele Beispiele und ich hatte damals schnell Ergebnisse.

    So kannst Du Dich auf Deine Visualisierung konzentrieren, denn die ist bei MRT Daten nicht so einfach wie beim CT mit der Hounsfield scala. Die Schnittbilder mal außen vor, musst Du bei den anderen Verfahren schon wissen was Du hervorheben möchtest(Knochen, Weichteile ...) und welche Voxel- Wertebereiche diese Strukturen in Deiner Serie haben.

    Ich denke für den Anfang werden Dir die Reslice Geschichten im VTK schon gut helfen. Und der Source Code ist recht leserlich, falls Du wissen willst wie die das machen.

    Ich hoffe es hilft Dir
    Gruß Andi



  • Heyho Andiamo,

    das Rad neu erfinden möchte ich natürlich nicht, aber auf ein fertiges Rad wie VTK zurück zu greifen ist mir leider auch nicht möglich. Was ich gerne hätte, wäre ein guter Bauplan des Rades damit ich es gut Nachbauen kann ;D.

    Es geht bei meiner Arbeit ja darum die Verfahren zu analysieren und zu implementieren. daraufhin zu vergleichen. Dafür muss ich eh wissen was im Hintergrund passiert. Und da das ganze auch noch Projekt gebunden ist kann ich ohnehin nicht auf VTK zurück greifen, sondern bin leider verpflichtet das zu nehmen, was das Projekt mir gibt.

    Und das ist nunmal OpenGL und GLFW.

    Trotzdem danke für den Tipp.

    Gruß´

    Jango



  • verstehe.
    Kannst Du mal Dein Thema konkreter beschreiben? Wofür ist das? Was für ein Projekt ist das? Welche Kriterien ziehst Du für den Vergleich der Methoden heran? Ich hatte für die Einarbeitung in diese Thematik das Buch "Visualization in Medicine" von Dirk Bartz in den Händen. Da steht doch schon alles drin. Mit Vergleich.

    Für Dein Projekt muss ich sagen, dass das was Du da vor hast extrem viel Arbeit ist. Die Verfahren sind alle an sich schon nicht trivial und dann gibt es noch Verbesserungen die die Qualität und Performance beeinflussen. Zum Beispiel denke ich da an Parallelität und verschiedenste Interpolationsmethoden. Fließt das alles auch in Deine Arbeit ein?

    Ich habe irgendwas hier gelesen, dass Deine Daten schon "vorverarbeitet" sind, dass man nur die Adern sieht. Wie wurde das gemacht? Window/Level? VOI-Lut?



  • Heyho,

    also die ganzen performance verbesserungen werde ich wohl aus zeitlichen Gründen nicht mehr mit rein nehmen können.
    Evt werd ich es erwähnen und auch erklären wie es funktioniert, aber nicht implementieren, da dazu die Zeit einfach nicht aussreicht. Der Wesentliche Vergleichspunkt ist das Visuelle Ergebnis und die Möglichkeit zur Weiterverarbeitung. Nebenkriterien sind Performance und Speicherbedarf. Evt wird für den Algorithmus, für den sich daraufhin entschieden wird auch noch die "Verbesserung" implementiert.

    Bzgl der vorverarbeitung der Daten.
    Die MRT-Daten vom Gehirn wurden in 2 schritten vor segmentiert.
    Zuerst wurde mit einem verfahren ähnlich dem von Forkert et. al. das Gehirn vor segmentiert.

    http://www.egms.de/static/de/meetings/gmds2008/08gmds245.shtml

    Daraufhin mit Hilfe von des Vesselness Filters von Frangi et. al. (Paper leider grad nicht zur Hand) eine Ader-Segmentiertung vorgenommen.

    Die Daten sollen nun visuallisiert werden.
    Da sie allerdings so gut vor segmentiert sind, sind die Materialeigenschaften eigl ziemlich unwichtig für mich.
    Das einzige, was meine Transferfunktion nach machen muss ist den Alpha-Wert setzten damit schwarze Pixel durchsichtig werden.

    Da es sich um eine Bachelor-Arbeit handelt in einer wissenschaftlichen Fakultät möchte ich halt begründen können welchen Algorithmus ich verwende. Und das geht am besten in dem ich mehrere Miteinander vergleiche und dann den für das Projekt am besten geeignete Verwende. Damit ich allerdings vernünftige Vergleichsdaten generieren kann sollte ich die natürlich auch mal Implementiert haben. Bei einer BA ist es aber auch kein Problem zu sagen, dass die Algorithmen erstmal in ihrer Grundform verglichen werden. Und somit die Auswahl auf 2 beschränkt wird. die dann im weiteren Verlauf nochmal in Ihrer "verbesserten" Form verglichen werden.
    Das kann ich ja als "Ausblick" dann einbauen und muss ich nicht zwingend jetzt machen. Ich würde gerne folgende Algorithmen Vergleichen. 3D-Texture-Based-Volume-Rendering, Volume-Ray-Casting, Splatting, Shear-Warp, und den ansatz über die ISO-Oberfläche mittels Marching-Cubes.

    Falls die Zeit überhaupt nicht reicht wird das auch noch weiter eingegrenzt werden müssen.

    Ideal wäre natürlich literatur in der die Algorithmen mit Beispielhafter Implementiert erklärt werden. Bin nämlich noch nicht so der OpenGL guru und hab da so meine Probleme mit :D.
    In der Theorie hab ich die alle verstanden und könnte die im Kolloqium auch super bildlich erklären. Beim umsetzten mit OpenGL harkt es aber noch gewaltig =(...

    Daher ja auch meine Frage nach Hilfe was das betrifft ^^

    Lieben Gruß


  • Mod

    damit es nicht daran scheitert 🙂

    JangoK schrieb:

    Wie bestimme ich die bounding-Box um meine Textur?

    die darfst du frei bestimmen, von [0|0|0] bis [1|1|1] oder [-1|-1|-1] bis [1|1|1] oder ...

    am ende hat das keine absolute bedeutung. du koenntest natuerlich, falls du das weisst, die 'real world' ausmasse in cm oder mm oder so benutzen, dann koenntest du vermessungen anbieten oder sowas. aber auch mit einem einheitswuerfel hast du die moeglichkeit, musst du lediglich umrechnen.

    Wie berechne ich die Schichten auf die ich meine Textur ziehe aus dieser bounding-Box?

    ist das nicht die theorie von der du schon alles intus hast? oder ist das problem wie du es an opengl uebergibst?

    Ich habe einen Ansatz mit Marching-Cubes gefunden.
    Den verstehe ich aber auch nicht so ganz um ihn selbst nach implementieren zu können..

    http://www.vmg.cs.bangor.ac.uk/Papers/05CGGM.pdf

    z.B. was bedeuten die Zahlen im Index bei GL_MODELVIEWMATRIX und ...

    ich nehme an du meinst "Algorithm 1", die indices sind scheinbar die elemente der modelview matrix.
    es schaut aus als ob er in dem fall einfach nur die 8 ecken des cubes berechnet, dank modelview matrix ist das entsprechend im view space.

    danach zucht er sich minZ und maxZ im view space (also vorderste kante und hinterste kante.

    dann (in 1.) prueft er ob der jeweilige vertex fuer diesen slice vor oder nach dem slice ist.

    im anschluss generiert er dann davon abhaengig ein triangle fan das den sliece abdeckt.

    woher kommt diese magische Tabelle die auf all meine Probleme Lösungen bietet? ^^

    die tabelle ist das resultat des algorithms und vermutlich nur exemplarisch da, du erstellst sie implizit mit dem code.



  • Hi rapso =),

    rapso schrieb:

    Wie berechne ich die Schichten auf die ich meine Textur ziehe aus dieser bounding-Box?

    ist das nicht die theorie von der du schon alles intus hast? oder ist das problem wie du es an opengl uebergibst?

    Das Problem ist OpenGL und ich ;D. Teilweise aber auch die Mathematik dahinter.

    Ich weiß (jetzt, danke 😉 ), ich habe einen beliebigen Würfel, welchen ich als bounding-Box verwende. Ich verstehe allerdings noch nicht, wie ich das in openGL umsetzte. Reicht es die 8 Eckpunkte zu definieren? Oder muss ich Tatsächlich 12 Triangles definieren und an OpenGL übergeben als würde ich den Würfel rendern wollen?
    Die Rotation und andere Manipulationen führe ich dann auf den Würfel aus und durch die Texturierung später wird das automatisch umgesetzt? oder muss ich irgendwas beim Volume (also meiner 3D-Textur) berücksichtigen? (Ich denke da schon etwas weiter und überlege ob ich da was beim Volume-Ray-Casting wiederverwenden kann).
    Die Bestimmung des min und max punktes sollte theoretisch ganz einfach sein.
    Die ecke mit dem kleinsten z-Wert = min, die mit dem Größten = max.
    Die Frage ist, wie kriege ich den Abstand zur Cam, also dem Viewport bestimmt?
    Ich Multipliziere den Würfel so wie ich das verstanden habe mit der Viewmatrix,
    Aber wo passiert das ganze?
    Logischerweise muss das in der Rendering-Schleife passieren, da es ja immer wieder passieren muss wenn ich mit dem Würfel interagiere.
    Aber passiert es auf der CPU oder in einem Shader?
    Wenn auf der CPU, wie komme ich an mein Würfelobjekt, alles was ich habe ist doch eine BufferID? Oder arbeite ich immer auf dem Array was ich in den Buffer stecke? Werden dann Rotationen überhaupt sinnvoll abgespeichert?
    Wenn ich das dann irgendwann mal verstanden habe, ist es wohl auch ziemlich einfach alle punkte an der stelle z=sliceXY-distance darauf zu utnersuchen ob sie auf einer Kante liegen, also einen Eckpunkt darstellen.
    Dann ist es nur noch daran die Punkte so zu ordnen, dass ich einen Triangle-Fan malen kann und die Textur drauf ziehen kann. Ich denke das sollt ich dann wieder hin kriegen.
    Alternativ kann ich dazu dann auch den Algorithmus den ich verlinkt hatte und den du mir netter Weise erklärt hast verwendet und in die Tabelle schauen, die scheinbar aus den beiden Funktionen entsteht. Dann hab ich direkt eine Anordnung die zu einem Triangle-Fan passt.
    Am ende stand noch da, dass ich das Objekt vom Viewspace wieder in den Model-Space zurück bringen muss. Meines bescheidenen Mathematischen wissens nach müssten das mit der Inversen-Matrix der Viewmatrix gehen oder?
    Wie komm ich an die ran (falls ich recht hab ^^)?

    Wie gesagt, die Theorie habe ich denk ich verstanden.
    Mit der Umsetzung komm ich allerdings nicht so klar ^^.

    Gruß

    Jango



  • interessantes Thema. Es tut mir Leid wenn ich noch mal auf deine Theorien zurückkomme. Ist es nicht ein bisschen viel, alle aufgezählten Verfahren für eine BA Arbeit selber zu bauen? Ich war vor Jahren in ähnlicher Situation und hab es damals gelassen. Verstehe mich nicht falsch, ich will Dich ganz bestimmt nicht angreifen. Aber Du sagst ja selbst dass Du nicht so sattelfest in OpenGL und auch in der ganzen Mathematik dahinter bist. Ich kann mir vorstellen Du Dich da verrennst und wertvolle Zeit damit vergeudest diese Verfahren zu bauen.

    Wäre es nicht sinnvoller die Daten einfach mal ein einen bestehenden Dicom viewer zu laden, der alle Verfahren anbietet? Dann kannst Du die Ergebnisse immer noch validieren bezüglich Deiner Kriterien. Ich kann Dir zum Beispiel Osirix empfehlen. Da sind alle Verfahren drin und der Output ist bombig. Es basiert auch auf OpenGL und ist opensource. Das kostet für Deine Zwecks nichts und wenn am Ende ein Verfahren feststeht dass für die Visualisierung in dem Projekt verwendet werden soll, kannst Du das immer noch selbst bauen in Deiner Masterarbeit 😉 Aber dann nur das eine und in einer ordentlichen Qualität. Ich habe mittlerweile etliche Raycaster beispielsweise gesehen, die so schlechte Ergebnisse liefern, dass man denken kann das raycasting Verfahren ist an sich nicht gut.



  • Heyho Andiamo,

    ich bin dir nicht böse, eher dankbar für jede Meinung ;).
    Es ist auf jedenfall notwendig, dass am ende der Bacheloar-Arbeit ein verfahren implementiert ist.
    Das verlangt das Projekt von der BA.
    Und nur ein einziges zu implementieren basierend auf Resultaten einer Software könnte meinen Dozenten zu wenig Eigenleistung sein. Die Bachelor-Arbeit ist auf Grund der ganzen Rand-Kriterien wie Interpolation, Klassifizierung usw ohnehin schon recht Theoretisch.
    Ich denke schon, dass es machbar ist die Algorithmen in Ihrer "Grundfunktion" zu implementieren und abzusehen welche am ehesten für vor segmentierte Adern geeignet sind. Und falls nicht, wäre das auch ein mögliches Ergebnis der BA.

    Gruß

    EDIT:

    @ Rapso:

    Die Tabelle scheint nicht das resultat des Algorithmus zu sein, da sich der Algorithmus eine Zeile unter "1" auf die Tabelle bezieht. An der Stelle "T_key,0 != -1" ist mit T die Tabelle gemeint.



  • Ich nochmal, sorry für Doppelpost 😉

    Ich wollte eigentlich nur präsentieren wie ich es letztendlich (fast komplett) gelöst habe, falls jemand auf diesen Post stößt.

    Zunächst habe ich mir ein Array mit Eckpunkten der Bounding-Box definiert.

    // (Array deklaratoin in Header-Datei)
    	// Defenition der Eckpunkte
    	eckpunkte[0] = glm::vec4(-1, 1,-1, 1);
    	eckpunkte[1] = glm::vec4( 1, 1,-1, 1);
    	eckpunkte[2] = glm::vec4( 1,-1,-1, 1);
    	eckpunkte[3] = glm::vec4(-1,-1,-1, 1);
    	eckpunkte[4] = glm::vec4(-1, 1, 1, 1);
    	eckpunkte[5] = glm::vec4( 1, 1, 1, 1);
    	eckpunkte[6] = glm::vec4( 1,-1, 1, 1);
    	eckpunkte[7] = glm::vec4(-1,-1, 1, 1);
    

    Dann habe ich diese Eckpunkte mit meiner ModelView-Matrix verrechnet Um sie in den View-Space zu bringen. Um dies ohne weiteres zu können wurden die Daten auch in homogenen koordinaten angelegt (die 4te Komponente der Eckpunkte).

    glm::mat4 modelView = this->viewport->getCamera()->getViewMatrix() * this->modelMatrix;
    
    	for(int i = 0; i < 8; i ++) {
    		modelView * eckpunkte[i];
    	}
    

    Um nun zu bestimmen welches der Eckpunkte mit am nächsten an meinem View ist habe ich eine kleine minMax-Funktion geschrieben.

    void minMax(int *minIndex, int *maxIndex, glm::vec4 *arr, int arrSize) {
    	*minIndex = 0;
    	*maxIndex = 0;
    	for(int i = 1; i < arrSize; i ++) {
    		cout << arr[i][2] << endl;
    		if(arr[i][2] < arr[*minIndex][2])
    			*minIndex = i;
    		if(arr[i][2] >  arr[*maxIndex][2])
    			*maxIndex = i;
    	}
    }
    

    Jetzt laufe ich in einer Schleife von der Z-Position der als minIndex bestimmten ecke zur Z-Position der als maxIndex bestimmten Ecke.

    for(GLfloat z = min + stepSize; z <= max; z = z + stepSize) {	
    	// Schleife über alle Schichten
              ...
    

    In der Schleife möchte ich bestimmen auf welchen Kanten (also zwischen welchen 2 Ecken meiner Bounding-Box) sich die aktuelle Z-Schicht befindet.
    Dazu habe ich eine sehr einfache Funktion geschrieben, die gaaaaaanz sicher viel Optimierungspotential besitzt 😉

    void KLASSENNAME::getEdges(GLfloat zValue, int **edgeArray) {
    	int count = 0;
    	if(eckpunkte[0][2] <= zValue && eckpunkte[1][2] > zValue || eckpunkte[0][2] >= zValue && eckpunkte[1][2] < zValue) {
    		edgeArray[count][0] = 0;
    		edgeArray[count][1] = 1;
    		count++;
    	}
    	if(eckpunkte[1][2] <= zValue && eckpunkte[2][2] > zValue || eckpunkte[1][2] >= zValue && eckpunkte[2][2] < zValue) {
    		edgeArray[count][0] = 1;
    		edgeArray[count][1] = 2;
    		count++;
    	}
    	if(eckpunkte[2][2] <= zValue && eckpunkte[3][2] > zValue || eckpunkte[2][2] >= zValue && eckpunkte[3][2] < zValue) {
    		edgeArray[count][0] = 2;
    		edgeArray[count][1] = 3;
    		count++;
    	}
    	if(eckpunkte[0][2] <= zValue && eckpunkte[3][2] > zValue || eckpunkte[0][2] >= zValue && eckpunkte[3][2] < zValue) {
    		edgeArray[count][0] = 0;
    		edgeArray[count][1] = 3;
    		count++;
    	}
    	if(eckpunkte[4][2] <= zValue && eckpunkte[5][2] > zValue || eckpunkte[4][2] >= zValue && eckpunkte[5][2] < zValue) {
    		edgeArray[count][0] = 4;
    		edgeArray[count][1] = 5;
    		count++;
    	}
    	if(eckpunkte[5][2] <= zValue && eckpunkte[6][2] > zValue || eckpunkte[5][2] >= zValue && eckpunkte[6][2] < zValue) {
    		edgeArray[count][0] = 5;
    		edgeArray[count][1] = 6;
    		count++;
    	}
    	if(eckpunkte[6][2] <= zValue && eckpunkte[7][2] > zValue || eckpunkte[6][2] >= zValue && eckpunkte[7][2] < zValue) {
    		edgeArray[count][0] = 6;
    		edgeArray[count][1] = 7;
    		count++;
    	}
    	if(eckpunkte[4][2] <= zValue && eckpunkte[7][2] > zValue || eckpunkte[4][2] >= zValue && eckpunkte[7][2] < zValue) {
    		edgeArray[count][0] = 4;
    		edgeArray[count][1] = 7;
    		count++;
    	}
    	if(eckpunkte[0][2] <= zValue && eckpunkte[4][2] > zValue || eckpunkte[0][2] >= zValue && eckpunkte[4][2] < zValue) {
    		edgeArray[count][0] = 0;
    		edgeArray[count][1] = 4;
    		count++;
    	}
    	if(eckpunkte[5][2] <= zValue && eckpunkte[1][2] > zValue || eckpunkte[5][2] >= zValue && eckpunkte[1][2] < zValue) {
    		edgeArray[count][0] = 5;
    		edgeArray[count][1] = 1;
    		count++;
    	}
    	if(eckpunkte[2][2] <= zValue && eckpunkte[6][2] > zValue || eckpunkte[2][2] >= zValue && eckpunkte[6][2] < zValue) {
    		edgeArray[count][0] = 2;
    		edgeArray[count][1] = 6;
    		count++;
    	}
    	if(eckpunkte[3][2] <= zValue && eckpunkte[7][2] > zValue || eckpunkte[3][2] >= zValue && eckpunkte[7][2] < zValue) {
    		edgeArray[count][0] = 3;
    		edgeArray[count][1] = 7;
    		count++;
    	}
    
    }
    

    Auch hier wird wieder nur mit Indizes gearbeitet.

    Hab ich alle Kanten gefunden durchlaufe ich sie mit einer Inneren-Schleife.

    // edgeArray ist mit {-1, -1} vordefiniert, da -1 ein ungültiger Index ist.
    while(edgeArray[i][0] != -1) {
    

    Innerhalb dieser While-Schleife Berechne ich mit einer Geradengleichung die Position der X und Y koordinate auf der aktuellen Kante an position Z.

    // Bestimmung des Richtungsvektors der Gradengleichung von der aktuellen Kante
    			glm::vec4 r = eckpunkte[edgeArray[i][0]] - eckpunkte[edgeArray[i][1]];
    			// Bestimmen des Wertes der Variablen der Gradengleichung anhand der z-koordinate
    			double k = -eckpunkte[edgeArray[i][1]][2] / r[2];
    			// Bestimmung von x und y
    			GLfloat x = r[0] + k * eckpunkte[edgeArray[i][1]][0];
    			GLfloat y = r[1] + k * eckpunkte[edgeArray[i][1]][1];
    

    Alle so erstellten Vertices speicher ich in einer kleinen selbstgeschriebenen Struktur ab.

    struct VerticesAndAngles {
    	bool operator<(const VerticesAndAngles & vaa) { return this->angle < vaa.angle; }
    
    	glm::vec3 vertice;
    	double angle;
    };
    

    Wie man an der Struktur schon erkennen kann berechne ich den Winkel zwischen den Punkten um die Vertices in Umgekehrter Uhrzeiger-Reihenfolge zu sortieren.
    Das kann ich einfach so machen, da meine Schichten alle konvex sind.

    EDIT:

    Das zeichnen der Schichten mit OpenGL

    Ich sammle alle Schichten in einem vectorglm::vec3 und Multipliziere jeder mit der Invertierten ModelView-Matrix (um sie wieder aus dem View-Space zurück zu rechnen, da sie später mit der MVP multipliziert werden).
    Beim erzeugen habe ich mir in der Schleife über die schichten gemerkt, an welcher Stelle in meinem vector sie beginnen, und wie viele Vertices zu dieser Schicht gehören.

    // Innerhalb der Schleife über alle Schichten
    		for(i = 0; i < vaaVec.size(); i ++) {
    			glm::vec4 erg = glm::inverse(modelView) * glm::vec4(vaaVec[i].vertice, 1);
    			vertices.push_back(glm::vec3(erg.x,erg.y,erg.z));
    			uvw.push_back(glm::vec3((erg.x+1)/2,(erg.y+1)/2,(erg.z+1)/2));
    		}
    		if(sliceCount == 0) {
    			startValues[0] = 0;
    			amountOfVertices[0] = vertices.size();
    		}
    		else {
    			startValues[sliceCount] = startValues[sliceCount-1] + amountOfVertices[sliceCount-1];
    			amountOfVertices[sliceCount] = vaaVec.size();
    		}
    		sliceCount++;
    

    Nach dem ganzen Buffer-Binden usw gehe ich in einer Schleife über alle Schichten und rufe für jede Schicht ( also jeden Triangle-Fan den ich oben erzeugt habe) die glDrawArrays-Funktion auf.

    for(int i = 0; i < amountOfSlices; i ++) {
    		glDrawArrays(GL_TRIANGLE_FAN, startValues[i], amountOfVertices[i]);
    	}
    

    Die Werte die UVW's berechne ich mir ziemlich simpel. Da ich eine bounding-Box habe die von -1 bis 1 geht, und die UVW-Werte jeweils von 0-1 nehme ich einfach jeden x,y und z Wert eines Vertex, addiere ihn mit 1 und teile ihn daraufhin durch 2. So habe ich eine abbildung der Werte von -1 bis 1 auf die Werte 0 bis 1. Also eine Abbildung von xyz auf UVW. (Hab keine Ahnung ob das so klug ist, aber mirs nix besseres eingefallen und im Inet gefunden hab ich auch nix ^^).

    Das führt auch zu ganz guten Ergebnissen. (Würds posten, wenn ich wüsste wo gratis ich Bilder uploaden kann ^^)

    Jetzt muss ich nur nochn bisl mit dem Alpha-Blending rum spielen, da steig ich noch nicht so ganz durch.
    Und herausfinden warum sich eine Manipulationen der Model-Matrix nur auf meine Textur bezieht, nicht aber auf die Bounding-Box.

    Gruß

    Jango


Anmelden zum Antworten