Operatoren
Ausdrücke sind Folgen von Variablen und Literalen, die durch Operatoren unterbrochen werden. Operatoren bestimmen, wie die Variablen und Literale kombiniert, verglichen, ausgewählt usw. werden. Zu den Operatoren gehören:
Operatorname | Operatoren |
---|---|
Additive und multiplikative Operatoren | +, -, *, /, % |
Arrayoperator | [i] |
Zuweisungsoperatoren | =, +=, -=, *=, /=, %= |
Binäre Umwandlungen | C-Regeln für Float- und Int-, C-Regeln oder HLSL-systeminterne Regeln für Bool |
Bitwise Operators (Bitweise Operatoren) | ~, <<, >>, &, |, ^, <<=, >>=, &=, |=, ^= |
Boolesche mathematische Operatoren | &&, ||, ?: |
Umwandlungsoperator | (Typ) |
Kommaoperator | , |
Comparison Operators (Vergleichsoperatoren) | <, >, ==, !=, <=, >= |
Präfix- oder Postfixoperatoren | ++, -- |
Strukturoperator | . |
Unary Operators (Unäre Operatoren) | !, -, + |
Viele der Operatoren sind komponentenbezogen, was bedeutet, dass die Operation unabhängig für jede Komponente jeder Variablen durchgeführt wird. Beispielsweise hat eine einzelne Komponentenvariable eine Operation ausgeführt. Andererseits hat eine Variable mit vier Komponenten vier Vorgänge ausgeführt, einen für jede Komponente.
Alle Operatoren, die einen Wert ausführen, z. B. + und *, funktionieren pro Komponente.
Die Vergleichsoperatoren erfordern eine einzelne Komponente, es sei denn, Sie verwenden die gesamte oder eine beliebige systeminterne Funktion mit einer Variablen mit mehreren Komponenten. Die folgende Operation schlägt fehl, da die If-Anweisung einen einzelnen bool erfordert, aber einen bool4 empfängt:
if (A4 < B4)
Die folgenden Operationen sind erfolgreich:
if ( any(A4 < B4) )
if ( all(A4 < B4) )
Die binären Umwandlungsoperatoren asfloat, asint usw. funktionieren pro Komponente, mit Ausnahme von asdouble, dessen spezielle Regeln dokumentiert sind.
Auswahloperatoren wie Punkt, Komma und Arrayklammern funktionieren nicht pro Komponente.
Umwandlungsoperatoren ändern die Anzahl der Komponenten. Die folgenden Umwandlungsoperationen zeigen ihre Äquivalenz:
(float) i4 -> float(i4.x)
(float4)i -> float4(i, i, i, i)
Additive und multiplikative Operatoren
Die additiven und multiplikativen Operatoren sind: +, -, *, /, %
int i1 = 1;
int i2 = 2;
int i3 = i1 + i2; // i3 = 3
i3 = i1 * i2; // i3 = 1 * 2 = 2
i3 = i1/i2; // i3 = 1/3 = 0.333. Truncated to 0 because i3 is an integer.
i3 = i2/i1; // i3 = 2/1 = 2
float f1 = 1.0;
float f2 = 2.0f;
float f3 = f1 - f2; // f3 = 1.0 - 2.0 = -1.0
f3 = f1 * f2; // f3 = 1.0 * 2.0 = 2.0
f3 = f1/f2; // f3 = 1.0/2.0 = 0.5
f3 = f2/f1; // f3 = 2.0/1.0 = 2.0
Der Modulusoperator gibt den Rest einer Division zurück. Dies erzeugt unterschiedliche Ergebnisse bei der Verwendung von Ganzzahlen und Gleitkommazahlen. Ganzzahlige Restbeträge, die Bruchzahlen sind, werden abgeschnitten.
int i1 = 1;
int i2 = 2;
i3 = i1 % i2; // i3 = remainder of 1/2, which is 1
i3 = i2 % i1; // i3 = remainder of 2/1, which is 0
i3 = 5 % 2; // i3 = remainder of 5/2, which is 1
i3 = 9 % 2; // i3 = remainder of 9/2, which is 1
Der Modulusoperator schneidet einen gebrochenen Rest ab, wenn Sie ganze Zahlen verwenden.
f3 = f1 % f2; // f3 = remainder of 1.0/2.0, which is 0.5
f3 = f2 % f1; // f3 = remainder of 2.0/1.0, which is 0.0
Der %-Operator wird nur in Fällen definiert, in denen beide Seiten positiv oder beide Seiten negativ sind. Im Gegensatz zu C arbeitet es nicht nur mit ganzen Zahlen, sondern auch mit Gleitkommadatentypen.
Arrayoperator
Der Arrayelementauswahloperator „[i]“ wählt eine oder mehrere Komponenten in einem Array aus. Es handelt sich um eine Reihe von eckigen Klammern, die einen nullbasierten Index enthalten.
int arrayOfInts[4] = { 0,1,2,3 };
arrayOfInts[0] = 2;
arrayOfInts[1] = arrayOfInts[0];
Der Arrayoperator kann auch für den Zugriff auf einen Vektor verwendet werden.
float4 4D_Vector = { 0.0f, 1.0f, 2.0f, 3.0f };
float 1DFloat = 4D_Vector[1]; // 1.0f
Durch Hinzufügen eines zusätzlichen Indexes kann der Arrayoperator auch auf eine Matrix zugreifen.
float4x4 mat4x4 = {{0,0,0,0}, {1,1,1,1}, {2,2,2,2}, {3,3,3,3} };
mat4x4[0][1] = 1.1f;
float 1DFloat = mat4x4[0][1]; // 0.0f
Der erste Index ist der nullbasierte Zeilenindex. Der zweite Index ist der nullbasierte Spaltenindex.
Zuweisungsoperatoren
Die Zuweisungsoperatoren sind: =, +=, -=, *=, /=
Variablen können Literalwerte zugewiesen werden:
int i = 1;
float f2 = 3.1f;
bool b = false;
string str = "string";
Variablen können auch das Ergebnis einer mathematischen Operation zugewiesen werden:
int i1 = 1;
i1 += 2; // i1 = 1 + 2 = 3
Eine Variable kann auf beiden Seiten des Gleichheitszeichens verwendet werden:
float f3 = 0.5f;
f3 *= f3; // f3 = 0.5 * 0.5 = 0.25
Die Division für Gleitkommavariablen funktioniert wie erwartet, da Dezimalreste kein Problem darstellen.
float f1 = 1.0;
f1 /= 3.0f; // f1 = 1.0/3.0 = 0.333
Seien Sie vorsichtig, wenn Sie ganze Zahlen verwenden, die geteilt werden können, insbesondere wenn das Ergebnis durch Abschneiden beeinflusst wird. Dieses Beispiel ist mit dem vorherigen Beispiel identisch, mit Ausnahme des Datentyps. Das Abschneiden führt zu einem stark abweichenden Ergebnis.
int i1 = 1;
i1 /= 3; // i1 = 1/3 = 0.333, which gets truncated to 0
Binäre Umwandlungen
Die Umwandlungsoperation zwischen Int und Float konvertiert den numerischen Wert in die entsprechenden Darstellungen, die folgenden C-Regeln zum Abschneiden eines Int-Typs folgen. Das Umwandeln eines Werts von einem Float in ein Int und zurück zu einem Float führt zu einer verlustbehafteten Konvertierung basierend auf der Genauigkeit des Ziels.
Binäre Zuordnungen können auch mit Hilfe von systeminternen Funktionen (DirectX HLSL) vorgenommen werden, die die Bit-Darstellung einer Zahl in den Zieldatentyp uminterpretieren.
asfloat() // Cast to float
asint() // Cast to int
asuint() // Cast to uint
Bitwise Operators (Bitweise Operatoren)
HLSL unterstützt die folgenden bitweisen Operatoren, die dem gleichen Rang folgen wie C in Bezug auf andere Operatoren. In der folgenden Tabelle werden die Operatoren beschrieben.
Hinweis
Bitweise Operatoren erfordern Shadermodell 4_0 mit Direct3D 10 und höherer Hardware.
Operator | Funktion |
---|---|
~ | Logisches NOT |
<< | Linke Umschalttaste |
>> | Nach rechts verschieben |
& | Logical And |
| | Logical Or |
^ | Logisches Xor |
<<= | Nach links verschieben gleich |
>>= | Nach rechts verschieben gleich |
&= | Und gleich |
|= | Oder gleich |
^= | Xor gleich |
Bitweise Operatoren sind so definiert, dass sie nur für Int- und Uint-Datentypen verwendet werden. Wenn Sie versuchen, bitweise Operatoren für Float- oder Struct-Datentypen zu verwenden, führt dies zu einem Fehler.
Boolesche mathematische Operatoren
Die booleschen mathematischen Operatoren sind: &&, ||, ?:
bool b1 = true;
bool b2 = false;
bool b3 = b1 && b2 // b3 = true AND false = false
b3 = b1 || b2 // b3 = true OR false = true
Im Gegensatz zur Kurzschlussauswertung von &&, ||, und ?: in C schließen HLSL-Ausdrücke niemals eine Auswertung kurz, da sie Vektoroperationen sind. Alle Seiten des Ausdrucks werden immer ausgewertet.
Boolesche Operatoren funktionieren auf Basis der einzelnen Komponenten. Dies bedeutet: Wenn Sie zwei Vektoren vergleichen, ist das Ergebnis ein Vektor, der das boolesche Ergebnis des Vergleichs für jede Komponente enthält.
Bei Ausdrücken, die boolesche Operatoren verwenden, wird die Größe und der Komponententyp jeder Variablen höhergestuft, bevor die Operation eintritt. Der höhergestufte Typ bestimmt die Auflösung, an der die Operation stattfindet, sowie den Ergebnistyp des Ausdrucks. Beispielsweise würde ein Int3 + Float-Ausdruck zur Auswertung in float3 + float3 heraufgestuft, und das Ergebnis wäre vom Typ float3.
Umwandlungsoperator
Ein Ausdruck, der einem Typnamen in Klammern vorausgeht, ist eine explizite Typumwandlung. Eine Typumwandlung konvertiert den ursprünglichen Ausdruck in den Datentyp der Umwandlung. Im Allgemeinen können die einfachen Datentypen in komplexere Datentypen umgewandelt werden (mit einer Heraufstufungsumwandlung), aber nur einige komplexe Datentypen können in einfache Datentypen umgewandelt werden (mit einer Herabstufung).
Nur rechtsseitiges Umwandlungsmuster ist zulässig. Beispielsweise sind Ausdrücke wie (int)myFloat = myInt;
unzulässig. Verwenden Sie stattdessen myFloat = (float)myInt;
.
Der Compiler führt auch implizite Typumwandlung durch. Beispielsweise sind die beiden folgenden Methodenaufrufe gleichbedeutend:
int2 b = int2(1,2) + 2;
int2 b = int2(1,2) + int2(2,2);
Kommaoperator
Der Kommaoperator (,) trennt einen oder mehrere Ausdrücke, die in der Reihenfolge ausgewertet werden sollen. Der Wert des letzten Ausdrucks in der Sequenz wird als Wert der Sequenz verwendet.
Der folgende Fall bedarf einiger Aufmerksamkeit. Wenn der Konstruktortyp versehentlich auf der rechten Seite des Gleichheitszeichens vergessen wurde, enthält die rechte Seite nun vier Ausdrücke, die durch drei Kommas getrennt sind.
// Instead of using a constructor
float4 x = float4(0,0,0,1);
// The type on the right side is accidentally left off
float4 x = (0,0,0,1);
Der Kommaoperator wertet einen Ausdruck von links nach rechts aus. Dies reduziert die rechte Seite auf:
float4 x = 1;
HLSL verwendet in diesem Fall eine skalare Promotion, so dass das Ergebnis so aussieht, als ob es wie folgt geschrieben wäre:
float4 x = float4(1,1,1,1);
In diesem Fall ist das Weglassen des float4-Typs von der rechten Seite wahrscheinlich ein Fehler, was der Compiler nicht erkennen kann, da dies eine gültige Anweisung ist.
Vergleichsoperatoren
Die Vergleichsoperatoren sind: <, >, ==, !=, <=, >=.
Vergleichen Sie Werte, die größer als (oder kleiner als) eines skalaren Werts sind:
if( dot(lightDirection, normalVector) > 0 )
// Do something; the face is lit
if( dot(lightDirection, normalVector) < 0 )
// Do nothing; the face is backwards
Oder vergleichen Sie Werte gleich (oder ungleich) einem Skalarwert:
if(color.a == 0)
// Skip processing because the face is invisible
if(color.a != 0)
// Blend two colors together using the alpha value
Oder kombinieren Sie beide Werte und vergleichen Sie Werte, die größer oder gleich (oder kleiner oder gleich) eines beliebigen Skalarwerts sind:
if( position.z >= oldPosition.z )
// Skip the new face because it is behind the existing face
if( currentValue <= someInitialCondition )
// Reset the current value to its initial condition
Jeder dieser Vergleiche kann mit jedem skalaren Datentyp erfolgen.
Um Vergleichsoperatoren mit Vektor- und Matrixtypen zu verwenden, verwenden Sie die gesamte oder eine beliebige systeminterne Funktion.
Diese Operation schlägt fehl, da die If-Anweisung einen einzelnen bool erfordert, aber einen bool4 empfängt:
if (A4 < B4)
Diese Operationen sind erfolgreich:
if ( any(A4 < B4) )
if ( all(A4 < B4) )
Präfix- oder Postfixoperatoren
Die Präfix- und Postfixoperatoren sind: ++, --. Präfixoperatoren ändern den Inhalt der Variablen, bevor der Ausdruck ausgewertet wird. Postfixoperatoren ändern den Inhalt der Variablen, nachdem der Ausdruck ausgewertet wurde.
In diesem Fall verwendet eine Schleife den Inhalt von i, um die Anzahl der Schleifen nachzuverfolgen.
float4 arrayOfFloats[4] = { 1.0f, 2.0f, 3.0f, 4.4f };
for (int i = 0; i<4; )
{
arrayOfFloats[i++] *= 2;
}
Da der Postfix-Inkrementoperator (++) verwendet wird, wird arrayOfFloats[i] mit 2 multipliziert, bevor i erhöht wird. Dies könnte leicht neu angeordnet werden, um den Präfixinkrementierungsoperator zu verwenden. Dieser ist schwieriger zu lesen, obwohl beide Beispiele gleichwertig sind.
float4 arrayOfFloats[4] = { 1.0f, 2.0f, 3.0f, 4.4f };
for (int i = 0; i<4; )
{
arrayOfFloats[++i - 1] *= 2;
}
Da der Präfixoperator (++) verwendet wird, wird arrayOfFloats[i+1 - 1] mit 2 multipliziert, nachdem i erhöht wurde.
Der Präfix-Dekrement- und Postfix-Dekrementoperator (--) werden in derselben Reihenfolge wie der Inkrementoperator angewendet. Der Unterschied besteht darin, dass Dekrement 1 subtrahiert, anstatt 1 zu addieren.
Strukturoperator
Der Strukturelementauswahloperator (.) ist ein Punkt. Bei dieser Struktur:
struct position
{
float4 x;
float4 y;
float4 z;
};
Kann er wie folgt aussehen:
struct position pos = { 1,2,3 };
float 1D_Float = pos.x
1D_Float = pos.y
Jedes Element kann mit dem Strukturoperator gelesen oder geschrieben werden:
struct position pos = { 1,2,3 };
pos.x = 2.0f;
pos.z = 1.0f; // z = 1.0f
pos.z = pos.x // z = 2.0f
Unäre Operatoren
Die Unäroperatoren sind: !, -, +
Unäroperatoren werden für einen einzelnen Operanden ausgeführt.
bool b = false;
bool b2 = !b; // b2 = true
int i = 2;
int i2 = -i; // i2 = -2
int j = +i2; // j = +2
Operatorrangfolge
Wenn ein Ausdruck mehrere Operatoren enthält, bestimmt die Operatorrangfolge die Reihenfolge der Auswertung. Die Rangfolge des Operators für HLSL folgt der gleichen Rangfolge wie C.
Hinweise
Geschweifte Klammern ({,}) beginnen und beenden einen Anweisungsblock. Wenn ein Anweisungsblock eine einzelne Anweisung verwendet, sind die geschweiften Klammern optional.
Zugehörige Themen