Partager via


Opérateurs

Les expressions sont des séquences de variables et de littéraux ponctués par des opérateurs. Les opérateurs déterminent la façon dont les variables et les littéraux sont combinés, comparés, sélectionnés, etc. Les opérateurs sont notamment :

Nom de l'opérateur Opérateurs
Opérateurs additifs et multiplicatifs +, -, *, /, %
Opérateur de tableau [i]
Opérateurs d’assignation =, +=, -=, *=, /=, %=
Casts binaires Règles C pour les float et int, règles C ou intrinsèques HLSL pour bool
Opérateurs au niveau du bit ~, <<, >>, &, |, ^, <<=, >>=, &=, |=, ^=
Opérateurs mathématiques booléens &&, ||, ?:
Opérateur de cast (type)
Opérateur de virgule ,
Opérateurs de comparaison <, >, ==, !=, <=, >=
Opérateurs de préfixe ou postfix ++, --
Opérateur de structure .
Opérateurs unaires !, -, +

 

De nombreux opérateurs sont appliqués par composant, ce qui signifie que l’opération est effectuée indépendamment pour chaque composant de chaque variable. Par exemple, une variable à un seul composant a une seule opération effectuée. En revanche, une variable à quatre composants a quatre opérations effectuées, une pour chaque composant.

Tous les opérateurs qui agissent sur la valeur, comme + et *, fonctionnent par composant.

Les opérateurs de comparaison nécessitent un seul composant pour fonctionner, sauf si vous utilisez la fonction intrinsèque all ou any avec une variable à plusieurs composants. L’opération suivante échoue, car l’instruction if nécessite une seule valeur booléenne, mais reçoit un bool4 :

if (A4 < B4)

Les opérations suivantes réussissent :

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

Les opérateurs de cast binaire asfloat, asint, etc. fonctionnent par composant, sauf asdouble dont les règles spéciales sont documentées.

Les opérateurs de sélection comme le point, la virgule et les crochets de tableau ne fonctionnent pas par composant.

Les opérateurs de cast changent le nombre de composants. Les opérations de cast suivantes montrent leur équivalence :

(float) i4 ->   float(i4.x)
(float4)i ->   float4(i, i, i, i)

Opérateurs additifs et multiplicatifs

Les opérateurs additifs et multiplicatifs sont : +, -, *, /, %

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

L’opérateur modulus renvoie le reste d’une division. Cela produit des résultats différents en cas d’utilisation d’entiers et de nombres à virgule flottante. Les restes entiers qui sont fractionnaires sont tronqués.

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

L’opérateur modulus tronque un reste fractionnaire en cas d’utilisation d’entiers.

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

L’opérateur % est défini uniquement quand les deux côtés sont positifs ou négatifs. Contrairement à C, il fonctionne également sur des types de données à virgule flottante, ainsi que sur des entiers.

Opérateur de tableau

L’opérateur de sélection de membre de tableau « [i] » sélectionne un ou plusieurs composants dans un tableau. Il s’agit d’un jeu de crochets contenant un index de base zéro.

int arrayOfInts[4] = { 0,1,2,3 };
arrayOfInts[0] = 2;
arrayOfInts[1] = arrayOfInts[0];

L’opérateur de tableau peut également être utilisé pour accéder à un vecteur.

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

En ajoutant un index supplémentaire, l’opérateur de tableau peut également accéder à une matrice.

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

Le premier index est l’index de ligne de base zéro. Le deuxième index est l’index de colonne de base zéro.

Opérateurs d’assignation

Les opérateurs d’assignation sont : =, +=, -=, *=, /=

Les variables peuvent recevoir des valeurs littérales :

int i = 1;            
float f2 = 3.1f; 
bool b = false;
string str = "string";

Les variables peuvent également recevoir le résultat d’une opération mathématique :

int i1 = 1;
i1 += 2;           // i1 = 1 + 2 = 3

Une variable peut être utilisée d’un côté ou de l’autre du signe égal :

float f3 = 0.5f;
f3 *= f3;          // f3 = 0.5 * 0.5 = 0.25

La division des variables à virgule flottante se fait comme prévu, car les restes décimaux ne sont pas un problème.

float f1 = 1.0;
f1 /= 3.0f;        // f1 = 1.0/3.0 = 0.333

Soyez attentifs quand vous utilisez des entiers qui peuvent être divisés, en particulier quand la troncation affecte le résultat. Cet exemple est identique à l’exemple précédent, à l’exception du type de données. La troncation provoque un résultat très différent.

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

Casts binaires

L’opération de cast entre int et float convertit la valeur numérique en représentations appropriées en suivant les règles C pour tronquer un type int. Le cast d’une valeur float en int, puis à nouveau en float entraîne une conversion avec perte selon la précision de la cible.

Les casts binaires peuvent également être effectués avec des Fonctions intrinsèques (DirectX HLSL) qui réinterprètent la représentation binaire d’un nombre dans le type de données cible.

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

Opérateurs au niveau du bit

HLSL prend en charge les opérateurs suivants au niveau du bit, qui suivent la même priorité que C en ce qui concerne les autres opérateurs. Le tableau suivant décrit les opérateurs.

Remarque

Les opérateurs au niveau du bit nécessitent Shader Model 4_0 avec un matériel Direct3D 10 et version supérieure.

 

Opérateur Fonction
~ NOT logique
<< Maj gauche
>> Décalage vers la droite
& And logique
| Or logique
^ Xor logique
<<= Décalage à gauche égal
>>= Décalage à droite égal
&= And égal
|= Or égal
^= Xor égal

 

Les opérateurs au niveau du bit sont définis pour fonctionner uniquement sur les types de données int et uint. Si vous tentez d’utiliser des opérateurs au niveau du bit sur les types de données float ou struct, une erreur se produit.

Opérateurs mathématiques booléens

Les opérateurs mathématiques booléens sont : &&, ||, ?:

bool b1 = true;
bool b2 = false;
bool b3 = b1 && b2 // b3 = true AND false = false
b3 = b1 || b2                // b3 = true OR false = true

Contrairement à l’évaluation de court-circuit de &&, || et ?: en C, les expressions HLSL ne court-circuitent jamais une évaluation, car ce sont des opérations vectorielles. Tous les côtés de l’expression sont toujours évalués.

Les opérateurs booléens fonctionnent par composant. Cela signifie que si vous comparez deux vecteurs, le résultat est un vecteur contenant le résultat booléen de la comparaison pour chaque composant.

Pour les expressions qui utilisent des opérateurs booléens, la taille et le type de composant de chaque variable sont promus pour être identiques avant que l’opération ne se produise. Le type promu détermine la résolution à laquelle l’opération a lieu, ainsi que le type de résultat de l’expression. Par exemple, une expression int3 + float est promue en float3 + float3 pour l’évaluation, et son résultat est de type float3.

Opérateur de conversion

Une expression précédée d’un nom de type entre parenthèses est un cast de type explicite. Un cast de type convertit l’expression d’origine en type de données du cast. En général, les types de données simples peuvent être castés en types de données plus complexes (avec un cast de promotion), mais seuls certains types de données complexes peuvent être castés en types de données simples (avec un cast de rétrogradation).

Seul le cast de type du côté droit est légal. Par exemple, des expressions comme (int)myFloat = myInt; sont illégales. Utilisez myFloat = (float)myInt; à la place.

Le compilateur effectue également un cast de type implicite. Par exemple, les deux expressions suivantes sont équivalentes :

int2 b = int2(1,2) + 2;
int2 b = int2(1,2) + int2(2,2);

Opérateur de virgule

L’opérateur de virgule (,) sépare une ou plusieurs expressions à évaluer dans l’ordre. La valeur de la dernière expression de la séquence est utilisée comme valeur de la séquence.

Voici un cas qui mérite une attention particulière. Si le type de constructeur est accidentellement supprimé du côté droit du signe égal, le côté droit contient maintenant quatre expressions, séparées par trois virgules.

// 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); 

L’opérateur de virgule évalue une expression de gauche à droite. Cela réduit le côté droit à :

float4 x = 1; 

HLSL utilisant la promotion scalaire dans ce cas, le résultat est le même que si l’équation avait été écrite de la façon suivante :

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

Dans ce cas, la suppression du type float4 du côté droit est probablement une erreur que le compilateur ne peut pas détecter, car il s’agit d’une instruction valide.

Opérateurs de comparaison

Les opérateurs de comparaison sont : <, >, ==, !=, <=, >=.

Ils comparent des valeurs qui sont supérieures (ou inférieures) à une valeur scalaire :

if( dot(lightDirection, normalVector) > 0 )
   // Do something; the face is lit
if( dot(lightDirection, normalVector) < 0 )
   // Do nothing; the face is backwards

Ou, ils comparent des valeurs égales à (ou non égales à) une valeur scalaire :

if(color.a == 0)
   // Skip processing because the face is invisible

if(color.a != 0)
   // Blend two colors together using the alpha value

Ou ils combinent les deux et comparent les valeurs qui sont supérieures ou égales à (ou inférieures ou égales à) une valeur scalaire :

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

Chacune de ces comparaisons peut être effectuée avec n’importe quel type de données scalaire.

Pour utiliser des opérateurs de comparaison avec des types de vecteur et de matrice, utilisez la fonction intrinsèque all ou any.

Cette opération échoue, car l’instruction if nécessite une seule valeur booléenne, mais reçoit un bool4 :

if (A4 < B4)

Ces opérations réussissent :

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

Opérateurs de préfixe ou postfix

Les opérateurs de préfixe et postfix sont : ++, --. Les opérateurs de préfixe changent le contenu de la variable avant l’évaluation de l’expression. Les opérateurs de postfix changent le contenu de la variable après l’évaluation de l’expression.

Dans ce cas, une boucle utilise le contenu de i pour suivre le nombre de boucles.

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

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

Comme l’opérateur d’incrément de postfix (++) est utilisé, arrayOfFloats[i] est multiplié par 2 avant que i soit incrémenté. Cela peut être légèrement réorganisé pour utiliser l’opérateur d’incrément de préfixe. Celui-ci est plus difficile à lire, bien que les deux exemples soient équivalents.

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

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

Comme l’opérateur de préfixe (++) est utilisé, arrayOfFloats[i+1 - 1] est multiplié par 2 après l’incrément de i.

L’opérateur de décrément de préfixe et de décrément de postfix (--) sont appliqués dans le même ordre que l’opérateur d’incrément. La différence est que le décrément soustrait 1 au lieu d’ajouter 1.

Opérateur de structure

L’opérateur de sélection de membre de structure (.) est un point. Étant donné cette structure :

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

Il peut être lu de la façon suivante :

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

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

Chaque membre peut être lu ou écrit avec l’opérateur de structure :

struct position pos = { 1,2,3 };
pos.x = 2.0f;
pos.z = 1.0f;       // z = 1.0f
pos.z = pos.x      // z = 2.0f

Opérateurs unaires

Les opérateurs unaires sont : !, -, +

Les opérateurs unaires opèrent sur un seul opérande.

bool b = false;
bool b2 = !b;      // b2 = true
int i = 2;
int i2 = -i;       // i2 = -2
int j = +i2;       // j = +2

Priorité des opérateurs

Quand une expression contient plusieurs opérateurs, la priorité des opérateurs détermine l’ordre d’évaluation. La priorité des opérateurs pour HLSL suit la même priorité que C.

Notes

Les accolades ({,}) ouvrent et ferment un bloc d’instructions. Quand un bloc d’instructions utilise une seule instruction, les accolades sont facultatives.

Instructions (DirectX HLSL)