Operadores
Las expresiones son secuencias de variables y literales puntuados mediante operadores. Los operadores determinan cómo se combinan, comparan, seleccionan, etc., las variables y los literales. Entre los operadores se incluyen:
Nombre del operador | Operadores |
---|---|
Operadores aditivos y multiplicativos | +, -, *, /, % |
Operador de matriz | [i] |
Operadores de asignación | =, +=, -=, *=, /=, %= |
Conversiones binarias | Reglas de C para elementos float e int, reglas de C o funciones intrínsecas de HLSL para elementos bool |
Operadores bit a bit | ~, <<, >>, &, |, ^, <<=, >>=, &=, |=, ^= |
Operadores matemáticos booleanos | &&, ||, ?: |
Operador de conversión | (escribir) |
Operador coma | , |
Operadores de comparación | <, >, ==, !=, <=, >= |
Operadores de prefijo o postfijo | ++, -- |
Operador de estructura | . |
Operadores unarios | !, -, + |
Muchos de los operadores son por componente, lo que significa que la operación se realiza de forma independiente para cada componente de cada variable. Por ejemplo, en una variable de un solo componente se realiza una sola operación. Por otra parte, en una variable de cuatro componentes se realizarán cuatro operaciones, una por cada componente.
Todos los operadores que hacen algo al valor, como "+" y "*", funcionan por componente.
Los operadores de comparación requieren que un único componente funcione a menos que use la función intrínseca all o any con una variable de varios componentes. Se produce un error en la siguiente operación porque la instrucción if requiere simplemente como respuesta bool pero recibe bool4:
if (A4 < B4)
Se realizan las siguientes operaciones:
if ( any(A4 < B4) )
if ( all(A4 < B4) )
Los operadores de conversión binaria asfloat, asint, etc., funcionan por componente, excepto asdouble cuyas reglas especiales están documentadas.
Los operadores de selección como los corchetes de punto, coma y matriz no funcionan por componente.
Los operadores de conversión cambian el número de componentes. Las siguientes operaciones de conversión muestran su equivalencia:
(float) i4 -> float(i4.x)
(float4)i -> float4(i, i, i, i)
Operadores aditivos y multiplicativos
Los operadores aditivos y multiplicativos son: +, -, *, /, %
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
El operador de módulo devuelve el resto de una división. Esto produce resultados diferentes al usar números enteros y de punto flotante. Los restos enteros que sean fraccionarios se truncarán.
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
El operador de módulo trunca un resto fraccionario cuando se usan números enteros.
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
El operador % solo se define en los casos en los que ambos lados son positivos o ambos lados son negativos. A diferencia de C, también funciona en tipos de datos de punto flotante, así como en números enteros.
Operador de matriz
El operador de selección de miembros de matriz "[i]" selecciona uno o varios componentes de una matriz. Es un conjunto de corchetes que contienen un índice de base cero.
int arrayOfInts[4] = { 0,1,2,3 };
arrayOfInts[0] = 2;
arrayOfInts[1] = arrayOfInts[0];
El operador de matriz también se puede usar para acceder a un vector.
float4 4D_Vector = { 0.0f, 1.0f, 2.0f, 3.0f };
float 1DFloat = 4D_Vector[1]; // 1.0f
Al agregar un índice adicional, el operador de matriz también puede acceder a una matriz.
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
El primer índice es el índice de fila de base cero. El segundo índice es el índice de columna de base cero.
Operadores de asignación
Los operadores de asignación son: =, +=, -=, *=, /=
Se pueden asignar valores literales a las variables:
int i = 1;
float f2 = 3.1f;
bool b = false;
string str = "string";
A las variables también se les puede asignar el resultado de una operación matemática:
int i1 = 1;
i1 += 2; // i1 = 1 + 2 = 3
Se puede usar una variable en cualquiera de los lados del signo igual:
float f3 = 0.5f;
f3 *= f3; // f3 = 0.5 * 0.5 = 0.25
La división de las variables de punto flotante es la esperada porque los restos decimales no suponen ningún problema.
float f1 = 1.0;
f1 /= 3.0f; // f1 = 1.0/3.0 = 0.333
Tenga cuidado si usa valores enteros que pueden dividirse, especialmente si el truncamiento afecta al resultado. Este ejemplo es idéntico al ejemplo anterior, excepto por el tipo de datos. El truncamiento provoca un resultado muy diferente.
int i1 = 1;
i1 /= 3; // i1 = 1/3 = 0.333, which gets truncated to 0
Conversiones binarias
La operación de conversión entre int y float convertirá el valor numérico en las representaciones adecuadas siguiendo las reglas de C para truncar un tipo int. La conversión de un valor float a un valor int y de nuevo a un valor float dará lugar a una conversión con pérdida de información en función de la precisión del destino.
Las conversiones binarias también se pueden realizar mediante funciones intrínsecas (DirectX HLSL), que reinterpretan la representación de bits de un número en el tipo de datos de destino.
asfloat() // Cast to float
asint() // Cast to int
asuint() // Cast to uint
Operadores bit a bit
HLSL admite los siguientes operadores bit a bit, que siguen la misma prioridad que C con respecto a otros operadores. Los operadores se describen en la siguiente tabla.
Nota:
Los operadores bit a bit requieren el modelo de sombreador 4_0 con Direct3D 10 y un hardware superior.
Operador | Función |
---|---|
~ | NOT lógico |
<< | Mayús Izq |
>> | Desplazamiento a la derecha |
& | Lógico And |
| | Lógico Or |
^ | Operador lógico Xor |
<<= | Desplazamiento a la izquierda igual |
>>= | Desplazamiento a la derecha igual |
&= | E igual |
|= | O igual |
^= | Xor igual |
Los operadores bit a bit están definidos para operar solo en tipos de datos int y uint. Si intenta usar operadores bit a bit en tipos de datos float o struct, se producirá un error.
Operadores matemáticos booleanos
Los operadores matemáticos booleanos son: &&, ||, ?:
bool b1 = true;
bool b2 = false;
bool b3 = b1 && b2 // b3 = true AND false = false
b3 = b1 || b2 // b3 = true OR false = true
A diferencia de la evaluación cortocircuitada de &&, || y ?: en C, las expresiones HLSL nunca cortocircuitan una evaluación porque son operaciones vectoriales. Todos los lados de la expresión se evalúan siempre.
Los operadores booleanos funcionan por componente. Esto significa que si compara dos vectores, el resultado es un vector que contiene el resultado booleano de la comparación de cada componente.
En el caso de las expresiones que usan operadores booleanos, el tamaño y el tipo de componente de cada variable se promocionan para que sean los mismos antes de que se produzca la operación. El tipo promocionado determina la resolución en la que tiene lugar la operación, así como el tipo de resultado de la expresión. Por ejemplo, una expresión int3 + float se promocionaría a float3 + float3 para la evaluación y su resultado sería de tipo float3.
Operador de conversión
Una expresión precedida por un nombre de tipo entre paréntesis es una conversión de tipos explícita. Una conversión de tipos convierte la expresión original en el tipo de datos de la conversión. En general, los tipos de datos simples se pueden convertir a los tipos de datos más complejos (con una conversión de promoción), pero solo algunos tipos de datos complejos se pueden convertir en tipos de datos simples (con una conversión de degradación).
Solo la conversión de tipos del lado derecho es válida. Por ejemplo, las expresiones como (int)myFloat = myInt;
no son válidas. En su lugar, use myFloat = (float)myInt;
.
El compilador también realiza la conversión implícita de tipos. Por ejemplo, las dos llamadas a métodos siguientes son equivalentes:
int2 b = int2(1,2) + 2;
int2 b = int2(1,2) + int2(2,2);
Operador coma
El operador coma (,) separa una o varias expresiones que se van a evaluar en orden. El valor de la última expresión de la secuencia se usa como valor de la secuencia.
Este es un caso sobre el que merece la pena llamar la atención. Si el tipo de constructor se deja accidentalmente fuera del lado derecho del signo igual, el lado derecho contendrá ahora cuatro expresiones, separadas por tres comas.
// 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);
El operador coma evalúa una expresión de izquierda a derecha. Esto reduce el lado derecho a:
float4 x = 1;
HLSL usa la promoción escalar en este caso, por lo que el resultado es como si fuera así:
float4 x = float4(1,1,1,1);
En este caso, dejar fuera el tipo float4 del lado derecho probablemente es un error que el compilador no puede detectar porque se trata de una instrucción válida.
Operadores de comparación
Los operadores de comparación son: <, >, ==, !=, <=, >=.
Compare los valores que sean mayores que (o menores que) cualquier valor escalar:
if( dot(lightDirection, normalVector) > 0 )
// Do something; the face is lit
if( dot(lightDirection, normalVector) < 0 )
// Do nothing; the face is backwards
O bien, compare los valores iguales a (o no iguales a) cualquier valor escalar:
if(color.a == 0)
// Skip processing because the face is invisible
if(color.a != 0)
// Blend two colors together using the alpha value
O combine ambos valores y compare los que sean mayores o iguales que (o menores o iguales a) cualquier valor escalar:
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
Cada una de estas comparaciones se puede realizar con cualquier tipo de datos escalar.
Para usar operadores de comparación con tipos de vector y matriz, use la función intrínseca all o any.
Se produce un error en esta operación porque la instrucción if requiere simplemente como respuesta bool pero recibe bool4:
if (A4 < B4)
Estas operaciones se realizan correctamente:
if ( any(A4 < B4) )
if ( all(A4 < B4) )
Operadores de prefijo o postfijo
Los operadores de prefijo y postfijo son: ++, --. Los operadores de prefijo cambian el contenido de la variable antes de evaluar la expresión. Los operadores de postfijo cambian el contenido de la variable después de evaluar la expresión.
En este caso, un bucle usa el contenido de i para realizar un seguimiento del recuento de bucles.
float4 arrayOfFloats[4] = { 1.0f, 2.0f, 3.0f, 4.4f };
for (int i = 0; i<4; )
{
arrayOfFloats[i++] *= 2;
}
Dado que se usa el operador de incremento de postfijo (++), arrayOfFloats[i] se multiplica por 2 antes de que se incremente i. Esto se puede reorganizar ligeramente para usar el operador de incremento de prefijo. Este es más difícil de leer, aunque ambos ejemplos son equivalentes.
float4 arrayOfFloats[4] = { 1.0f, 2.0f, 3.0f, 4.4f };
for (int i = 0; i<4; )
{
arrayOfFloats[++i - 1] *= 2;
}
Dado que se usa el operador de prefijo (++), arrayOfFloats[i+1 - 1] se multiplica por 2 después de que se incremente i.
El operador de decremento de prefijo y postfijo (--) se aplica en la misma secuencia que el operador de incremento. La diferencia es que el decremento resta 1 en lugar de agregar 1.
Operador de estructura
El operador de selección de miembros de la estructura (.) es un punto. Dada esta estructura:
struct position
{
float4 x;
float4 y;
float4 z;
};
Se puede leer de la siguiente manera:
struct position pos = { 1,2,3 };
float 1D_Float = pos.x
1D_Float = pos.y
Cada miembro se puede leer o escribir con el operador de estructura:
struct position pos = { 1,2,3 };
pos.x = 2.0f;
pos.z = 1.0f; // z = 1.0f
pos.z = pos.x // z = 2.0f
Operadores unarios
Los operadores unarios son: !, -, +
Los operadores unarios operan en un único operando.
bool b = false;
bool b2 = !b; // b2 = true
int i = 2;
int i2 = -i; // i2 = -2
int j = +i2; // j = +2
Prioridad de los operadores
Si una expresión contiene más de un operador, la prioridad del operador determina el orden de evaluación. La prioridad del operador de HLSL sigue la misma prioridad que C.
Comentarios
Las llaves ({,}) inician y finalizan un bloque de instrucciones. Si un bloque de instrucciones usa una sola instrucción, las llaves son opcionales.
Temas relacionados