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%
+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).
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
).
Rufen Sie ValueToDigits
in Ihrer ursprünglichen Funktion auf und finden Sie die Ziffern- und Texturkoordinaten für das aktuelle Fragment.
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%