共用方式為


運算子

表達式是由運算符標點符號的變數和常值序列。 運算符會決定變數和常值如何結合、比較、選取等等。 運算子包括:

操作員名稱 操作員
加法和乘法運算符 +, -, *, /, %
陣列運算子 [i]
指派運算子 =, +=, -=, *=, /=, %=
二進位轉換 適用於 float 和 int 的 C 規則、C 規則或 bool 的 HLSL 內部函數
位元運算子 ~、、 <<、、 >>|、^、 <<=、 >>=、|=、|=、^=
布爾數學運算符 & &, ||, ?:
轉換運算元 (類型)
逗號運算子 ,
比較運算子 <、 >、==、!=、=、 <=、 >=
前置詞或後置運算符 ++, --
結構運算元 .
一元運算子 !, -, +

 

許多運算子都是個別元件,這表示作業會針對每個變數的每個元件獨立執行。 例如,單一元件變數已執行一個作業。 另一方面,四個元件變數有四個作業執行,每個元件各執行一個作業。

對值執行某些動作的所有運算符,例如 + 和 *,每個元件都會運作。

比較運算子需要單一元件才能運作,除非您使用all或任何內建函式搭配多元件變數。 下列作業失敗,因為 if 語句需要單一 bool,但會收到 bool4:

if (A4 < B4)

下列作業成功:

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

二進位轉換運算符 asfloatasint 等每個元件的工作,除了記錄特殊規則的雙倍。

選取運算子,例如句號、逗號和數位括弧,無法依每個元件運作。

轉換運算子會變更元件數目。 下列轉換作業會顯示其等價:

(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]」 會選取數位中的一或多個元件。 它是一組方括弧,其中包含以零起始的索引。

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,然後轉換回 float 會導致根據目標的精確度進行遺失轉換。

二進位轉換也可以使用內部函數 (DirectX HLSL)來執行,其會將數位的位表示重新解譯成目標數據類型。

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

位元運算子

HLSL 支援下列位運算元,其與其他運算元遵循與 C 相同的優先順序。 下表描述運算符。

 

運算子 函式
~ 邏輯 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 表達式絕對不會縮短評估,因為它們是向量作業。 一律會評估表達式的所有部分。

布爾運算子會根據每個元件運作。 這表示,如果您比較兩個向量,則結果會是一個向量,其中包含每個元件的比較布爾值結果。

對於使用布爾運算子的表達式,每個變數的大小和元件類型都會在作業發生之前升階為相同。 升階類型會決定作業的發生解析度,以及表達式的結果類型。 例如,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

每個比較都可以使用任何純量數據類型來完成。

若要搭配向量和矩陣類型使用比較運算子,請使用all或任何內部函數。

此作業失敗,因為 if 語句需要單一 bool,但會收到 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; 
}

因為使用後置遞增運算符 (++) ,因此 arrayOfFloats[i] 會乘以 2,然後再遞增 i。 這可能會稍微重新排列,以使用前置遞增運算符。 雖然這兩個範例都相等,但這一個比較難閱讀。

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

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

因為使用前置詞運算符 (++) ,因此 arrayOfFloats[i+1 - 1] 會在 i 遞增之後乘以 2。

前置詞遞減和後置遞減運算子 (--) 會套用與遞增運算符相同的序列。 差異在於遞減減 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 相同的優先順序。

備註

大括弧 ({,}) 開始和結束語句區塊。 當語句區塊使用單一語句時,大括弧是選擇性的。

語句 (DirectX HLSL)