Операторы
Выражения — это последовательности переменных и литералы, препинаемые операторами. Операторы определяют, как объединяются переменные и литералы, сравниваются, выбираются и т. д. К операторам относятся:
имя оператора; | Операторы |
---|---|
Аддитивные и умножительные операторы | +, -, *, /, % |
Оператор массива | [i] |
Операторы присваивания | =, +=, -=, *=, /=, %= |
Двоичные приведения | Правила C для операций с плавающей запятой и int, правил C или встроенных функций HLSL для bool |
Битовые операторы | ~, <<, >>&, |, ^, ^ <<, =, >>=, &=, |=, ^= |
Логические математические операторы | & &, ||, ?: |
Оператор приведения | (тип) |
Оператор запятой | , |
Операторы сравнения | <, >==, !=, =, =, <>= |
Префикс или операторы postfix | ++, -- |
Оператор структуры | . |
Унарные операторы | !, -, + |
Многие операторы являются отдельным компонентом, что означает, что операция выполняется независимо для каждого компонента каждой переменной. Например, одна переменная компонента выполняет одну операцию. С другой стороны, четырехкомпонентная переменная имеет четыре операции, по одному для каждого компонента.
Все операторы, которые делают что-то с значением, например +и *, работают на компонент.
Операторы сравнения требуют, чтобы один компонент работал, если вы не используете все или любую встроенную функцию с переменной с несколькими компонентами. Следующая операция завершается ошибкой, так как оператор if требует одно логическое значение, но получает bool4:
if (A4 < B4)
Следующие операции выполняются успешно:
if ( any(A4 < B4) )
if ( all(A4 < B4) )
Операторы двоичного приведения asfloat, asint и т. д. для каждого компонента, за исключением asdouble, специальные правила которых документируются.
Операторы выбора, такие как период, запятая и квадратные скобки массива, не работают для каждого компонента.
Операторы приведения изменяют количество компонентов. Следующие операции приведения показывают их эквивалентность:
(float) i4 -> float(i4.x)
(float4)i -> float4(i, i, i, i)
Аддитивные и умножительные операторы
Аддитивные и мультипликативные операторы: +, -, *, /, %
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
Оператор модуля возвращает оставшуюся часть деления. Это приводит к различным результатам при использовании целых чисел и чисел с плавающей запятой. Целые оставшиеся числа, которые являются дробными, будут усечены.
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
Оператор modulus усечение дробного остатка при использовании целых чисел.
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
Оператор %определяется только в тех случаях, когда обе стороны являются положительными или обе стороны отрицательными. В отличие от C, он также работает с типами данных с плавающей запятой, а также целыми числами.
Оператор массива
Оператор выбора элементов массива "[i]" выбирает один или несколько компонентов в массиве. Это набор квадратных квадратных скобок, содержащих отсчитываемый от нуля индекс.
int arrayOfInts[4] = { 0,1,2,3 };
arrayOfInts[0] = 2;
arrayOfInts[1] = arrayOfInts[0];
Оператор массива также можно использовать для доступа к вектору.
float4 4D_Vector = { 0.0f, 1.0f, 2.0f, 3.0f };
float 1DFloat = 4D_Vector[1]; // 1.0f
Добавив дополнительный индекс, оператор массива также может получить доступ к матрице.
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
Первый индекс — это отсчитываемый от нуля индекс строк. Второй индекс — это отсчитываемый от нуля индекс столбца.
Операторы присваивания
Операторы назначения: =, +=, -=, *=, /=
Переменные могут быть назначены литеральными значениями:
int i = 1;
float f2 = 3.1f;
bool b = false;
string str = "string";
Переменные также можно назначить результат математической операции:
int i1 = 1;
i1 += 2; // i1 = 1 + 2 = 3
Переменная может использоваться с любой стороны знака равенства:
float f3 = 0.5f;
f3 *= f3; // f3 = 0.5 * 0.5 = 0.25
Деление переменных с плавающей запятой как ожидалось, так как десятичные останки не являются проблемой.
float f1 = 1.0;
f1 /= 3.0f; // f1 = 1.0/3.0 = 0.333
Будьте осторожны, если вы используете целые числа, которые могут быть разделены, особенно если усечение влияет на результат. Этот пример идентичен предыдущему примеру, за исключением типа данных. Усечение приводит к очень другому результату.
int i1 = 1;
i1 /= 3; // i1 = 1/3 = 0.333, which gets truncated to 0
Двоичные приведения
Операция приведения между int и float преобразует числовое значение в соответствующие представления, приведенные в правилах C для усечения типа int. Приведение значения от float к int и обратно к плавающему значению приведет к потере преобразования на основе точности целевого объекта.
Двоичные приведения также могут выполняться с помощью встроенных функций (DirectX HLSL), которые повторно интерпретируют битовое представление числа в целевом типе данных.
asfloat() // Cast to float
asint() // Cast to int
asuint() // Cast to uint
Битовые операторы
HLSL поддерживает следующие битовые операторы, которые соответствуют тому же приоритету, что и C относительно других операторов. В следующей таблице описаны операторы.
Примечание.
Для побитовых операторов требуется модель шейдера 4_0 с direct3D 10 и более поздних версий оборудования.
Оператор | Function |
---|---|
~ | Логическое НЕ |
<< | Клавиша SHIFT слева |
>> | Смена вправо |
& | Логическое «И» |
| | Логические или |
^ | Логический Xor |
<<= | Левая смена равно |
>>= | Равный сдвиг вправо |
&= | И равно |
|= | Или равно |
^= | Xor Equal |
Побитовые операторы определяются для работы только с типами данных int и uint. При попытке использовать битовые операторы в плавающем или структурном типе данных возникает ошибка.
Логические математические операторы
Логические математические операторы: &&, ||, ?:
bool b1 = true;
bool b2 = false;
bool b3 = b1 && b2 // b3 = true AND false = false
b3 = b1 || b2 // b3 = true OR false = true
В отличие от оценки короткого канала &&, ||и ?: в выражениях C, HLSL никогда не прерывать оценку, так как они являются векторными операциями. Все стороны выражения всегда вычисляются.
Логические операторы работают на основе каждого компонента. Это означает, что при сравнении двух векторов результатом является вектор, содержащий логический результат сравнения для каждого компонента.
Для выражений, использующих логические операторы, размер и тип компонента каждой переменной повышаются до возникновения операции. Повышенный тип определяет разрешение, в котором выполняется операция, а также тип результата выражения. Например, выражение int3 + float будет повышено до float3 + float3 для оценки, и его результат будет иметь тип float3.
Оператор приведения
Выражение, предшествуемое имени типа в скобках, является явным приведением типов. Приведение типа преобразует исходное выражение в тип данных приведения. Как правило, простые типы данных можно привести к более сложным типам данных (с повышением приведения), но только некоторые сложные типы данных можно привести к простым типам данных (с приведением понижения).
Только правой рукой тип литья является законным. Например, выражения, такие как (int)myFloat = myInt;
незаконные. Вместо этого используйте myFloat = (float)myInt;
.
Компилятор также выполняет неявное приведение типов. Например, следующие два выражения эквивалентны:
int2 b = int2(1,2) + 2;
int2 b = int2(1,2) + int2(2,2);
Оператор запятой
Оператор запятых (,) отделяет одно или несколько выражений, которые необходимо оценить по порядку. Значение последнего выражения в последовательности используется в качестве значения последовательности.
Вот один случай стоит привлечь внимание к. Если тип конструктора случайно ушел от правой стороны знака равенства, справа теперь содержит четыре выражения, разделенные тремя запятыми.
// 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);
Оператор запятой вычисляет выражение слева направо. Это сокращает правую сторону:
float4 x = 1;
HLSL использует скалярное продвижение в этом случае, поэтому результат выглядит так, как если бы это было записано следующим образом:
float4 x = float4(1,1,1,1);
В этом экземпляре выход из типа float4 с правой стороны, вероятно, является ошибкой, которую компилятор не может обнаружить, так как это допустимая инструкция.
Операторы сравнения
Операторы сравнения: <, >==, !=, =, =, =, <>=.
Сравните значения, превышающие (или меньше) любое скалярное значение:
if( dot(lightDirection, normalVector) > 0 )
// Do something; the face is lit
if( dot(lightDirection, normalVector) < 0 )
// Do nothing; the face is backwards
Или сравнивайте значения, равные (или не равным) скалярным значениям:
if(color.a == 0)
// Skip processing because the face is invisible
if(color.a != 0)
// Blend two colors together using the alpha value
Или сочетайте оба значения и сравнивайте значения, которые больше или равно (или меньше или равно) любому скалярного значения:
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
Каждое из этих сравнений можно выполнить с любым скалярным типом данных.
Чтобы использовать операторы сравнения с типами векторов и матриц, используйте все или любую встроенную функцию.
Эта операция завершается ошибкой, так как оператор if требует одно логическое значение, но получает bool4:
if (A4 < B4)
Эти операции выполняются успешно:
if ( any(A4 < B4) )
if ( all(A4 < B4) )
Префикс или операторы postfix
Операторы префикса и постфикса: ++, --. Операторы префикса изменяют содержимое переменной перед вычислением выражения. Операторы postfix изменяют содержимое переменной после вычисления выражения.
В этом случае цикл использует содержимое i для отслеживания количества циклов.
float4 arrayOfFloats[4] = { 1.0f, 2.0f, 3.0f, 4.4f };
for (int i = 0; i<4; )
{
arrayOfFloats[i++] *= 2;
}
Так как используется оператор добавочного числа постфикса (++), массивOfFloats[i] умножается на 2 перед увеличением i. Это может быть немного изменено для использования оператора добавочного префикса. Это трудно прочитать, хотя оба примера эквивалентны.
float4 arrayOfFloats[4] = { 1.0f, 2.0f, 3.0f, 4.4f };
for (int i = 0; i<4; )
{
arrayOfFloats[++i - 1] *= 2;
}
Так как используется оператор префикса (++), массивOfFloats[i+1 – 1] умножается на 2 после увеличения i.
Оператор декремента префикса и дефикса (-) применяются в той же последовательности, что и оператор добавок. Разница заключается в том, что уменьшение вычитает 1 вместо добавления 1.
Оператор структуры
Оператор выбора элементов структуры (.) — это период. Учитывая эту структуру:
struct position
{
float4 x;
float4 y;
float4 z;
};
Его можно прочитать следующим образом:
struct position pos = { 1,2,3 };
float 1D_Float = pos.x
1D_Float = pos.y
Каждый элемент можно считывать или записывать с помощью оператора структуры:
struct position pos = { 1,2,3 };
pos.x = 2.0f;
pos.z = 1.0f; // z = 1.0f
pos.z = pos.x // z = 2.0f
Унарные операторы
Унарные операторы: , -, +
Унарные операторы работают на одном операнде.
bool b = false;
bool b2 = !b; // b2 = true
int i = 2;
int i2 = -i; // i2 = -2
int j = +i2; // j = +2
Приоритет операторов
Если выражение содержит несколько операторов, приоритет оператора определяет порядок оценки. Приоритет оператора для HLSL следует тому же приоритету, что и C.
Замечания
Фигурные скобки ({,}) начинаются и заканчиваются блоком инструкций. Если блок инструкций использует одну инструкцию, фигурные скобки являются необязательными.
См. также