3D mit GDI+ (A3D.au3)

  • Moin,

    Edit: Ich poste hier ab und zu mal neue Versionen, selbst wenn es keinen interessiert hat man hier einen Überblick über den Werdegang :)

    vor einiger Zeit wollte ich mal einen Asteroidengenerator basteln (der kleine Bildchen für ein Spiel generiert). Irgendwie bin ich dann auf die Idee gekommen, dass man das doch in 3D machen könnte. Im EN Forum habe ich dazu die S3d.au3 (von Starg, 2014) gefunden, die 22KB leicht ist und keine externen Libs verwendet. Die hat mir aber von der Handhabung her nicht gefallen, sie diente aber als Inspirationsquelle.

    Das Folgende ist maximal eine Alpha-Phase, nicht mehr als ein kleiner Test bei dem die halbe Funktionalität fehlt. S3d ist vom Umfang her ein Stück besser (hier gibt es z.B. auch eine mobile Kamera und vielseitigere Zeichenwerkzeuge), in meiner UDF geht es mehr um die Anzeige von Geometrien (z.B. eine Kugel die durch Deformation & Farbe in einen Asteroiden verwandelt wird ;) Soweit bin ich aber noch nicht)

    Zum Ausprobieren -> Ordner entpacken und die Test.au3 aufrufen. Ich habe alle Dateien im Ordner so gelassen wie sie sind und nicht aufgeräumt, wenn jemand stöbern möchte, nur zu :)

    Edit: v28.12.22:

    - Performance wurde um ca. 20% erhöht (erforderte quasi komplettes Umschreiben von allem)

    - Primitives Parallel Light hinzugefügt (eine Lichtquelle, Weiß, Parallel (unendlich weit weg)), Dadurch ging die Performance wieder um 20% runter :rofl:

    - Grundstein für "beliebige" Polygone gelegt (es soll neben Triangles und Quads auch andere Polygone geben. Ein Pentagondodekaeder sollte nativ gezeichnet werden können. Kann ja wohl nicht angehen, dass man den triangulieren muss, dabei ist er so schön)

    - Oktaeder zur Geometrie hinzugefügt

    Edit: v26.01.23:

    - Die Beleuchtung wurde wieder entfernt (die Berechnung war doof gelöst. Das wird zukünftig als "statische" und "dynamische" Beleuchtung getrennt berechnet). Die Statische kann man nämlich auslagern und nur 1x berechnen, während man die dynamische in jedem Frame erneut berechnen muss.

    - Jetzt sind "alle" möglichen geometrischen Formen die aus Punkten und Polygonen (egal wie viele Punkte pro Polygon) unterstützt. Mein lieblings Pentagondodekaeder ist endlich mit von der Partie.

    - Culling hinzugefügt für Objekte die außerhalb sind.

    - Eine Kamera gibts jetzt auch (aber nur eine sehr rudimentäre, keine frei fliegende und beim Culling sind hier noch Bugs wenn man unter bestimmten Winkeln auf Objekte schaut, oder zu nah dran ist. Dann sieht man ggf. die Rückseite)

    - Quasi alle Algorithmen neu geschrieben. Sie sind nicht wirklich optimiert, haben jetzt aber besseres Optimierungspotential.

    - Code aufgeräumt (sofern man diese Baustelle aus "aufgeräumt" bezeichnen will)
    - In der Demo vom 26.01.23 -> Test.au3 starten und mit der linken Maustaste um xy und mit der rechten in um z drehen.

    Test3.gif

    (edit: Das ist ein Bild, keine Ahnung warum hier das Vorschau einfügen nicht funktioniert)

    Edit v30.01.23:

    - Aufräumen (im Prinzip sollte "alles" in Linalg.au3 integriert werden was gebraucht wird, sonst hat man 3 Includes nur für Mathe)

    - Test1 und Test2 sind jetzt 2 Beispiele. Das 2te ist mein geliebter Planetengenerator (bzw. ein Beispiel für eine bunte deformierte Kugel... der Grund für alles hier :D)

    - In Test2 wird eine gebastelte Steuerung verwendet die kein Y-Lock hat (Rotation um freie Achse, statt eine Achse des Koordinatensystems.).

    )

    lg

    M

  • Mars 26. Januar 2023 um 20:48

    Hat den Titel des Themas von „3D Herumgebastel (A3D?)“ zu „Natives 3D mit GDI+ (A3D.au3)“ geändert.
  • Habe zwar keine Ahnung was ihr hier macht, fragt sich aber, ob man die Flächen mit Fotos "bekleben" kann?
    Wäre doch eine lustige Präsentation für Bilder. :Glaskugel: Hast Du eine Kugel mit Bild, hast Du dann eine z. B. Weihnachtskugel. Kommt dann doch auf das Bild an.

    Okay, bin wieder weg.

    Lieben Gruß,
    Alina

    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    Geheime Information: ;)
    OuBVU5ebLhHu5QvlnAyQB4A7SzBrvWulwL7RLl2BdH5tI6sIYspeMKeXMSXl

  • Zunächst einmal Mars....sehr schön!

    Wieder ein Mitglied im Bereich "Brotlose Kunst" ( :theke: für die Insider 8o )

    GDI+ wird leider das Speed Limit bleiben...

    Das ist sicher richtig.... aber:

    Wie so oft, sind die Berechnungen innerhalb der Schleifen der Geschwindigkeitstechnische "Supergau" bei AutoIt.

    Profiling des Scriptes hat bei mir (4 FPS) ergeben:

    - In der While-Schleife liegen die Zeiten der Zeilen bis zu Draw($Sphere) bei je 1ms, also (zunächst) unerheblich.

    - Draw($Sphere) bzw. die eigentliche Funktion __A3D_GeometryDraw() dauert 150ms, davon ca. 30ms in der ersten For/Next, bei der ausschließlich bissl addiert und subtrahiert wird.

    Die anderen 120ms werden in der zweiten For/Next "verbraten" in der, man mag es kaum glauben, auch nur bissl addiert wird. In der Summe mit den kaskadierenden OR´s je CASE ist das für einen Interpreter der schon angesprochene Supergau...

    - In der Funktion _A3D_EndScene() dauert die erste verschachtelte For/Next 85ms, bei der ausschließlich bissl addiert und dividiert wird.

    In der zweiten For/Next (mit den CASE) werden in 60ms ca.1900 Schleifendurchgänge mit jeweils ZWEI GDI(+)-Funktionen aufgerufen. Also SO schlecht ist da GDI nicht!!


    Zusammengefasst:

    Das was das Script so "langsam" macht, sind (wie so oft) die Berechnungen innerhalb der Schleifen.

    Es lohnt sich also definitiv, diese Berechnungen auszulagern, bspw. in eine DLL.

    Ich reite jetzt bestimmt nicht wieder auf Assembler rum ( Mars bekäme das sicher auch mit AVE/SSE unter Ausreizung aller vom Prozessor verfügbaren Möglichkeiten incl. Multithreating (das auch in AutoIt!) hin), aber jeder beliebige Compiler schafft die Berechnungen heutzutage mit mindestens dem Faktor 1000 schneller! UEZ würde da FreeBasic nutzen!

    Also mal angenommen, die o.g. Berechnungs-Schleifen würden in Summe je 1ms brauchen (also vernachlässigbar), dann bleiben je Haupt-Schleifendurchlauf die 60ms für die 3800 GDI-Funktions-Aufrufe. Ob DAS ein Compiler auch nur Faktor 5-10 schneller macht, wage ich zu bezweifeln! Aber Versuch macht kluch!

    Letztendlich führen die in einen Assembler/Compiler ausgelagerten Berechnungs-Funktionen zu einer Beschleunigung des Scripts um ca. Faktor 3-4, bei mir würden da doch ansprechende 15FPS rauskommen. Und zwar UNABHÄNGIG von der Anzahl der Polygone!

    Das Script komplett 1:1 in FreeBasic umgesetzt schätze ich mal erreichbare 25-30FPS mit GDI(+). Die Verwendung von D3D wäre allerdings, abhhängig von der Grafikkarte, unendlich viel schneller....

    Fazit:

    Die "brotlose Kunst" ist LEIDER nicht die Stärke von AutoIt, um aber mal fix bissl Grafikgedöns hinzuzaubern, immer gut :P .

    Daher :thumbup:

  • Ich glaube aktuell gehen ca. 20% der Zeit für simples "kopieren" (in EndScene, wenn die Structs befüllt werden), 20% für GDI+ und 50% für Matrixmultiplikationen und simple Mathematik und 10% fürs z-Buffer Sortieren drauf (bei "einem sehr großen Modell"). Gestoppt habe ich das nicht, ist nur eine Vermutung...

    Mir fallen auf anhieb einige stellen ein die man etwas aufbohen kann, wenn man eine dll oder asm nutzt, aber ich will erstmal schauen was man ohne diese Hilfsmittel rausholen kann. Klar in OpenGL eine primitiv beleuchtete Kugel mit 5000 Triangles anzuzeigen ist keine Kunst, in AutoIt ohne Hilfsmittel macht es deutlich mehr Spaß sowas zu machen :D

    Die vielen kaskardierten ORs sind doch eigentlich "der schnelle" Weg in AutoIt, oder? Einziges Problem in Test2 ist, dass meistens alle Vertices okay sind und daher die ersten 3 ORs nicht anschlagen können.

    Ein paar inner loops sind doof gelöst weil dort eigentlich nur der Mittelpunkt berechnet wird (z.B. in EndEscene -> Mittelpunkte berechnen & Sortieren), das kann man doppelt so schnell anderweitig lösen, oder 5x so schnell approximativ^^

    Im Lauf der Zeit hol ich nativ noch 20% performance raus... Dann schaue ich ob ich einige kritische Teile via inlineasm lösen kann. Und DANN baue ich einen "richtigen" Kugelgenerator (mit GUI und ganz vielen Slidern, sodass man nicht mehr von Hand im Code arbeiten muss wenn man seine Kugel designen will).

    M

  • Mars 31. Januar 2023 um 12:09

    Hat den Titel des Themas von „Natives 3D mit GDI+ (A3D.au3)“ zu „3D mit GDI+ (A3D.au3)“ geändert.
  • aber ich will erstmal schauen was man ohne diese Hilfsmittel rausholen kann.

    Hatte ich oben ja bereits beschrieben....gesetzt den Fall, du optimierst die Schleifen auf die Hälfte der Zeit, das GDI-Gedöns beschleunigst du nicht. Da werden dann aus 4 FPS wegen mir 8 FPS...?!

    Allerdings ist JEDE Optimierung im noch so langsamen Code eine Verbesserung in der Ablaufgeschwindigkeit, und schlägt somit voll auch bei einer ggf. compilierten Variante durch!

    Wenn du deinen Code "schnell" machst, dann ist auch das Programm "schnell", SO zum Beispiel...

    Ein paar inner loops sind doof gelöst weil dort eigentlich nur der Mittelpunkt berechnet wird (z.B. in EndEscene -> Mittelpunkte berechnen & Sortieren), das kann man doppelt so schnell anderweitig lösen, oder 5x so schnell approximativ^^

    ...was aber (im Bezug auf AutoIt! )den Kohl auch nicht wirklich fett macht^^ :D

    Und DANN baue ich einen "richtigen" Kugelgenerator (mit GUI und ganz vielen Slidern, sodass man nicht mehr von Hand im Code arbeiten muss wenn man seine Kugel designen will).

    Mach das doch mal zuerst! Ich vermute, auf dem Weg dahin findet sich die eine oder andere Verbesserung ganz automatisch ein, weiterhin findet sich bestimmt jemand (sic), der für die Berechnungen hochperformanten SSE/AVX-Code (dafür gibts in C(++) die intrinsics(!) ) basteln könnte....ich mein ja nur.... :Glaskugel::rofl: