GDI3D - 3D auch ohne DirectX

    • Beta

    Es gibt 92 Antworten in diesem Thema. Der letzte Beitrag () ist von Quadsoft.

      GDI3D - 3D auch ohne DirectX

      Name der DLL:
      GDI3D oder auch Graphics3D

      Beschreibung:
      Da ich mich in der letzten Zeit wieder mal mit DirectX beschäftigt habe, mir aber das seitenlange coden, Errorhandling, OnLostDevicehandling, usw, usw, langsam auf den Senkel ging, habe ich mich nach einer Alternative umgeschaut, konnte aber kaum etwas brauchbares finden. Durch diesen Thread kam mir die Idee von GDI3D.

      GDI3D ist eine Klassenbibliothek, mit der man schnell und einfach 3D zeichnen kann - mit GDI.
      Dazu können alle möglichen sogenannte Meshes (also Drahtgittermodelle) aus Dateien geladen werden.
      Das (zur Zeit einzige) unterstützte Dateiformat ist das *Obj-Format von Wavefront. Nahezu jede Modeller-Software (auch Blender!) kann dieses Format exportieren.

      Was mich selbst überrascht hat, ist die relativ hohe Performance von GDI. Erst ab etwa 5000 Polygonen pro Frame, kommt es bei mir zum leichten Ruckeln.

      Open Source!

      Anwendung:
      GDI3D lässt sich leicht integrieren.
      Wichtig sind jedoch folgende Schritte:
      • Instanziierung der Graphics3D-Klasse und Übergabe der Zeichengröße
      • Festlegen der World-, View-, und Projection-Matrizen (wer schon einmal mit DX gearbeitet hat, sollte das kennen)

      Und schon kann es losgehen. Hier ein Beispiel-Code zum zeichnen eines Meshes, das aus einer Datei geladen wurde, in die gesamte Form "Form1":

      Spoiler anzeigen

      VB.NET-Quellcode

      1. Imports GDI3D
      2. Public Class Form1
      3. Private Sample_Graphics As Graphics3D
      4. Private Sample_Mesh As Mesh
      5. Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
      6. Me.SetStyle(ControlStyles.AllPaintingInWmPaint Or ControlStyles.OptimizedDoubleBuffer, True)
      7. ' Das Mesh wird geladen
      8. Sample_Mesh = Mesh.FromFile("C:\Dokumente und Einstellungen\Lukas\Desktop\untitled3.obj")
      9. ' Initialisierung der Graphics3D-Instanz und der Matrizen
      10. Sample_Graphics = New Graphics3D(Me.ClientSize)
      11. Sample_Graphics.Transform_World = Matrix.Identity
      12. Sample_Graphics.Transform_View = Matrix.Translation(0, 0, -5)
      13. Sample_Graphics.Transform_Projection = Matrix.Projection(Math.PI / 4, Me.ClientSize.Width / Me.ClientSize.Height, 0.1, 1000)
      14. End Sub
      15. Private Sub Form1_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles Me.Paint
      16. ' Das Mesh soll sich um die Y-Achse drehen (Wichtig: Die Winkel sind in Radiant anzugeben)
      17. Sample_Graphics.Transform_World = Matrix.Rotate_Y_Axis(Now.Millisecond * (Math.PI * 2) / 1000)
      18. ' Das Mesh wird gezeichnet
      19. Sample_Graphics.Draw_Mesh(e.Graphics, Sample_Mesh, Color.FromArgb(240, 100, 20), GDI3D.Graphics3D.DrawMode.Fill Or GDI3D.Graphics3D.DrawMode.Wireframe)
      20. Me.Invalidate()
      21. End Sub
      22. Private Sub Form1_Resize(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Resize
      23. ' Da sich nun das Sichtfenster verändert hat, muss auch die Zeichenfläche und
      24. ' das Seitenverhältnis der Projektion verändert werden
      25. If Sample_Graphics IsNot Nothing Then
      26. Sample_Graphics.Bounds = Me.ClientSize
      27. Sample_Graphics.Transform_Projection = Matrix.Projection(Math.PI / 4, Me.ClientSize.Width / Me.ClientSize.Height, 0.1, 1000)
      28. End If
      29. End Sub
      30. End Class


      Screenshot und Video:

      Und hier noch ein tolles Video. :D


      Verwendete Programmiersprache:
      VB.Net

      Systemanforderungen:
      • .NET Framework 2.0
      • Es ist keine DirectX-Runtime nötig.

      Lizenz:
      LGPL ;)

      Download:
      GDI3D Release (10 KB)
      Source-Code-Projekt (30 KB)

      Beispiel OBJ-Mesh (45 KB)

      Demo-Projekt

      Viel Spaß! :)

      Dieser Beitrag wurde bereits 7 mal editiert, zuletzt von „nikeee13“ ()

      WTF!

      Ich bin beeindruckt...
      Kann man stark vereinfacht sagen, dass du quasi einen Algorithmus entwickelt hast, der die Koordinaten der einzelnen Polygonen in X|Y-Koordinaten umwandelt,
      und diese dann mit Regions/Paths zeichnet?

      Ich kann mir echt nicht vorstellen wie du das gemacht hast.
      Auf jeden Fall weiter so!

      mfg vredesbyrD
      Impressive.

      Echt sehr geil, habs mir aus Interesse mal ganz kurz grade angeschaut. Es sieht echt gut aus..
      Wenn ich Zeit habe, werde ich mir den Source auf jedenfall näher anschauen und versuchen nachzuvollziehen, wie du das gemacht hast.
      Das Dateiformat .obj und dessen Aufbau ist mir leider komplett unbekannt...

      In jedem Fall 5 sterne ;)
      Das ist meine Signatur und sie wird wunderbar sein!
      Das ist ja wahnsinn! Ehrlich gesagt hatte ich auch die Idee, habs aber sein lassen. Ey: Du bist heute schon an einem Tag auf Platz 1 in Libraries/Controls gerutscht :thumbsup:

      Natürlich 5 Sterne, auch wenn ich nicht weiß, ob ichs benutzen werde :thumbsup:
      Wow!! Vielen Dank für die guten Kritiken.
      Hätte niemals gedacht, dass das so vielen hier gefällt. :)


      Ich werde auf jeden Fall daran weiter arbeiten. Falls es dann bald stabil ist gibt's auch den Sourcecode.
      Eine Doku dazu wird auch kommen.

      Zuerst aber:
      - Vielleicht ist das jemanden schon aufgefallen, dass es kein "Tiefensortierung" (also kein Z-Buffer) gibt. Das heißt, die Polygone werden nacheinander, so wie sie im Mesh angeordnet sind, gezeichnet.
      Daher kann es dazu kommen, dass ein Polygon, das eigentlich verdeckt sein müsste, über ein vorderes Polygon gezeichnet wird. Das sieht sehr unrealistisch aus (zB hier).

      Daher werde ich ein Z-Buffer einbauen.

      - Ein weiteres Manko ist, dass zur Zeit nur mit einer Farbe gezeichnet werden kann. Langweilig...
      Damit sich das ändert kommt gegebenenfalls programmierbare Pixel- und Vertex-Shader hinzu, um für jeden Pixel einen Farbwert zu errechnen.
      Somit sind Schatten, Texturen und alle möglichen Materialien möglich.
      Ich hoffe mal, dass ich das hinkriege und die GDI-Performance dabei nicht den Bach herunterläuft.

      - Das Laden von Obj-Files ist ein wenig fehlerhaft. Cinema4D beispielsweise exportiert irgendwie anders. Mal schauen.

      Ich freue mich über jeden Vorschlag. ^^




      So zur Technik:
      Wie ich oben schon beschrieben habe, läuft alles wie auf Grafikkartenebene bei DX ab.
      Ein Mesh besteht aus einer Liste von Vertices, also Raumpunkten. Jeweils 3 Vertices spannen ein Polygon bzw. Dreieck im Raum auf.

      Für jeden Vertex eines Dreiecks passiert nun folgendes:
      • Der Vertex ist ein 4-D-Vektor. Die ersten 3 Koordinaten sind die Raumpunkte. Die 4 Koordinate, also "w" ist immer 1.
      Der Vektor wird mit der World-, dann der View- und dann der Projektions -Matrix multipliziert. Alle diese Matrizen sind ebenso 4-dimensionale Matrizen. In ihnen stecken die Informationen über Verschiebung, Rotation, Projektionsmethode usw.
      • Der resultierende Vektor besitzt wieder 4 Koordinaten. Zur Vervollständigung unser Berechnung müssen nun xdie ersten 3 Koordinaten durch die 4. Koordinate geteilt werden.
      Der ersten beiden Koordinaten sind jetzt die fertig projezierten 2-D-Koordinaten des Vertex. Die 3. gibt Asukunft darüber, wie weit der Vertex weg ist.

      Hier noch ein genauerer Artikel.

      ich schätze mal, dass das ganze auf Eulerscher Rotation basiert.
      Die Drehung im Raum beruht auf dieser Methode, ja. ^^
      und diese dann mit Regions/Paths zeichnet?
      Zur Zeit wird alles mit mit FillPolygon und DrawPolygon gezeichnet.




      Und hier noch ein Obj-Modell. Vor allem hier ist zu sehen, dass ein z-Buffer nötig ist.
      Dateien
      • Obj-Modell.zip

        (43,62 kB, 466 mal heruntergeladen, zuletzt: )

      Lapdogs schrieb:

      Bei mir kommt leider eine Felermeldung beim Testen:

      "Fehler beim Erstellen des Formulars. Weitere Informationen finden Sie in Exception.InnerException. Fehler: Der Objektverweis wurde nicht auf eine Objektinstanz festgelegt.."

      PS: Das ist wohl einer der besten (oder das beste?) Libary :)

      Der besten Library? Nein ganz sicher nicht. Das beste Library? Auch nicht. Die beste Library - ja genau.
      Einer der besten Librarys passt wohl noch besser zu deinem Satz.
      PS: Soll kein Angriff u.a. sein
      Auch wenn ich jetzt eigentlich erwartet hätte du sagst das ist einer der bekanntesten Fehlermeldungen.


      @Topic
      Ahh, sowas hatte ich auch schonmal vor. Leider konnte man keine .obj Dateien nutzen. Kann mir sogar genau Vorstellen wie du das gemacht hast.
      PS: Falls noch nicht gemacht - nutzt ein Protector.
      Entweder ich bin zu blöd den Link zum Video zu sehen oder es gibt irgendwie keinen 8|

      btw: Schaut super aus ;)
      Meine neue Homepage: pkern.at
      Wetter bei mir zu Haus: