式は、演算子によって区切られた 変数 およびリテラルのシーケンスです。 演算子は、変数とリテラルの結合方法、比較方法、選択方法などを決定します。 演算子は次のとおりです。
オペレーター名 | 演算子 |
---|---|
加法演算子と乗法演算子 | +、-、*、/、% |
配列演算子 | [i] |
代入演算子の | =、+=、-=、*=、/=、%= |
バイナリ キャスト の | float および int の C 規則、bool の C 規則または HLSL 組み込み関数 |
ビット演算子 の | ~、<<、>>、&、|、^、<<=、>>=、&=、|=、^= |
ブール演算演算子 | & &、||、?: |
キャスト 演算子の | (型) |
コンマ演算子 | , |
比較演算子の | <、>、=、!=、<=、>= |
プレフィックス演算子または後置演算子 を する | ++, -- |
構造体演算子の | . |
単項演算子の | !, -, + |
演算子の多くはコンポーネント単位です。つまり、操作は各変数の各コンポーネントに対して個別に実行されます。 たとえば、1 つのコンポーネント変数に 1 つの操作が実行されます。 一方、4 つのコンポーネント変数には、コンポーネントごとに 1 つずつ、4 つの操作が実行されます。
+ や *など、値に対して何かを行うすべての演算子は、コンポーネントごとに機能します。
すべてのを使用するか、または複数コンポーネント変数を持つ組み込み関数をしない限り、比較演算子では 1 つのコンポーネントが動作する必要があります。 if ステートメントでは 1 つのブール値が必要ですが、bool4 を受け取るため、次の操作は失敗します。
if (A4 < B4)
次の操作は成功します。
if ( any(A4 < B4) )
if ( all(A4 < B4) )
二項キャスト演算子 、asfloat、asintなど、特殊な規則が文書化されている 同じ を除き、コンポーネントごとに動作します。
ピリオド、コンマ、配列角かっこなどの選択演算子は、コンポーネントごとに機能しません。
キャスト演算子は、コンポーネントの数を変更します。 次のキャスト操作は、その等価性を示しています。
(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
剰余演算子は、整数を使用すると小数部の剰余を切り捨てます。
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]" は、配列内の 1 つ以上のコンポーネントを選択します。 これは、0 から始まるインデックスを含む角かっこのセットです。
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
最初のインデックスは、0 から始まる行インデックスです。 2 番目のインデックスは、0 から始まる列インデックスです。
代入演算子
代入演算子は、=、+=、-=、*=、/= です。
変数にはリテラル値を割り当てることができます。
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
10 進剰余は問題ではないため、浮動小数点変数の除算は想定どおりに行われます。
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 の間でキャスト操作を行うと、int 型を切り捨てる C 規則に従って数値が適切な表現に変換されます。 float から int に値をキャストし、float に戻すと、ターゲットの精度に基づいて損失が発生します。
バイナリ キャストは、組み込み関数 (DirectX HLSL)を使用して実行することもできます。これは、数値のビット表現をターゲット データ型に再解釈します。
asfloat() // Cast to float
asint() // Cast to int
asuint() // Cast to uint
ビット演算子
HLSL では、他の演算子に関して C と同じ優先順位に従う次のビット演算子がサポートされています。 次の表では、演算子について説明します。
手記
ビットごとの演算子には、Direct3D 10 以降のハードウェア シェーダー モデル 4_0 が必要です。
演算子 | 機能 |
---|---|
~ | 論理 Not |
<< | 左シフト |
>> | 右シフト |
& | 論理および |
| | 論理または |
^ | 論理 Xor |
<<= | 左シフト (等しい) |
>>= | 右シフト (等号) |
&= | 等しい |
|= | または等しい |
^= | Xor Equal |
ビット演算子は、int データ型と uint データ型でのみ動作するように定義されています。 float または構造体データ型でビット演算子を使用しようとすると、エラーが発生します。
ブール演算演算子
ブール演算演算子は、&&、||、?:
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 式はベクター演算であるため、評価を短絡することはありません。 式のすべての側面が常に評価されます。
ブール演算子は、コンポーネントごとに機能します。 つまり、2 つのベクトルを比較した場合、結果は各コンポーネントの比較のブール値の結果を含むベクターになります。
ブール演算子を使用する式の場合、各変数のサイズとコンポーネント型は、操作が行われる前に同じに昇格されます。 昇格された型は、操作が実行される解像度と、式の結果の型を決定します。 たとえば、int3 + float 式は評価のために float3 + float3 に昇格され、結果は float3 型になります。
Cast 演算子
かっこ内に型名が付いた式は、明示的な型キャストです。 型キャストは、元の式をキャストのデータ型に変換します。 一般に、単純なデータ型は (昇格キャストを使用して) より複雑なデータ型にキャストできますが、単純なデータ型 (降格キャストを使用) にキャストできるのは一部の複合データ型のみです。
右辺型鋳造のみが有効です。 たとえば、(int)myFloat = myInt;
などの式は無効です。 代わりに myFloat = (float)myInt;
を使用してください。
コンパイラは、暗黙的な型キャストも実行します。 たとえば、次の 2 つの式は同等です。
int2 b = int2(1,2) + 2;
int2 b = int2(1,2) + int2(2,2);
コンマ演算子
コンマ演算子 (,) は、順番に評価される 1 つ以上の式を区切ります。 シーケンス内の最後の式の値は、シーケンスの値として使用されます。
注意を呼び出す価値のあるケースを次に示します。 コンストラクターの型が誤って等号の右側から離れた場合、右側には 3 つのコンマで区切られた 4 つの式が含まれるようになりました。
// 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 ステートメントには 1 つのブール値が必要ですが、bool4 を受け取るため、この操作は失敗します。
if (A4 < B4)
これらの操作は成功します。
if ( any(A4 < B4) )
if ( all(A4 < B4) )
プレフィックス演算子または後置演算子
プレフィックス演算子と後置演算子は、++、--.です。 プレフィックス演算子は、式が評価される前に変数の内容を変更します。 後置演算子は、式の評価後に変数の内容を変更します。
この場合、ループはiの内容を使用してループカウントを追跡します。
float4 arrayOfFloats[4] = { 1.0f, 2.0f, 3.0f, 4.4f };
for (int i = 0; i<4; )
{
arrayOfFloats[i++] *= 2;
}
後置インクリメント演算子 (++) が使用されるため、i がインクリメントされる前に arrayOfFloats[i] に 2 が乗算されます。 これは、プレフィックスインクリメント演算子を使用するように少し並べ替えることができます。 これは読みにくいですが、両方の例が同等です。
float4 arrayOfFloats[4] = { 1.0f, 2.0f, 3.0f, 4.4f };
for (int i = 0; i<4; )
{
arrayOfFloats[++i - 1] *= 2;
}
プレフィックス演算子 (++) が使用されるため、i がインクリメントされた後、arrayOfFloats[i+1 - 1] に 2 が乗算されます。
プレフィックスデクリメントおよび後置デクリメント演算子 (--) は、インクリメント演算子と同じシーケンスで適用されます。 違いは、デクリメントでは 1 を加算するのではなく 1 を減算するという点です。
Structure 演算子
構造体メンバー選択演算子 (.) はピリオドです。 この構造を考えると、次のようになります。
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
単項演算子
単項演算子は次のとおりです: , -, +
単項演算子は、1 つのオペランドで動作します。
bool b = false;
bool b2 = !b; // b2 = true
int i = 2;
int i2 = -i; // i2 = -2
int j = +i2; // j = +2
演算子の優先順位
式に複数の演算子が含まれている場合、演算子の優先順位によって評価の順序が決まります。 HLSL の演算子の優先順位は、C と同じ優先順位に従います。
備考
中かっこ ({,}) ステートメント ブロックを開始および終了します。 ステートメント ブロックで 1 つのステートメントを使用する場合、中かっこは省略可能です。
関連トピック