2013-07-14 7 views
6

Ich möchte zwei Float-Werte in einer einzelnen 32-Bit-Float-Variable speichern. Die Kodierung erfolgt in C#, während die Dekodierung in einem HLSL-Shader erfolgen soll.Speichern von zwei Float-Werten in einer einzelnen Float-Variablen

Die beste Lösung, die ich bisher gefunden haben, ist, Festverdrahtung der Offset der dezimalen in den codierten Werten und als ganze Zahl und decimal des „carrier“ float Speicherung:

123.456 -> 12.3 and 45.6 

Es kann‘ t behandeln negative Werte, aber das ist in Ordnung.

Allerdings habe ich mich gefragt, ob es einen besseren Weg gibt, dies zu tun.

EDIT: Noch ein paar Details über die Aufgabe:

ich mit einer festen Datenstruktur in Unity bin zu arbeiten, wo die Scheitelpunktdaten als Schwimmer gespeichert sind. (Float2 für ein UV, float3 das Normale und so weiter.) Offensichtlich gibt es keine Möglichkeit, zusätzliche Daten richtig hinzuzufügen, also muss ich innerhalb dieser Grenzen arbeiten, deshalb dachte ich, dass alles auf ein allgemeineres Problem der Kodierung von Daten zurückzuführen ist . Zum Beispiel könnte ich die sekundären UV-Daten opfern, um die 2x2 zusätzlichen Datenkanäle zu übertragen.

Das Ziel ist Shader Model 3.0, aber ich hätte nichts dagegen, wenn die Decodierung auch auf SM2.0 funktioniert.

Datenverlust ist in Ordnung, solange es "vernünftig" ist. Der Erwartungswertbereich ist 0..64, aber wie ich jetzt denke, ist es 0..1. Das wäre auch in Ordnung, denn das ist billig, wenn man innerhalb des Shaders einen Bereich neu zuordnen möchte. Wichtig ist, die Präzision so hoch wie möglich zu halten. Negative Werte sind nicht wichtig.

+0

@ZoltanE: Kennen Sie die Bereiche der Variablen, die Sie verschlüsseln möchten? –

+0

@ZoltanE: Auf welches Shader-Modell und welche Version von DirectX zielen Sie? Kannst du mehr darüber erzählen, warum du so verschlüsselst? Schließlich: Überlege dir, ob du auf der [gamedev] (http://gamedev.stackexchange.com/) -Seite nachfragen kannst, du könntest bessere Antworten erhalten. –

+3

Vielleicht könnte die Frage http://stackoverflow.com/questions/4811219/pack-four-bytes-in-a-float Ihnen helfen. – Gnietschow

Antwort

2

Nach Gnietschows Empfehlung habe ich den Algo von YellPika angepasst. (. Es ist C# für Unity 3D)

float Pack(Vector2 input, int precision) 
{ 
    Vector2 output = input; 
    output.x = Mathf.Floor(output.x * (precision - 1)); 
    output.y = Mathf.Floor(output.y * (precision - 1)); 

    return (output.x * precision) + output.y; 
} 

Vector2 Unpack(float input, int precision) 
{ 
    Vector2 output = Vector2.zero; 

    output.y = input % precision; 
    output.x = Mathf.Floor(input/precision); 

    return output/(precision - 1); 
} 

Die schnelle und schmutzige Prüfung ergab folgende Statistiken (1 Million zufällige Wert-Paare im Bereich 0..1):

Precision: 2048 | Avg error: 0.00024424 | Max error: 0.00048852 
Precision: 4096 | Avg error: 0.00012208 | Max error: 0.00024417 
Precision: 8192 | Avg error: 0.00011035 | Max error: 0.99999940 

Präzision von 4096 scheint der Lieblingsplatz sein. Beachten Sie, dass sowohl das Packen als auch das Entpacken in diesen Tests auf der CPU ausgeführt wurde, so dass die Ergebnisse auf einer GPU schlechter sein könnten, wenn sie mit Float-Genauigkeit schneidet.

Egal, ich weiß nicht, ob dies der beste Algorithmus ist, aber es scheint gut genug für meinen Fall.

+0

Würde es Ihnen etwas ausmachen, zu erklären, warum der Teil 'input% precision' funktioniert? Du machst einen Modulo auf einem Float und einem Int, aber Modulo ist nur für ganze Zahlen definiert. – mrueg

+0

Die Definition ist nicht auf ganze Zahlen beschränkt: "Die Modulo-Operation findet den Rest der Division einer Zahl durch eine andere". Es macht Sinn zu fragen "Was ist der Rest, wenn ich 7,7 durch 3,3 teile?" – ZoltanE

+0

Hinweis: Dies wird unterbrochen, wenn "input.y" über "1" ist. In diesem Fall fügt '+ output.y' nur ein weiteres Inkrement des Wertes von' precision' hinzu - dann kann 'input% precision' nur den Bruchteil von' input.y' und seinen ganzzahligen Teil (dividiert durch ' Präzision ") wird zu" output.x "hinzugefügt. – meetar