Fließkommazahlen in GLSL in Dezimalzahlen umwandeln?

8

Wie andere bereits besprochen haben , gibt es in GLSL keinerlei Debugging. Aber manchmal möchte ich beim Debuggen meiner Shader wirklich numerische Werte untersuchen.

Ich habe versucht, ein visuelles Debugging-Tool zu erstellen. Ich fand heraus, dass es möglich ist, in einem Shader relativ einfach eine beliebige Ziffernfolge zu rendern, Wenn Sie mit einem sampler2D arbeiten, in dem die Ziffern 0123456789 in Monospace gerendert wurden. Im Grunde jonglieren Sie einfach Ihre x-Koordinate.

Um nun eine Fließkommazahl zu untersuchen, brauche ich einen Algorithmus zum Konvertieren von float zu einer Folge von Dezimalziffern, wie Sie sie in einer printf -Implementierung finden. Leider scheinen soweit ich das Thema verstehe diese Algorithmen zu scheinen müssen die repräsentieren Fließkommazahl in einem Format mit höherer Genauigkeit, und ich sehe nicht, wie das sein wird möglich in GLSL wo ich scheinen nur 32-Bit float s zur Verfügung zu haben. Aus diesem Grund denke ich Diese Frage ist kein Duplikat eines allgemeinen "Wie funktioniert Printf", sondern eher speziell darüber, wie solche Algorithmen dazu gebracht werden können, unter den Bedingungen von GLSL zu arbeiten. Ich habe diese Frage und Antwort gesehen, habe aber keine Ahnung, was dort vor sich geht.

Die Algorithmen, die ich ausprobiert habe, sind nicht sehr gut. Mein erster Versuch, markierte Version A (auskommentiert) schien ziemlich schlecht zu sein: um drei zufällige Beispiele zu nehmen, RenderDecimal(1.0) gerendert als 1.099999702 , RenderDecimal(2.5) gab mir 2.599999246 und RenderDecimal(2.6) wurden als 2.699999280 ausgegeben. Mein zweiter Versuch, markierte Version B, schien etwas besser: 1.0 und 2.6 kommen beide gut raus, aber RenderDecimal(2.5) stimmt immer noch nicht überein Aufrunden der 5 mit der Tatsache, dass der Rest 0.099... ist. Das Ergebnis erscheint als 2.599000022 .

Mein minimales / vollständiges / überprüfbares Beispiel beginnt unten mit einem kurzen GLSL 1.20-Code und dann Ich habe Python 2.x für den Rest ausgewählt, nur um die Shader kompiliert und die Texturen zu bekommen geladen und gerendert. Es erfordert die pygame, numpy, PyOpenGL und PIL-Drittanbieter Pakete. Beachten Sie, dass das Python wirklich nur Standard ist und trivial (wenn auch mühsam) neu geschrieben werden könnte in C oder irgendetwas anderem. Nur der GLSL-Code an der Spitze ist entscheidend für diese Frage und dafür Ich glaube nicht, dass die Tags python oder python 2.x hilfreich wären.

Das folgende Bild muss als digits.png gespeichert werden:

%Vor%     
jez 28.06.2017, 04:50
quelle

3 Antworten

10

+1 für ein interessantes Problem. War neugierig, also habe ich versucht, das zu programmieren. Ich brauche Arrays, also habe ich #version 420 core gewählt. Meine App rendert einzelne Quads mit den Koordinaten <-1,+1> . Ich verwende ganze ASCII 8x8 Pixel 32x8 Zeichen Schrift Textur Ich habe vor einigen Jahren erstellt:

Der Scheitelpunkt ist einfach:

%Vor%

Fragment ist ein bisschen komplizierter:

%Vor%

Hier meine Uniformen für die CPU:

%Vor%

wo xs,ys ist meine Bildschirmauflösung. Schriftart ist 8x8 in Einheit 0

Hier Ausgabe für den Testfragment-Code:

Wenn Ihre Gleitkommagenauigkeit aufgrund der HW-Implementierung verringert wird, sollten Sie in Erwägung ziehen, in Hex auszugeben, wo kein Genauigkeitsverlust vorhanden ist (mit Binärzugriff). Das könnte später in Ganzzahlen in dekadische Basis umgewandelt werden ...

siehe:

[Edit2] GLSL-Shader im alten Stil

Ich habe versucht, nach altem Stil zu portieren GLSL und plötzlich funktioniert es (vorher würde es nicht mit vorhandenen Arrays kompilieren, aber wenn ich daran denke, versuchte ich char[] , was der wahre Grund war).

%Vor% %Vor%     
Spektre 28.06.2017, 08:53
quelle
3

Zunächst möchte ich erwähnen, dass die erstaunliche Lösung von Spektre fast perfekt und noch mehr eine allgemeine Lösung für die Textausgabe ist. Ich gab seine Antwort ein upvote . Als Alternative präsentiere ich eine minimal-invasive Lösung und verbessere den Code der Frage.

Ich möchte nicht verschweigen, dass ich die Lösung von Spektre studiert und in meine Lösung integriert habe.

%Vor%

Die Funktion ValueToDigits interpretiert eine Gleitkommazahl und füllt ein Array mit den Ziffern.  Jede Zahl im Array befindet sich in ( 0 , 9 ).

%Vor%

Rufen Sie ValueToDigits in Ihrer ursprünglichen Funktion auf und finden Sie die Ziffern- und Texturkoordinaten für das aktuelle Fragment.

%Vor%     
Rabbid76 28.06.2017 19:18
quelle
1

Hier ist mein aktualisierter Fragment-Shader, der in der ursprünglichen Frage in den Eintrag eingefügt werden kann. Es implementiert den Dezimalstellen-Suchalgorithmus, den Spektre vorgeschlagen hat, in einer Weise, die sogar mit dem alten GLSL 1.20-Dialekt, den ich verwende, kompatibel ist. Ohne diese Einschränkung ist die Lösung von Spektre natürlich viel eleganter und leistungsfähiger.

%Vor%     
jez 29.06.2017 05:20
quelle

Tags und Links