Operatoren

Ausdrücke sind Sequenzen von Variablen und Literalen, die von Operatoreninterpunktiert 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 Funktionen für bool
Bitwise Operators (Bitweise Operatoren) ~, <<, >>, &, | , ^, <<=, >>=, &=, | =, ^=
Boolesche mathematische Operatoren & &, | | , ?:
Umwandlungsoperator (Typ)
Kommaoperator ,
Comparison Operators (Vergleichsoperatoren) <, >, ==, !=, <=, >=
Präfix- oder Postfixoperatoren ++, --
Structure-Operator .
Unary Operators (Unäre Operatoren) !, -, +

Viele der Operatoren sind pro Komponente, was bedeutet, dass der Vorgang unabhängig für jede Komponente jeder Variablen ausgeführt wird. Beispielsweise wird für eine einzelne Komponentenvariable ein Vorgang ausgeführt. Andererseits werden für eine Variable mit vier Komponenten vier Vorgänge ausgeführt, eine für jede Komponente.

Alle Operatoren, die etwas für den Wert tun, z. B. + und * , funktionieren pro Komponente.

Die Vergleichsoperatoren erfordern, dass eine einzelne Komponente funktioniert, es sei denn, Sie verwenden die all- oder eine systeminterne Funktion mit einer Variablen mit mehreren Komponenten. Der folgende Vorgang schlägt fehl, da die if-Anweisung eine einzelne bool erfordert, aber bool4 empfängt:

if (A4 < B4)

Die folgenden Vorgänge sind erfolgreich:

if ( any(A4 < B4) )
if ( all(A4 < B4) )

Die binären Umwandlungsoperatoren asfloat, asintusw. 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 Umwandlungsvorgänge 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 führt bei Verwendung von ganzen Zahlen und Gleitkommazahlen zu unterschiedlichen Ergebnissen. Ganzzahlige Reste, 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 Bruchteil des Rests ab, wenn ganze Zahlen verwendet werden.

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 werden auch Gleitkommadatentypen sowie ganze Zahlen verwendet.

Arrayoperator

Der Arraymemberauswahloperator [ ] "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 verwendet werden, um auf einen Vektor zuzugreifen.

float4 4D_Vector = { 0.0f, 1.0f, 2.0f, 3.0f  };         
float 1DFloat = 4D_Vector[1];          // 1.0f

Durch Hinzufügen eines zusätzlichen Index 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 ist 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 ganzzahlige Zahlen verwenden, die geteilt werden können, insbesondere, wenn sich die Kürzung auf das Ergebnis auswirkt. Dieses Beispiel ist mit dem vorherigen Beispiel identisch, mit Ausnahme des Datentyps. Die Kürzung führt zu einem sehr unterschiedlichen Ergebnis.

int i1 = 1;
i1 /= 3;           // i1 = 1/3 = 0.333, which gets truncated to 0

Binäre Umwandlungen

Beim Umwandlungsvorgang zwischen int und float wird der numerische Wert gemäß den C-Regeln zum Abschneiden eines int-Typs in die entsprechenden Darstellungen konvertiert. Das Umwandeln eines Werts aus einem float-Wert in einen int-Wert und zurück in einen float-Wert führt basierend auf der Genauigkeit des Ziels zu einer verlustbeschwerte Konvertierung.

Binäre Umwandlungen können auch mithilfe von systeminternen Funktionen (DirectX HLSL)ausgeführt werden, die die Bitdarstellung einer Zahl in den Zieldatentyp neu interpretieren.

asfloat() // Cast to float
asint()   // Cast to int 
asuint()  // Cast to uint

Bitweise Operatoren

HLSL unterstützt die folgenden bitweisen Operatoren, die im Hinblick auf andere Operatoren derselben Rangfolge wie C folgen. In der folgenden Tabelle werden die Operatoren beschrieben.

Hinweis

Bitweise Operatoren erfordern shader Model 4 _ 0 mit Direct3D 10 und höher hardware.

Operator Funktion
~ Logisches NOT
<< NACH-LINKS-UMSCHALTTASTE
>> Rechtsverschiebung
& Logisches UND
| Logisches ODER.
^ Logischer Xor
<<= Nach links umschalten gleich
>>= Rechtsverschiebung gleich
&= Und gleich
|= Oder gleich
^= Xor Equal

Bitweise Operatoren sind so definiert, dass sie nur für int- und uint-Datentypen ausgeführt werden. Der Versuch, bitweise Operatoren für float- oder struct-Datentypen zu verwenden, führt 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 es sich um Vektorvorgänge handelt. Alle Seiten des Ausdrucks werden immer ausgewertet.

Boolesche Operatoren funktionieren pro Komponente. Wenn Sie also 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, werden die Größe und der Komponententyp jeder Variablen so heraufgestuft, dass sie gleich sind, bevor der Vorgang ausgeführt wird. Der heraufgestufte Typ bestimmt die Auflösung, bei der der Vorgang stattfindet, sowie den Ergebnistyp des Ausdrucks. Beispielsweise würde ein int3 +float-Ausdruck zur Auswertung auf float3 + float3 heraufgestuft, und das Ergebnis wäre vom Typ float3.

Umwandlungsoperator

Ein Ausdruck, dem ein Typname in Klammern vorangestellt ist, ist eine explizite Typform. Eine Typ-Umwandlung konvertiert den ursprünglichen Ausdruck in den Datentyp der Umwandlung. Im Allgemeinen können die einfachen Datentypen in komplexere Datentypen (mit einer Promotion-Cast) umformen werden, aber nur einige komplexe Datentypen können in einfache Datentypen (mit Herabstufungs cast) umformen werden.

Nur die Umwandlung von rechtsseitigen Typen ist legal. Ausdrücke wie sind beispielsweise (int)myFloat = myInt; ungültig. Verwenden Sie stattdessen myFloat = (float)myInt;.

Der Compiler führt auch eine implizite Typ cast aus. Beispielsweise sind die folgenden beiden Ausdrücke äquivalent:

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.

Dies ist ein Fall, auf den Sie achten müssen. Wenn der Konstruktortyp versehentlich von der rechten Seite des Gleichheitszeichens links gelassen wird, 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 die skalare Promotion, sodass das Ergebnis so ist, als ob dies wie folgt geschrieben wäre:

float4 x = float4(1,1,1,1);

In diesem Fall ist das Verlassen des float4-Typs von der rechten Seite wahrscheinlich ein Fehler, den der Compiler nicht erkennen kann, da es sich um eine gültige Anweisung handelt.

Vergleichsoperatoren

Die Vergleichsoperatoren sind: <, >, ==, !=, <=, >=.

Vergleichen Sie Werte, die größer als (oder kleiner als) eines beliebigen Skalarwerts 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, die gleich (oder nicht gleich) einem beliebigen Skalarwert sind:

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) einem beliebigen Skalarwert 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 durchgeführt werden.

Um Vergleichsoperatoren mit Vektor- und Matrixtypen zu verwenden, verwenden Sie die systeminterne Funktion all oder eine beliebige intrinsische Funktion.

Dieser Vorgang schlägt fehl, da die if-Anweisung einen einzelnen Bool erfordert, aber einen bool4 empfängt:

if (A4 < B4)

Diese Vorgänge 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 nachverfolgung zu behalten.

float4 arrayOfFloats[4] = { 1.0f, 2.0f, 3.0f, 4.4f };

for (int i = 0; i<4; )
{
    arrayOfFloats[i++] *= 2; 
}

Da der Postfixinkrementoperator (++) verwendet wird, wird arrayOfFloats i mit 2 multipliziert, [ bevor i erhöht ] wird. Dies kann leicht neu angeordnet werden, um den Präfixinkrementoperator zu verwenden. Dieses 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 inkrementiert wurde.

Der Präfixdekrementoperator und der Postfixdekrementoperator (--) werden in derselben Sequenz wie der Inkrementoperator angewendet. Der Unterschied besteht in der Dekrementierung, die 1 subtrahiert, anstatt 1 hinzuzufügungen.

Structure-Operator

Der Struktur-Memberauswahloperator (.) ist ein Zeitraum. Bei dieser Struktur:

struct position
{
float4 x;
float4 y;
float4 z;
};

Sie kann wie hier gelesen werden:

struct position pos = { 1,2,3 };

float 1D_Float = pos.x
1D_Float = pos.y

Jeder Member 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ären Operatoren sind: !, -, +

Unäre Operatoren arbeiten mit einem einzelnen Operanden.

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 mehr als einen Operator enthält, bestimmt die Rangfolge der Operatoren die Reihenfolge der Auswertung. Die Operatoren-Rangfolge für HLSL hat die gleiche Rangfolge wie C.

Hinweise

Geschweifte Klammern ( {,} ) starten und beenden einen Anweisungsblock. Wenn ein Anweisungsblock eine einzelne Anweisung verwendet, sind die geschweiften Klammern optional.

Anweisungen (DirectX HLSL)