Zeichne eine Kugel mit 3D-Pixeln (Voxel)

8

Können Sie einen Algorithmus vorschlagen, der eine Kugel im 3D-Raum zeichnen kann, indem nur das Basiselement plot(x,y,z) verwendet wird (das ein einzelnes Voxel zeichnen würde)?

Ich hatte auf etwas gehofft, das dem Kreis-Algorithmus von Bresenham ähnlich ist, aber für 3D statt für 2D.

Zu Ihrer Information: Ich arbeite an einem Hardwareprojekt, das eine 3D-Anzeige mit niedriger Auflösung unter Verwendung einer dreidimensionalen Matrix von LEDs ist, also muss ich tatsächlich eine Kugel zeichnen, nicht nur eine 2D-Projektion (dh einen Kreis) / p>

Das Projekt ist dem sehr ähnlich:

... oder sehen Sie es in Aktion hier .

>

Eine Möglichkeit, die mir in den Sinn kommt, ist diese:

  • berechne die Y-Koordinaten der Pole (gegeben durch den Radius) (für eine Kugel, die im Ursprung zentriert ist, wären dies -r und +r )
  • Zerschneide die Kugel: Berechne für jede horizontale Ebene p i zwischen diesen Koordinaten den Radius des Kreises, der durch Schneiden der Ebene mit der Kugel erhalten wird = & gt; r i .
  • Zeichnen Sie den tatsächlichen Kreis des Radius r i in der Ebene p i mit Hilfe des Bresenham-Algorithmus.

FWIW, ich benutze einen .NET Micro-Framework-Mikroprozessor , also programmieren ist C #, aber ich brauche keine Antworten in C #.

    
Cristi Diaconescu 31.01.2012, 17:35
quelle

4 Antworten

7

Die einfache Brute-Force-Methode besteht darin, jedes Voxel im Gitter zu durchlaufen und seinen Abstand vom Kugelzentrum zu berechnen. Dann färben Sie das Voxel, wenn sein Abstand kleiner als der Kugelradius ist. Sie können viele Anweisungen speichern, indem Sie die Quadratwurzel entfernen und das Skalarprodukt mit dem Radius im Quadrat vergleichen.

Ziemlich weit von optimal, sicher. Aber auf einem 8x8x8 Raster, wie gezeigt, müssen Sie diese Operation 512 Mal pro Kugel durchführen. Wenn sich das Kugelzentrum auf dem Gitter befindet und sein Radius eine ganze Zahl ist, benötigen Sie nur Ganzzahlmathematik. Das Skalarprodukt besteht aus 3 Multiplikationen und 2 Additionen. Multiplikationen sind langsam; Nehmen wir an, sie nehmen jeweils 4 Anweisungen. Plus brauchen Sie einen Vergleich. Addieren Sie die Lasten und speichert, sagen wir, es kostet 20 Anweisungen pro Voxel. Das sind 10240 Anweisungen pro Kugel.

Ein Arduino mit 16 MHz könnte 1562 Kugeln pro Sekunde drücken. Es sei denn, Sie tun Tonnen anderer Mathematik und I / O, sollte dieser Algorithmus gut genug sein.

    
japreiss 31.01.2012 17:54
quelle
4

Angenommen, Sie haben bereits eine Plotfunktion wie Sie gesagt haben:

%Vor%

Diese Funktion sollte eine Kugel im Ursprung mit der angegebenen Breiten- und Längenauflösung darstellen (nach Ihrem Würfel schätzen Sie wahrscheinlich etwas um 40 oder 50 als grobe Schätzung). Dieser Algorithmus "füllt" die Sphäre jedoch nicht, so dass er nur einen Umriss liefert, aber wenn Sie mit dem Radius spielen, sollten Sie das Innere füllen, wahrscheinlich mit abnehmender Auflösung der Lats und Longs auf dem Weg.

    
NominSim 31.01.2012 17:55
quelle
3

Ich glaube nicht, dass das Ausführen des Mittelpunktskreisalgorithmus auf jeder Ebene die gewünschten Ergebnisse liefert, sobald Sie die Pole erreicht haben, da Sie Lücken in der Oberfläche haben werden, wo LEDs nicht leuchten. Dies kann jedoch zu dem gewünschten Ergebnis führen, was der Ästhetik entspricht. Dieser Beitrag basiert auf der Verwendung des Mittelpunktskreisalgorithmus, um den Radius der Schichten durch die mittleren zwei vertikalen Oktanten zu bestimmen, und dann, wenn jeder dieser Kreise gezeichnet wird, werden auch die Punkte für die polaren Oktanten festgelegt.

Ich denke, basierend auf @Nick Udalls Kommentar und Antwort hier mit dem Kreis-Algorithmus, um den Radius Ihrer horizontalen Scheibe zu bestimmen, funktioniert mit einer Änderung, die ich in einem Kommentar zu seiner Antwort vorgeschlagen habe. Der Kreis-Algorithmus sollte modifiziert werden, um als Eingabe einen anfänglichen Fehler zu nehmen, und auch die zusätzlichen Punkte für die polaren Oktanten zu zeichnen.

  • Zeichnen Sie die Standard-Kreisalgorithmuspunkte bei y0 + y1 und y0 - y1 : x0 +/- x, z0 +/- z, y0 +/- y1 , x0 +/- z, z0 +/- x, y0 +/- y1 , insgesamt 16 Punkte. Dies bildet den größten Teil der Vertikalen der Kugel.
  • Zeichnen Sie zusätzlich die Punkte x0 +/- y1, z0 +/- x, y0 +/- z und x0 +/- x, z0 +/- y1, y0 +/- z , insgesamt 16 Punkte, die die Polarkappen für die Kugel bilden.

Indem der Fehler des äußeren Algorithmus in den Kreisalgorithmus übernommen wird, wird eine Untervoxelanpassung des Kreises jeder Ebene ermöglicht. Ohne den Fehler in den inneren Algorithmus zu überführen, wird der Äquator des Kreises einem Zylinder angenähert, und jede approximierte Kugelfläche auf der x-, y- und z-Achse wird ein Quadrat bilden. Wenn der Fehler enthalten ist, wird jede Fläche mit einem genügend großen Radius als gefüllter Kreis angenähert.

Der folgende Code wurde aus Wikipedia's Mittelpunkt-Kreisalgorithmus geändert. Der DrawCircle -Algorithmus hat die Nomenklatur geändert, um in der xz-Ebene zu arbeiten, wobei der dritte Anfangspunkt y0 , der y-Offset y1 und der Anfangsfehler error0 hinzugefügt werden. DrawSphere wurde von derselben Funktion geändert, um den dritten Anfangspunkt y0 zu erhalten, und ruft DrawCircle anstatt DrawPixel

auf %Vor%

Für eine Kugel mit Radius 4 (die tatsächlich 9x9x9 erfordert) würde dies drei Iterationen der Routine DrawCircle ausführen, wobei die erste Zeichnung einen typischen Radius 4 Kreis (drei Schritte), die zweite Zeichnung einen Radius 4 Kreis mit Anfangsfehler von 0 (auch drei Schritte), und dann die dritte Zeichnung ein Radius 3 Kreis mit Anfangsfehler 0 (auch drei Schritte). Das ergibt neun berechnete Punkte, die jeweils 32 Pixel ziehen. Das ergibt 32 (Punkte pro Kreis) x 3 (Addieren oder Subtrahieren von Operationen pro Punkt) + 6 (Addieren, Subtrahieren, Verschiebeoperationen pro Iteration) = 102 Addieren, Subtrahieren oder Verschieben pro berechnetem Punkt. In diesem Beispiel sind das 3 Punkte für jeden Kreis = 306 Operationen pro Ebene. Der Radiusalgorithmus fügt auch 6 Operationen pro Schicht hinzu und iteriert dreimal, also 306 + 6 * 3 = 936 Grundrechenarten für den Beispielradius von 4. Die Kosten hier sind, dass Sie einige Pixel ohne zusätzliche Zustandsprüfungen (d. H. X = 0, y = 0 oder z = 0) wiederholt setzen, also wenn Sie Ihre I / O langsam ist, können Sie die Bedingungsprüfungen besser hinzufügen. Unter der Annahme, dass alle LEDs beim Start gelöscht wurden, würde der Beispielkreis 288 LEDs setzen, während es viel weniger LEDs gibt, die aufgrund von Wiederholungssätzen tatsächlich leuchten würden.

Es sieht so aus, als würde dies für alle Kugeln, die in das Raster 8x8x8 passen, besser sein als die Bruteforce-Methode, aber die Bruteforce-Methode hätte unabhängig vom Radius ein konsistentes Timing, während diese Methode beim Zeichnen von Sphären mit großem Radius langsamer wird Teil wird angezeigt. Wenn die Auflösung des Anzeigewürfels zunimmt, bleibt dieser Algorithmus jedoch konstant, während Bruteforce zunimmt.

    
rjp 04.12.2013 20:38
quelle
1

Ich habe gerade ein altes q & amp; a über die Erzeugung eines Sphere Mesh gefunden, aber die oberste Antwort gibt dir einen kurzen Pseudo-Code, um dein X, Y und Z zu generieren:

(x, y, z) = (sin(Pi * m/M) cos(2Pi * n/N), sin(Pi * m/M) sin(2Pi * n/N), cos(Pi * m/M))

Überprüfen Sie dieses Q & A für Details :) generieren Sie prozesstechnisch ein Kugelgitter

    
Kotch 31.01.2012 18:24
quelle