Welches Genauigkeit von PI brauche ich für 3D-Grafik?



  • Ich schreibe eine kleine 3D-Engine von der Picke auf ohne Hardwareunterstützung, die halt auch mal eventuell auf verschiedenen Mikrocontrollern laufen soll. Es ist aber nur ein Lernprojekt und wird wahrscheinlich nie irgend jemanden nutzen. Wenn es meine Horizont für die 3D-Programmierung erweitert und ich durch dieses Projekt viel lernen kann, dann hat es sein Ziel schon erreicht.

    Ich möchte es in C aber auch in C++ umsetzen, um so auch beide Sprachen mal wirklich an einem mittleren Projekt in Aktion zu erleben.



  • Hmja, ich mein nur. Mir scheint 3D Grafik ohne FPU irgendwie witzlos zu sein. Wobei - für Rotationen macht es sogar irgendwie Sinn, bei 360° fängt man ja wieder von vorne an. Und jetzt, wo ich drüber nachdenke, macht es eigentlich auch für Positionen Sinn, schließlich will man ja eine gleichverteilte Präzision, und keine die relativ zum Nullpunkt immer schlechter wird. Kann mir mal jemand erklären warum wir floats für den Quatsch nutzen? 😃

    Lichtweite schrieb:

    Ich möchte es in C aber auch in C++ umsetzen, um so auch beide Sprachen mal wirklich an einem mittleren Projekt in Aktion zu erleben.

    Könnte interessant werden - allerding leider nur wenn du auch beide Sprachen gut beherrschst.



  • Lichtweite schrieb:

    Hi,

    PI wird ja heute bis auf Millionen von Stellen nach dem Komma berechnet, tatsächlich braucht es aber für die meisten Berechnungen nur recht wenige Stellen. Wie viele Stellen sind denn eurer Meinung nach für die Berechnung von 3D Grafik notwendig, also für Rotationen etc.?

    Wenn Du Berechnungen durchführst, spielt es keine Rolle, ob Du mit 3 rechnest, mit 3.14 oder einer Million Stellen. Eine Operation dauert so lange, wie eine Operation dauert. In ein Float oder Double passt eine gewisse Größe rein, nicht mehr. Nimmst Du weniger Stellen wird der Algorithmus nicht schneller. Willst Du mehr Stellen musst Du aufwendigere Geschichten fahren, das wird tierisch langsam. Das willst Du vermutlich auch nicht.

    Bei Winkeln wirst Du sowieso schnell merken, dass Ungenauigkeiten im Kreis mit dem Radius zusammenlaufen. Ein Winkel wird bei maximaler Genauigkeit durch den Radius schnell in einen kritischen Bereich multipliziert, so dass Du hier schnell in aus der Epsilontik läufst und Deine Ergebnisse genauso gut Würfeln kannst.

    Für die Frage gibt es also nur eine sinnvolle Antwort: Pack rein, was in Dein Register passt und hoffe dass es reicht. Dann wird es nämlich richtig interessant. ^^



  • @Xin Da er ja mit Festkommazahlen rechnet, wollte er wahrscheinlich wissen an welche Stelle er das Komma setzen soll - das ist ja nicht ganz klar auch bei gegebener Registergröße.



  • cooky451 schrieb:

    @Xin Da er ja mit Festkommazahlen rechnet, wollte er wahrscheinlich wissen an welche Stelle er das Komma setzen soll - das ist ja nicht ganz klar auch bei gegebener Registergröße.

    Double hat maximal 53 Nachkommastellen (binär). Das sind ca. 15 dezimale Stellen. Und das reicht nicht immer. Solange sich der Winkel im Bereich von 0 bis pi befindet, gehen vorne auch mal gleich 2 weitere Stellen verloren, bleiben also nur 51 binäre Stellen.

    Wie immer ist die Frage mit welchen Größen er arbeitet und wie er sie verrechnet.
    Vermutlich werden die Strecken weniger Nachkommastellen benötigen, als die Winkel, es stellt sich also schon die Frage, ob Winkel und Strecken mit dem gleichen Datentyp gespeichert werden sollten, weil sich das Komma an unterschiedlichen Punkten befindet, bzw. die Strecken und Winkel auf einen Wertebereich abgeglichen werden müssen.

    Diesen Abgleich macht man bei Fließkommazahlen mit dem Exponenten. Wenn man den einsparen kann, kann man natürlich größere Mantissen speichern. Dafür sollte bei Winkeln das Festkomma bei Bit 61 stehen. Die Strecken wird er aber vermutlich nicht im Bereich von -4.9 bis +4.9 halten wollen, dann würde ein Radius ihm auch kaum Probleme bereiten. 😉



  • Doch Sone, das meine ich Ernst, s. z.B. http://stackoverflow.com/questions/1727881/how-to-use-the-pi-constant-in-c
    Alternativ eben

    const double PI = acos(-1.0);
    

    Der Compiler kann es eben exakt ausrechnen mit maximalen Nachkommastellen (je Architektur).
    Natürlich nur sinnvoll, wenn Intrinsics aktiviert sind bzw. die Berechnung nur genau einmal am Anfang des Programms durchgeführt wird.

    Du kannst natürlich auch PI als Literal verwenden (3.14...). Aber entweder du gibst unnötigerweise zu viele Nachkommastellen an oder eben zu wenig. Wer weiß, vllt. gibt es in einigen Jahrzehnten den Datentyp 'double' mit 100 Nachkommastellen und dort steht dann nur PI = 3.14159265.
    Dann würde mein Programmcode trotzdem mit bestmöglicher Genauigkeit arbeiten und der mit dem festdefinierten Literal nicht.



  • Gut, ich sehe ein, das macht doch Sinn.



  • Nur vorsichtig sein wegen dem Typ. Wenn du mit float Werten rechnest, willst du auf jeden Fall pi auch als float definieren und auf keinen Fall als double. float und double willst du nicht nur aus rein ästhetischen Gründen auf keinen Fall vermischen, sondern vor allem auch, da der Compiler sonst gezwungen ist, langsamen Code zu produzieren, was du wohl vor allem in einem Software-Renderer vermeiden willst...

    Btw: Rotationswinkel kann man sehr elegant als Normalized Integer darstellen...



  • Th69 schrieb:

    Doch Sone, das meine ich Ernst, s. z.B. http://stackoverflow.com/questions/1727881/how-to-use-the-pi-constant-in-c
    Alternativ eben

    const double PI = acos(-1.0);
    

    Der Compiler kann es eben exakt ausrechnen mit maximalen Nachkommastellen (je Architektur).
    Natürlich nur sinnvoll, wenn Intrinsics aktiviert sind bzw. die Berechnung nur genau einmal am Anfang des Programms durchgeführt wird.

    Sorry, aber ich halte das auch für Unfug.
    Es ist zwar "sicher", in dem Sinn dass keine Fehler passieren werden, aber es kann unnötigerweise bremsen.
    Bzw. ich behaupte mal: es *wird* unnötigerweise bremsen. Mag sein dass einige Compiler schlau genug sind das optimieren zu können. Dem mit dem ich gerade arbeite (MSVC 2005) traue ich die Optimierung aber nicht zu.
    Und vor allem garantiert dir keiner dass es vom Compiler deiner Wahl *immer* korrekt optimiert wird.
    Irgendwann änderst du was und die Optimierung "bricht" und dann läuft dein Programm unnötiger weise langsamer.

    In den meisten Fällen wird es natürlich nicht viel ausmachen. Für Quatsch halte ich es trotzdem.



  • dot schrieb:

    Nur vorsichtig sein wegen dem Typ. Wenn du mit float Werten rechnest, willst du auf jeden Fall pi auch als float definieren und auf keinen Fall als double. float und double willst du nicht nur aus rein ästhetischen Gründen auf keinen Fall vermischen, sondern vor allem auch, da der Compiler sonst gezwungen ist, langsamen Code zu produzieren, was du wohl vor allem in einem Software-Renderer vermeiden willst...

    Btw: Rotationswinkel kann man sehr elegant als Normalized Integer darstellen...

    Danke, nettes Forum, habe mich gleich mal angemeldet.


  • Mod

    cooky451 schrieb:

    Hmja, ich mein nur. Mir scheint 3D Grafik ohne FPU irgendwie witzlos zu sein.

    sag nicht du hast nie eine playstation(1),nintendo ds gesehen:P, keine FPU, aber 3d Grafik ;). sehr viele software engines haben frueher rein mit int gerechnet, da float zu langsam war, selbst mit fpu, alleine float->int konvertierung, die du frueher oder spaeter machen musstest, war mit der masse an vertices bzw pixeln untragbar.

    weshalb wir float nutzen? ja, es ist an sich schlechter als int, aber man kann relativ gedankenfrei damit arbeiten. es stoesst schon an unsinn, wenn leute anfangen modelle als halfs zu speichern um platz zu sparen, statt short, aber naja...

    @Lichtweite
    man muss nicht nur eine genauigkeit festlegen. wenn ich auf so limitierten platformen arbeite(te), speichere ich meine modelle meistens mit 8bit 'genauigkeit' und um den bereich bestens auszunutzen, hab ich einen skalierungswert (auch 8 bit, der besagt wieviel geschiftet werden muss, wobei das ein signed wert ist).
    bei den ganzen transformationen nutze ich meistens 20:12 als genauigkeit, damit hab ich einen wertebereich von -512k bis +512k mit 1/4096 genauigkeit.
    nach dem clipping und projektion arbeite ich dann mit 12:20, das ist ein ausreichender wertebereich fuer sich wiederholende texturen (wrapping) und die genauigkeit ist gut genug um bei gross gezogenen polys noch eine smooth UV interpolation zu haben (z.b. bei terrain).

    graphikkarten haben etwa 48bit fixpoint zur interpolation von polys, das liegt an deren 'guard band' der dafuer sorgt, dass nicht geclippt werden muss (jedenfalls 'kaum'). davon ist die aufteilung, soweit ich weiss, 44:4, jedoch wird das nur zum evaluieren benutzt, ob ein pixel im oder ausserhalb vom dreieck liegt, wenn das erstmal feststeht, wird die pixelposition in float umgewandelt und spaeter damit interpoliert.



  • Danke für den interessanten Einblick, da sind Punkte bei über die ich mir noch gar keine Gedanke gemacht habe. Naja, meine Pipeline steht ja auch noch nicht.



  • rapso schrieb:

    sag nicht du hast nie eine playstation(1),nintendo ds gesehen:P

    Zu jung fürs eine und zu alt fürs andere. 🤡

    rapso schrieb:

    weshalb wir float nutzen? ja, es ist an sich schlechter als int, aber man kann relativ gedankenfrei damit arbeiten.

    Schon, aber würde es nicht viele Probleme lösen? Wenn man sich auf ein bestimmtes Festkommaformat einigen würde, wären zumindest mal alle Skalierungen gleich. Ich frage mich, ob ich mal versuchen soll in meinen Shadern mit ints zu rendern. Nur habe ich das Gefühl, dass die Grafikkarten dafür nicht wirklich optimiert sind, und das zieht sich dann wohl durch's ganze Programm, wenn man nicht irgendwo teuer umwandeln möchte. 😞



  • cooky451 schrieb:

    Nur habe ich das Gefühl, dass die Grafikkarten dafür nicht wirklich optimiert sind [...]

    Mit diesem Gefühl liegst du da richtig; für eine GPU ist float quasi der native Datentyp und alles andere wird (auf Shader Ebene) bestenfalls gleich schnell sein, in der Regel meist langsamer.

    Festkomma ist kein Ersatz für Gleitkomma und auch nicht umgekehrt. Beides hat völlig andere Vor- und Nachteile und je nach Anwendungsfall wird das eine oder das andere zu bevorzugen sein. Charakteristisch für Festkomma ist jedenfalls, dass es eben für Zahlen einer gewissen Größenordnung gedacht ist. Sich allgemein "auf ein Festkommaformat zu einigen" ginge rein prinzipiell am Sinn von Festkomma vorbei...



  • cooky451 schrieb:

    Wenn man sich auf ein bestimmtes Festkommaformat einigen würde, wären zumindest mal alle Skalierungen gleich.

    Ja, aber für die meisten wäre die Skalierung falsch. Wenn man mit Festkomma arbeitet, muss man für jede Variable entscheiden, wie die Skalierung aussehen soll. Die Skalierung gehört quasi zum Datentyp dazu.


  • Mod

    cooky451 schrieb:

    rapso schrieb:

    sag nicht du hast nie eine playstation(1),nintendo ds gesehen:P

    Zu jung fürs eine und zu alt fürs andere. 🤡

    rapso schrieb:

    weshalb wir float nutzen? ja, es ist an sich schlechter als int, aber man kann relativ gedankenfrei damit arbeiten.

    Schon, aber würde es nicht viele Probleme lösen? Wenn man sich auf ein bestimmtes Festkommaformat einigen würde, wären zumindest mal alle Skalierungen gleich.

    aber oben drueber schrieb ich, dass ich mich mit mir selber nicht auf nur ein format einigen konnte 😉

    Ich frage mich, ob ich mal versuchen soll in meinen Shadern mit ints zu rendern. Nur habe ich das Gefühl, dass die Grafikkarten dafür nicht wirklich optimiert sind, und das zieht sich dann wohl durch's ganze Programm, wenn man nicht irgendwo teuer umwandeln möchte. 😞

    DirectX 8 shader bzw texture stages (bzw register combiner) haben genau das gemacht. das war anfangs nichtmal definiert wie es sein sollte und je nach hardware bzw treiber waren die resultate dann unterschiedlich.
    geforce 3/4 hatten glaube ich 1:1:8 (vorzeichen,-1 bis +1 und 1/256 genauigkeit)
    GeforceFX hattae 1:2:9
    Radeon 8500 hatte 1:3:10
    geforce4MX hatte eine nicht standard kompilante emulation in software, und Nv hatte sich immer grosszuegig zeit mit dem fixen gelassen. 😡


  • Mod

    dot schrieb:

    Charakteristisch für Festkomma ist jedenfalls, dass es eben für Zahlen einer gewissen Größenordnung gedacht ist.

    das problem mit float ist, dass es gewissermassen auch so ist, es ist quasi ein fix point, dem man jedesmal mitgibt wie der wertebereich ist.
    bei statischen fix points muss man sich damit auseinander setzen, weil eine bereichsueber/unterschreitung zu fehlern fuerht. bei floats hat man hingegen grundsaetzlich einen viel kleineren bereich der sicher abgedeckt ist und wenn der bereich ueber-/unterschritten ist, wird der 'fehler' silent ignoriert und einfach die range angepasst.
    das sieht man nicht mit dem auge, aber es kann sein, dass sich irgendwelche physic objekte ploetzlich zueinander ueberschneident verhalten, nur weil man sie weiter vom zentrum der level bewegt hat.

    das lustige ist eigentlich, dass wissenschaftler mit floats (bzw eher mit doubles) genau so arbeiten wie graphikprogrammierer mit fix point gearbeitet haben. sie waehlen algorithmen oft danach aus (und implementieren sie so) dass der wertebereich nur einen gewissen maximalfehler hat. und fuer sie ist die genauigkeit von double so limitierend wie es bei graphik mit fixpoint ist.
    man simuliert eine galaxie und in dieser die einzelnen sternensysteme, bei deren entstehung ist es quasi bis runter zum staub den man simulieren will.

    hier gab es mal ein thread wie man ausrechnet wieviel flops eine funktion hat und manche haben es fuer nicht machbar gehalten alle operationen zu zaehlen, wissenschaftler gehen soweit die fehler anhand der operationen zu zaehlen 🙂 (was nicht nur die operationen sondern die reihenfolge der operationen und die zu erwartenen wertebereiche einzelner register miteinbezieht).

    fuer graphic/spiele sind floats einfach nur ein fire&forget weg, quasi das arithmetisch, was C#/java VMs fuer den speicher sind.
    bei fix point musste man sich gedanken machen
    bei float24 (z.b. radeon 9500) musste man noch alle objekte relativ zur kamera schieben
    bei float32 hat man nur noch bei weltraumspielen und bei speziallfaellen probleme (z.b. manchmal in physics wenn die schrittweite zu klein wird oder wenn man cascaded shadow maps macht und sie stabil halten will).


Anmelden zum Antworten