A)     頂点シェーダリファレンス

 

頂点シェーダのレジスタや命令には独特の癖があります。

a-1レジスタ

レジスタの解説をします。表の中身は次のようになっています。

名前

表記

読み/書き

説明

1_1

2_0

2_x

3_0

ポート数

レジスタの名前

シェーダプログラムでの表記法

どのようなことができるか

 

各バージョンでの最大数

1つの命令で同時に使える数

 

a-1-1入力レジスタ (Input Register1_1, 2_0, 2_x, 3_0)

名前

表記

読み/書き

説明

1_1

2_0

2_x

3_0

ポート数

入力レジスタ

v0〜v15

頂点入力

16

16

16

16

1

入力レジスタは、バージョン1_1では、位置座標レジスタ(Position Register)と呼ばれます。ポリゴンの頂点データが与えられます。

入力レジスタは、使う前に宣言する必要があります(命令のdcl_usage項目も見てください)。

dcl_position0 v0

この宣言命令によって、入力されるデータと、頂点シェーダの入力レジスタが関連付きます。

 

a-1-2一時レジスタ(Temporary Register1_1, 2_0, 2_x, 3_0)

名前

表記

読み/書き

説明

1_1

2_0

2_x

3_0

ポート数

一時レジスタ

r0〜r11

/書

一時的に使う

12

12

12〜

12〜

3

一時レジスタは、12個あります。r0〜r11が使われます。このレジスタは読み書きできます。1つの命令に3つもの一時レジスタが使えます。バージョン2_x以降では、レジスタの数は最低12個で、実際に使える値はD3DCAPS9.VS20Caps.NumTempsに記録されています。

 

a-1-3浮動小数点数定数レジスタ(Constant Float Register1_1, 2_0, 2_x, 3_0)

名前

表記

読み/書き

説明

1_1

2_0

2_x

3_0

ポート数

定数レジスタ

c0〜c255

定数

96

256

256

256

1

定数レジスタは、頂点に共通な座標変換の行列を設定したりします。アドレスレジスタを通した読み込みもできます。

それぞれのバージョンでの最大数は、最低のシステム構成の場合で、実際に使える値はD3DCAPS9.MaxVertexShaderConstに記録されています。

IDirect3DDevice9::SetVertexShaderConstantF(レジスタ番号,ポインタ,個数)で、アプリケーションプログラムから値を設定できます。または、シェーダプログラム内でdef命令を使って値を設定します。

 

a-1-4整数型定数レジスタ(Constant Integer Register2_0, 2_x, 3_0)

名前

表記

読み/書き

説明

ポート数

反復レジスタ

i0〜i15

/書

ループ用の3要素

16

1

整数型定数レジスタは、ループの回数を設定するため等に使います。

IDirect3DDevice9::SetVertexShaderConstantI(レジスタ番号,ポインタ,個数)で、アプリケーションプログラムから値を設定できます。ポインタで指し示すアドレスは、整数型のデータ配列でないといけません。または、シェーダプログラム内でdefi命令を使って値を設定します。

 

a-1-5ブール型定数レジスタ(Constant Boolean Register2_0, 2_x, 3_0)

名前

表記

読み/書き

説明

ポート数

分岐レジスタ

b0〜b15

ブール値

16

1

IDirect3DDevice9::SetVertexShaderConstantB(レジスタ番号,ポインタ,個数)で、アプリケーションプログラムから値を設定できます。ポインタで指し示すアドレスは、BOOL型のデータ配列でないといけません。配列の次元は設定したい個数だけ必要です。

実際にはレジスタは1つだけで、内部的には16ビットの符号無し整数のレジスタとして処理されています。

 

a-1-6アドレスレジスタ(Address Register1_1, 2_0, 2_x, 3_0)

名前

表記

読み/書き

説明

ポート数

アドレスレジスタ

a0

/書

4次元アドレス

1

1

アドレスレジスタは、バージョン1_1では、a0.x だけ、バージョン2_0以降ではa0.x、a0.y、a0.z、a0.wの4つの値が使えます。このレジスタにはバージョン1_1では、「mov」命令で、それ以外のバージョンでは「mova」命令で値を書き込むことができます。

アドレスレジスタの使い道は、固定レジスタを読み込む時に、

c[a0.x+20]

のような形式でアドレスレジスタを動かしながら読むことです。

 

a-1-7ループ カウンタ レジスタ(Loop Counter Register 2_0, 2_x, 3_0)

名前

表記

読み/書き

説明

ポート数

ループカウンタレジスタ

aL

使用

ループカウンタ

1

1

ループ命令の中だけで使えます。相対アドレス指定のために使います。

 

a-1-8プレディケーション レジスタ(Predicate 2_x, 3_0)

名前

表記

読み/書き

説明

ポート数

プレディケーション

p0

/使用

動的フロー制御のためのフラグ

1

1

ループ命令の中だけで使えます。相対アドレス指定のために使います。setp命令を使って値を設定します。

 

a-1-9サンプラ レジスタ(Sampler Register 3_0)

名前

表記

読み/書き

説明

ポート数

サンプラ レジスタ

s0〜s3

テクスチャ読み込み

4

1

テクスチャサーフェスの指定につかいます。サンプラ レジスタは、テクスチャ ロード命令 texldl の引数だけに使われます。

 

a-1-10出力レジスタ(Output Register)

 

      位置(Position Register: 1_1, 2_0, 2_x)

名前

表記

読み/書き

説明

位置レジスタ

oPos

射影座標

1

射影空間の座標を出力します。この座標を元に走査線変換が行われます。全ての成分について必ず出力する必要があります。ピクセルシェーダのバージョン2_xまでは、ピクセルシェーダから参照することはできません。

 

      頂点色(Diffuse/Specular Register: 1_1, 2_0, 2_x)

名前

表記

読み/書き

説明

ディフューズ レジスタとスペキュラ レジスタ

oD0,oD1

頂点色

2

  2種類の色をピクセルシェーダに受け渡すことができます。ピクセルシェーダでは、oD0、oD1はそれぞれ、v0, v1のレジスタとして入力されます。

 

      テクスチャ座標(Texture Coordinates Register: 1_1, 2_0, 2_x)

名前

表記

読み/書き

説明

テクスチャ座標レジスタ

oT0〜oT7

テクスチャ座標

8

  8つのテクスチャ座標をピクセルシェーダに受け渡すことができます。ピクセルシェーダでは、oT0〜oT7はそれぞれ、t0〜t7のレジスタとして入力されます。

 

      フォグ濃度(Fog Register: 1_1, 2_0, 2_x)

名前

表記

読み/書き

説明

フォグレジスタ

oFog

フォグ濃度

1

  フォグ濃度はoFog.xだけが使われます。また、値の範囲は自動的に0〜1の間に制限されます。フォグ濃度は深度などのテストが終わった後にピクセルの色と合成されます。ピクセルシェーダでは値を見ることができません。

 

      スプライトサイズ(Point Size Register: 1_1, 2_0, 2_x)

名前

表記

読み/書き

説明

スプライトサイズレジスタ

oPts

スプライトサイズ

1

  スプライトサイズはoPts.xだけが使われます。パーティクルを表示する時にそのサイズとして使われます。

 

      汎用出力レジスタ(Point Size Register: 3_0)

名前

表記

読み/書き

説明

出力レジスタ

o0〜o11

結果の書き出し

12

バージョン3_0の出力レジスタは、12 個の o# (出力) レジスタにまとめらています(2 つが色、8 つがテクスチャ、1 つが位置、1 つがフォグとポイント サイズです)。出力レジスタを使うときには、出力レジスタの宣言dcl_usageをしなくてはなりません。例えば、次の構文になります。

dcl_positiont  o0.xyzw

頂点シェーダでは、少なくとも位置情報の出力はする必要があります。

 

a-2修飾子

命令数を増やさずにバリエーションを広げるために、命令やレジスタにくっつけて補正を行う記号が修飾子です。

a-2-1符号の反転 (1_1, 2_0, 2_x, 3_0)

命令の引数レジスタに使います。「-r0」と書きます。引数レジスタを−1倍した値が引数に使われます。

m3x2, m3x3, m3x4, m4x3, m4x4の命令の最後の引数は符号の反転ができません。

 

a-2-2成分の入れ換え(Swizzling: 1_1, 2_0, 2_x, 3_0)

引数レジスタの成分を入れ替えます。「r0.yzxw」のように書きます。

r0.xxxx」の場合は、「r0.x」と、1つに省略することもできます。

 

a-2-3書き込みマスク(1_1, 2_0, 2_x, 3_0)

出力するレジスタの成分を制限します。

r0.xw」のように書きます。並び順はxyzwでなければいけません。

出力レジスタに対するマスクにはいくつかの制限があります。スカラー型のレジスタoFogとoPtsでは、書き込みマスクは使えません。 oPos には、oPos.xyzwしかつかえません。 oT# には、.x か .xy か .xyz か .xyzwを指定します。

 

a-2-4絶対値(3_0)

レジスタの絶対値を取得します。

abs(r0)」のように書きます。

 

a-2-5飽和命令修飾子(3_0)

飽和命令修飾子_satは、書き込むときに、値を0から1の間に制限します。「mov_sat r0, v0」のように使います。frc 命令、sincos 命令や、テクスチャアドレッシング命令texld*、texkillには使えません。出力レジスタo#に対する出力にも使えません。

 

 

a-3命令

 

演算をするためのコマンドが命令です。命令は、バージョン1_1では128個、それ以上では256個まで使えます。

 

a-3-1設定命令(Setup Instructions)

これらの命令は頂点シェーダプログラムの一番先頭に置く必要があります。

 

      vs (バージョン情報:1_1, 2_0, 2_x, 3_0)

vs命令は必ず必要な命令です。バージョン情報の値に応じて、使える命令が決まります。

例えば次のように使います。

vs.2.0

最初の「2」がメジャーバージョン、後ろの「0」はマイナーバージョンと呼ばれます。

バージョンとしては、「1_0」、「1_1」、「2_0」、「3_0」があります。また、デバッグのための強制ソフトウェア実行のためのバージョン「2_sw」、「3_sw」というものも定義されています。

バージョンの数が大きいほど、つかる命令も多くなりますが、ハードウェア的に対応するグラフィックチップも少なくなるので、機能的に必要でないならば、なるべく小さな値を使うほうがいいでしょう。

 

      dcl_usage (入力データの宣言:1_1, 2_0, 2_x, 3_0)

頂点シェーダの入力レジスタがどの入力に割り当てられるのか宣言します。

この命令によって外部のcソースファイルと頂点シェーダプログラムのデータが結びつきます。

dcl_position v0

dcl_normal v3

dcl_texcoord0 v7

dcl_texcoord1 v7

テクスチャ座標(dcl_texcoord)など、複数の座標値を持つ場合があるので、宣言の後に何番目の入力か判断するための番号がつきます。

宣言の種類としては、11個の宣言がありえます。

dcl_position 位置座標

dcl_blendweight 座標値の合成の割合

dcl_blendindices合成する座標値の番号

dcl_normal 法線

dcl_psize 点のサイズ

dcl_diffuse 拡散光

dcl_specular 鏡面反射光

dcl_texcoord テクスチャ座標

dcl_tangent 接ベクトル

dcl_binormal 従法線ベクトル

dcl_tessfactor 曲面分割用の係数

 

      def(浮動小数点型定数の定義:1_1, 2_0, 2_x, 3_0)

定数の値をシェーダ内で決めるために使います。例えば、

def c0, 0.0f, 0.0f, 0.0f, 0.0f

のように使います。

この命令で定義された定数は外部からの設定(IDirect3DDevice9:: SetVertexShaderConstantF)よりも優先されます。

 

      defb(ブール型定数の定義:2_0, 2_x, 3_0)

ブール型のレジスタの値を設定します。

defb b0, TRUE

のように使います。代入できる値は、TRUE(真)かFALSE(偽)です。

この命令で定義された定数は外部からの設定(IDirect3DDevice9:: SetVertexShaderConstantB)よりも優先されます。

 

      defi(整数型の定数値の定義: 2_0, 2_x, 3_0)

整数型のレジスタの値を設定します。

defi i0, 0,10,1,0

のように使います。代入できる値は、TRUE(真)かFALSE(偽)です。

この命令で定義された定数は外部からの設定(IDirect3DDevice9:: SetVertexShaderConstantI)よりも優先されます。

a-3-2算術命令

これらの命令は一般的な計算をするのに用いられます。

 

      nop(なにもしません:1_1, 2_0, 2_x, 3_0

なにもしません。ほとんど使わない命令ですが、分岐命令などでの処理時間を調整するために使えそうです。

nop

ただし、バージョン1_1では、スロット数は0なので、全く何もしません。

 

      mov(コピー:1_1, 2_0, 2_x, 3_0

値を一つのレジスタから別のレジスタにコピーします。

mov r0, c0

それぞれのレジスタの成分では次の処理がなされます。

r0.x = c0.x

r0.y = c0.y

r0.z = c0.z

r0.w = c0.w

 

      mova(浮動小点数から整数への型変換: 2_0, 2_x, 3_0

mova 命令は浮動小数点数を扱うレジスタから、アドレスレジスタへ値をコピーします。与えられた浮動小数点数に一番近い整数に値を代入します(小数点以下切り捨てではありません)。

mova a0, c0

 

      add (足し算:1_1, 2_0, 2_x, 3_0)

2つのレジスタの足し算をします。

add r1, r0, c0

 

  r1.x = r0.x + c0.x

  r1.y = r0.y + c0.y

  r1.z = r0.z + c0.z

  r1.w = r0.w + c0.w

 

      sub(引き算:1_1, 2_0, 2_x, 3_0

引き算します。といっても足し算をする時に負数(-r0等)が使えるので、足し算で代用できます。まぁ、いらない命令といえばいらない命令です。

sub r1, r0, c0

 

  r1.x = r0.x - c0.x

  r1.y = r0.y - c0.y

  r1.z = r0.z - c0.z

  r1.w = r0.w - c0.w

 

      mul(掛け算:1_1, 2_0, 2_x, 3_0

各成分ごとの掛け算をします。

mul r1, r0, c0

 

  r1.x = r0.x * c0.x

  r1.y = r0.y * c0.y

  r1.z = r0.z * c0.z

  r1.w = r0.w * c0.w

 

      mad(積和:1_1, 2_0, 2_x, 3_0)

掛け算と足し算を同時に行います。それぞれの命令を別々に計算するよりも命令数が減るので、mad命令を使うほうが高速化につながります。

mad r2, r0, r1, c0

 

  r2.x = r0.x * r1.x + c0.x

  r2.y = r0.y * r1.y + c0.y

  r2.z = r0.z * r1.z + c0.z

  r2.w = r0.w* r1.w + c0.w

積和計算を使って、転置行列の計算ができます。転置行列は、

mul   r0,  c0,  r1.x

mad   r0,  c1,  r1.y,  r0

mad   r0,  c2,  r1.z,  r0

mad   r0,  c3,  r1.w,  r0

を使えば計算できます。

 

      dp3 (3成分内積:1_1, 2_0, 2_x, 3_0)

3次元ベクトルの内積を計算します。

dp3 r1, r0, c0

 

  r1.x = r1.y = r1.z = r1.w = r0.x*c0.x+ r0.y*c0.y+ r0.z*c0.z

 

      dp4 (4成分内積:1_1, 2_0, 2_x, 3_0)

4次元ベクトルの内積を計算します。

dp4 r1, r0, c0

 

  r1.w = r0.x*c0.x+ r0.y*c0.y+ r0.z*c0.z+ r0.w*c0.w

  r1.x = r1.y = r1.z :使われない

dp4命令を使えば、4次元行列と、4次元ベクトルの作用の計算ができます。例えば、

の計算は、

dp4 r1.x, r0, c0

dp4 r1.y, r0, c1

dp4 r1.z, r0, c2

dp4 r1.w, r0, c3

の命令で計算ができます(実は,この計算をまとめたものがマクロ命令のm4x4です)。

 

      dst(距離:1_1, 2_0, 2_x, 3_0

距離ベクトルを計算します。実際に行われる計算は、

crs r1, r0, c0

 

  r1.x = 1

  r1.y = r0.y *c0.y

  r1.z = r0.z

  r1.w = c0.w

です。この計算は、2つめの引数のレジスタに(使わない, d*d, d*d, 使わない)を用意しておき、3つめの引数のレジスタに(使わない, 1/d, 使わない, 1/d)を用意しておくと、べき乗(1, d, d*d, 1/d)が求まります。結果として、距離dのオイラーマクローリン展開の低次の項を求めるのに便利になります。

 

      rcp(逆数:1_1, 2_0, 2_x, 3_0

x成分の逆数を計算します。明示的に添え字がつけられているときは、添え字の成分の逆数を計算します。引数のレジスタには、どの成分を使うのか必ず1つだけ指定しなくてはなりません。

元になる数字が1.0fの時は、結果は1.0になります。元になる数字が0.0fの時は、正の無限大の値が返ります。

rcp r0, c0.w

 

  r0.x = r0.y = r0.z = r0.w = 1.0f/c0.w

頂点シェーダの命令には、割り算が無いので、割り算は、

rcp r0.w, r0.w

mul r1, r1, r0.w   ; r1 = r1÷r0.w

の方法で2命令使って、計算します。

 

      rsq(逆数平方根:1_1, 2_0, 2_x, 3_0

x成分の絶対値の逆数の平方根を計算します。明示的に添え字がつけられているときは、添え字の成分を計算します。

元になる数字が1.0fの時は、結果は1.0になります。元になる数字が0.0fの時は、正の無限大の値が返ります。

rsq r0, c0.w

 

  r0.x = r0.y = r0.z = r0.w = 1.0f / sqrt|c0.w|

 

頂点シェーダには平方根を計算する命令がありませんが、rsq命令を使えば、平方根を計算できます。

; r0.x = sqrt(r1.x)

rsq   r0.x,  r1.x             ; r0.x = 1/sqrt(r1.x)

mul   r0.x,  r1.x,  r0.x       ; r0.x = r1.x * (1/sqrt(r1.x)) = sqrt(r1.x)

 

 

      max (最大値:1_1, 2_0, 2_x, 3_0)

2つの入力のうち、大きい方を返します。

max r1, r0, c0

 

  r1.x = (r0.x<c0.x)?c0.x:r0.x

  r1.y = (r0.x<c0.x)?c0.y:r0.y

  r1.z = (r0.x<c0.x)?c0.z:r0.z

  r1.w = (r0.x<c0.x)?c0.w:r0.w

例えば、値の下限値を0に制限したいときに、

def c0, 0.0f, 0.0f, 0.0f, 0.0f

max r0, r0, c0

と計算すれば、r0が負の時でも、0に抑えることができます。

 

      min (最小値:1_1, 2_0, 2_x, 3_0)

2つの入力のうち、小さい方を返します。

min r1, r0, c0

 

  r1.x = (r0.x<c0.x)?r0.x:c0.x

  r1.y = (r0.y<c0.y)?r0.y:c0.y

  r1.z = (r0.z<c0.y)?r0.z:c0.z

  r1.w = (r0.w<c0.z)?r0.w:c0.w

例えば、値の上限値を1に制限したいときに、

def c0, 1.0f, 1.0f, 1.0f, 1.0f

max r0, r0, c0

と計算すれば、r0が1より大きい時でも、1に抑えることができます。

 

      sge(以上:1_1, 2_0, 2_x, 3_0

第2引数の値が第3引数の値以上の場合は、結果である第一引数のレジスタに 1.0 を設定します。それ以外の場合は、結果に 0.0 を返します。

sge r1, r0, c0

 

  r1.x = (r0.x>=c0.x)?1:0

  r1.y = (r0.y>=c0.y)? 1:0

  r1.z = (r0.z>=c0.z)? 1:0

  r1.w = (r0.w>=c0.w)? 1:0

 

      slt(未満:1_1, 2_0, 2_x, 3_0

1つめの引数のレジスタの値が2つめの引数のレジスタの値未満の場合は、結果のレジスタに 1.0 を設定します。それ以外の場合は、結果に 0.0 を返します。

sge r1, r0, c0

 

  r1.x = (r0.x < c0.x)?1:0

  r1.y = (r0.y < c0.y)? 1:0

  r1.z = (r0.z < c0.z)? 1:0

  r1.w = (r0.w < c0.w)? 1:0

 

      lit(光源計算:1_1, 2_0, 2_x, 3_0

この命令は光源計算の部分的な手助けをします。出力した値のy成分が平行光源の成分として、z成分がスペキュラの成分に使えます。x成分は、しいていえば環境光に使えます。バージョン1_1では、1スロットで処理しますが、バージョン2_0以降は3スロット消費します。

lit r1, r0

 

  r1.x = 1

  r1.y = max(NL, 0)

  r1.z = (NH)r0.w      (LN, HNのどちらかが負の場合は0)

  r1.w = 1

入力するレジスタの値は次の値を入れる必要があります。

r0.x = N L (法線ベクトルと光源ベクトルの内積)

r0.y = N H (法線ベクトルと半ベクトルの内積)

r0.w = スペキュラーの強さを示すべき乗 (+128 -128じゃなきゃだめ)

ハーフベクトルは、頂点から視点の方向を示す視線ベクトルと光源ベクトルの方向の平均を取ったベクトルです。N,HおよびLベクトルは規格化したものに関して内積を計算していなくてはなりません。

 

a-3-2マクロ命令

これらの命令はより複雑な計算をするのに用いられます。ほとんどの命令が2つの命令以上の命令時間がかかります。

 

      m3x23 × 2 ベクトル行列の乗算:1_1, 2_0, 2_x, 3_0

3x2行列と3次元ベクトルの計算をします。この命令は、2スロット消費します。結果のレジスタには、書き込みマスク.xyが必要です。

m3x2 r1.xy, r0, c0

 

  r1.x = r0.x*c0.x + r0.y*c0.y + r0.z*c0.z

  r1.y = r0.x*c1.x + r0.y*c1.y + r0.z*c1.z

最後の引数のレジスタは、行列の最初のレジスタを指定します。計算には、最初のレジスタ(c0)と次の数字のレジスタ(c1)が使われます。最後の引数のレジスタには、入れ換えおよび正負の反転の修飾子は使えません。

 

 

      m3x33 × 3 ベクトル行列の乗算:1_1, 2_0, 2_x, 3_0

3x3行列と3次元ベクトルの計算をします。この命令は、3スロット消費します。結果のレジスタには、書き込みマスク.xyzが必要です。

m3x3 r1.xyz, r0, c0

 

  r1.x = r0.x*c0.x + r0.y*c0.y + r0.z*c0.z

  r1.y = r0.x*c1.x + r0.y*c1.y + r0.z*c1.z

  r1.z = r0.x*c2.x + r0.y*c2.y + r0.z*c2.z

計算には、最初のレジスタ(c0)から3つのレジスタ(c2まで)が使われます。最後の引数のレジスタには、入れ換えおよび正負の反転の修飾子は使えません。

 

 

      m3x43 × 4 ベクトル行列の乗算:1_1, 2_0, 2_x, 3_0

3x4行列と3次元ベクトルの計算をします。この命令は、4スロット消費します。結果のレジスタには、書き込みマスク.xyzwが必要です。

m3x4 r1.xyzw, r0, c0

 

  r1.x = r0.x*c0.x + r0.y*c0.y + r0.z*c0.z

  r1.y = r0.x*c1.x + r0.y*c1.y + r0.z*c1.z

  r1.z = r0.x*c2.x + r0.y*c2.y + r0.z*c2.z

  r1.w = r0.x*c3.x + r0.y*c3.y + r0.z*c3.z

計算には、最初のレジスタ(c0)から4つのレジスタ(c3まで)が使われます。最後の引数のレジスタには、入れ換えおよび正負の反転の修飾子は使えません。

 

 

      m4x34 × 3 ベクトル行列の乗算:1_1, 2_0, 2_x, 3_0

4x3行列と4次元ベクトルの計算をします。この命令は、3スロット消費します。結果のレジスタには、書き込みマスク.xyzが必要です。

m4x3 r1.xyz, r0, c0

 

  r1.x = r0.x*c0.x + r0.y*c0.y + r0.z*c0.z + r0.w*c0.w

  r1.y = r0.x*c1.x + r0.y*c1.y + r0.z*c1.z + r0.w*c1.w

  r1.z = r0.x*c2.x + r0.y*c2.y + r0.z*c2.z + r0.w*c2.w

計算には、最初のレジスタ(c0)から3つのレジスタ(c2まで)が使われます。最後の引数のレジスタには、入れ換えおよび正負の反転の修飾子は使えません。

 

 

      m4x44 × 4 ベクトル行列の乗算:1_1, 2_0, 2_x, 3_0

4x4行列と4次元ベクトルの計算をします。この命令は、4スロット消費します。結果のレジスタには、書き込みマスク.xyzwが必要です。

m4x4 r1.xyzw, r0, c0

 

  r1.x = r0.x*c0.x + r0.y*c0.y + r0.z*c0.z + r0.w*c0.w

  r1.y = r0.x*c1.x + r0.y*c1.y + r0.z*c1.z + r0.w*c1.w

  r1.z = r0.x*c2.x + r0.y*c2.y + r0.z*c2.z + r0.w*c2.w

  r1.w = r0.x*c3.x + r0.y*c3.y + r0.z*c3.z + r0.w*c3.w

計算には、最初のレジスタ(c0)から4つのレジスタ(c3まで)が使われます。最後の引数のレジスタには、入れ換えおよび正負の反転の修飾子は使えません。

 

 

      abs (絶対値: 2_0, 2_x, 3_0)

入力した値の絶対値を求めます。この命令は、1スロット消費します。

abs r0, c0

 

  r0.x = |c0.x|

  r0.y = |c0.y|

  r0.z = |c0.z|

  r0.w = |c0.w|

バージョン1_1では、abs命令は使えませんが、max命令を使えばabs命令を作ることができます。

max   r0,  r1, -r1     ; r0 = |r1|

 

      sgn(符号: 2_0, 2_x, 3_0

入力した値が正か負かに応じて1か−1の値を返します。この命令は3スロット消費します。

abs r0, c0

 

  r0.x = (c0.x<0)?-1:( (0<c0.x)?+1:0);

  r0.y = (c0.y<0)?-1:( (0<c0.y)?+1:0);

  r0.z = (c0.z<0)?-1:( (0<c0.z)?+1:0);

  r0.w = (c0.w<0)?-1:( (0<c0.w)?+1:0);

入力するレジスタと出力するレジスタは違うものにする必要があります。

バージョン1_1では、sgn命令は使えませんが、slt命令を使えばsgn命令を作ることができます。

def   c0,  0.0f,  0.0f,  0.0f,  0.0f

slt   r1,  r0,  c0.x

slt   r0, -r0,  c0.x

add   r0,  r0, -r1

 

      crs(外積: 2_0, 2_x, 3_0

ベクトルの外積を計算します。この命令は2スロット消費します。

crs r1.xyz, r0, c0

 

  r1.x = r0.y * c0.z – r0.z*c0.y

  r1.y = r0.z * c0.x – r0.y*c0.z

  r1.z = r0.x * c0.y – r0.x*c0.y

書き込みマスクには、.x、.y、.z、.xy、.xz、.yz、.xyzを指定しなくてはなりません。引数と結果のレジスタは全て別のレジスタにしないといけません。結果を格納するレジスタは一時レジスタr#でなくてはいけません(つまり、出力レジスタを指定してはいけないということです)。

バージョン1_1では、crs命令は使えませんが、成分の入れ替えを使えばcrs命令を作ることができます。

mul   r1,  r0.yzxw,  c0.zxyw

mad   r1, - c0.yzxw,  r0.zxyw,  r1

 

      nrm(正規化: 2_0, 2_x, 3_0

3次元ベクトルを正規化します。この命令は3スロット消費します。

nrm r1, r0

 

  r1.x = r0.x / d

  r1.y = r0.y / d

  r1.z = r0.z / d

   

この命令は入力に使うレジスタと結果に使うレジスタを同じレジスタにすることは出来ません。

バージョン1_1では、nrm命令は使えませんが、rsq命令を使えばnrm命令を作ることができます。

dp3  r1.x,  r0                ; r1.x = r0r0

rsq   r1.x,  r1.x               ; r1.x = 1/sqrt(r1.x)

mul   r1.xyz,  r1.x,  r0        ; r1.xyz = r0.xyz * (1/sqrt(r1.x)) = r0.xyz/ sqrt(r0r0)

 

 

      lrp(線形補間: 2_0, 2_x, 3_0

3つめの引数のレジスタと、4つめの引数のレジスタを2つめの引数の重みで線形補間します。この命令は2スロット消費します。

lrp r2, c0, r0, r1

 

  r2.x = c0.x*r0.x + (1-c0.x)*r1.x

  r2.y = c0.y*r0.y + (1-c0.y)*r1.y

  r2.z = c0.z*r0.z + (1-c0.z)*r1.z

  r2.w = c0.w*r0.w + (1-c0.w)*r1.w

 

      expp (精度が低い2を底とする指数:1_1, 2_0, 2_x, 3_0)

2を底とする10ビットの部分精度の指数を求めます。入力が負の値の場合の結果は定められていないので、正の値で入力しなくてはなりません。それぞれの成分には次の値が入力されます。z成分に指数の値が返ります。

out.x = 2 ^ (int)in.w

out.y = 小数部(in.w)

out.z = 2 ^ in.w (近似解)

out.w = 1.0

実際に使うときは、

expp r0, c0.w

のように、入力するレジスタの成分を書き下す必要があります。

 

      exp(完全精度の2を底とする指数:1_1, 2_0, 2_x, 3_0

最低でも仮数部が21ビットの精度を持った2を低とする指数を求めます。この命令は、バージョン1_1では10スロット消費しますが、2_0以上では1スロット消費します。

exp r0, c0.w

 

  r0.x = r0.y = r0.z = r0.w = 2c0.w

 

      logp (精度が低い2を底とする対数:1_1, 2_0, 2_x, 3_0)

2を底とする10ビットの部分精度の対数を求めます。入力した数の絶対値の対数が結果として返ります。入力した値が0の時は負の無限大が返ります。

logp r0, c0.w

 

  r0.x=r0.y=r0.z=r0.w = log|c0.w|/log2

 

      log(完全精度の2を底とする対数:1_1, 2_0, 2_x, 3_0

最低でも仮数部が21ビットの精度を持った2を低とする対数を求めます。この命令は、バージョン1_1では10スロット消費しますが、2_0以上では1スロット消費します。

log r0, c0.w

 

  r0.x=r0.y=r0.z=r0.w = log|c0.w|/log2

入力した数の絶対値の対数が結果として返ります。入力した値が0の時は負の無限大が返ります。

 

 

      pow(べき乗: 2_0, 2_x, 3_0

15ビットの精度を持つべき乗の計算をします。この命令は3スロット消費します。入力に使うレジスタには、どの成分を使うかしてしなくてはなりません。結果は全ての成分に同じ値が入力されます。底となるレジスタの値は絶対値をとったものが使われます。

pow r1, c0.w, r0.w

 

  r1.x=r1.y=r1.z=r1.w = |r0.w|c0.w

結果を入れるレジスタは、一時レジスタでなければいけません。さらに、最後の引数と同じレジスタもつかえません。

 

 

      sincos(サイン、コサイン: 2_0, 2_x, 3_0

サインとコサインを計算します。この命令は8スロット消費します。

sincos r1, r0.w, c0, c1

 

 −π≦r0.w≦πの範囲に収まる必要がある

c0 = (-1.f/(7!*128), -1.f/(6!*64), 1.f/(4!*16), 1.f/(5!*16))

c1 = (-1.f/(3!*8), -1.f/(2!*8), 1.f, 0.5f)

の定数レジスタでなければいけない。

 

  r1.x = cos(r0.w)

  r1.y = sin(r0.w)

誤差の最大値は0.02になります。

 

 

      frc(小数部:1_1, 2_0, 2_x, 3_0

入力された数値の小数部を返します。この命令は、バージョン1_1では3スロット消費しますが、2_0以上では1スロット消費します。結果は必ず0.0から1.0の間に収まります。

frc r0, c0

バージョン1_1を使うときには、書き込みマスクを.xyもしくは.yのどちらかにしなくてはなりません。

 

 

 

a-3-3フロー制御

条件分岐による制御を行います。頂点シェーダ2_0から使えるようになりました。ただし、計算結果を使って分岐を行う動的フロー制御は、2_xから導入されたプレディクションレジスタによる処理の切り替えとして実装されます。

 

      ifelseendif (分岐: 2_0, 2_x, 3_0)

 

分岐レジスタの値に応じて、2つの処理を切り替えます。if命令は3スロット、elseは1スロット、endif命令は1スロット消費します。

if b0

なんかの処理

else

べつの処理

endif

b0が1(TRUE)の時は、if〜elseの間にある命令が実行されます。b0が0(FALSE)の時は、else〜endifの間の命令が実行されます。if ブロックはネストすることができますが、loop ブロックをまたぐことはできません。

 

      if_comp (比較に伴う分岐: 2_x, 3_0)

 

2つのレジスタを比較して、その結果に応じてそれぞれ別の命令を実行します。if_comp命令は3スロット消費します。

if_lt r3.x, r4.y

// r3.x < r4.y の時に実行する命令

else

// r3.x >= r4.y の時に実行する命令

endif

比較の内容には、次の種類があります。レジスタの成分は必ず指定しなくてはなりません。

構文

比較

(if_comp src0, src1でTRUEになる場合)

_gt

より大きい

(src0 > src1)

_lt

より小さい

(src0 < src1)

_ge

以上

(src0 >= src1)

_le

以下

(src0 <= src1)

_eq

等しい

(src0 == src1)

_ne

等しくない

(src0 != src1)

if_compは、if predと一緒に24階層までネストできます。

 

      if pred (プレディケーションに基く分岐条件: 2_x, 3_0)

 

レディケーション レジスタの内容に基づいて命令を使い分けます。if pred命令は3スロット消費します。

if p0.適当な成分

なんかの処理

else

べつの処理

endif

否定演算子!を使うことによって、p0がFALSEの時の分岐が実現できます。

if !p0.適当な成分

 

if predは、if_compと一緒に24階層までネストできます。

 

 

      callret, label (サブルーチン呼び出し: 2_0, 2_x, 3_0)

 

サブルーチンは、labelとretでくくられた命令を呼び出して実行します。call命令は2スロット、retは1スロット、label命令は0スロット消費します。

call 1

なんかの処理

 

label 1

サブルーチン命令

ret

labelとして使える数字は2_0、2_xでは0〜15、3_0では0〜2047です。Labelの位置は、call命令の後ろに置かなければなりません。

2_0では、再帰はできません。3_0では、4階層まで再帰できます。2_xでは、D3DCAPS9.VS20Caps.StaticFlowControlDepthの値によってネストの深さが決まります。

 

      callnz (条件付きサブルーチン呼び出し: 2_x, 3_0)

 

条件付きサブルーチンは、分岐レジスタの値がTRUEの場合にサブルーチンを実行します。callnz命令は3スロット消費します。

callnz ラベル番号, b#

 

      callnz pred (プレディケーションに基くサブルーチン呼び出し: 2_x, 3_0)

 

プレディケーションに基くサブルーチン呼び出しは、プレディケーション レジスタの値がTRUE(!がついている場合はFALSE)の場合にサブルーチンを実行します。callnz pred命令は3スロット消費します。

callnz ラベル番号, [!] p0. 適当な成分

 

      rependret, label (反復: 2_0, 2_x, 3_0)

 

反復は、反復レジスタを見て処理を繰り返します。rep命令は3スロット、endret命令は2スロット消費します。

rep i0

ループ内処理

endrep

整数レジスタのx成分は繰り返し回数になります。ループの最大回数は255回です。反復はネストできません。反復のループの中にジャンプして入ってきたり、飛び出たりすることはできません。また、ifブロックをまたぐこともできません。break命令や、break_comp、break pred 命令でループを抜けることができます。

 

      loopendloop (反復ループ: 2_0, 2_x, 3_0)

 

反復ループは、整数レジスタi#を見て処理を繰り返すと共に、ループカウンタaLを使って、定数レジスタの番号をずらしながら読み込めます。loop命令は3スロット、endloop 命令は2スロット消費します。

loop aL, i0

ループ内処理 (aLが定数レジスタの指定に使える)

endloop

i0.xにループ回数、i0.yにaLレジスタの初期値、i0.zにaLレジスタの増加数を入れます。ループはネストできません。if文をまたげません。break命令や、break_comp、break pred 命令でループを抜けることができます。ループの初期値およびループの繰り返し数は負にできません。

 

      break, break_comp, break pred (反復ループ: 2_x, 3_0)

 

repまたはloopによるフロー制御を中断します。break命令は1スロット、break_comp, break pred 命令は3スロット消費します。break_compは、2つのレジスタの比較に伴うループの中断をします。

break_comp src0, src1

比較修飾子_compは、if_compと同じ修飾子が使えます。

break predは、プレディクションレジスタを比較してループの中断をします。

break [!]p0.成分

否定修飾子「!」をつけると、p0がFALSEの時にループを中断します。

 

      setp (プレディケーションレジスタの設定: 2_x, 3_0)

 

レジスタの比較によって、プレディケーションレジスタを設定します。setp命令は1スロット消費します。

setp_comp p0, src0, src1

比較修飾子_compには、次の種類があります。

構文

比較

(setp_comp p0, src0, src1でTRUEになる場合)

_gt

より大きい

(src0 > src1)

_lt

より小さい

(src0 < src1)

_ge

以上

(src0 >= src1)

_le

以下

(src0 <= src1)

_eq

等しい

(src0 == src1)

_ne

等しくない

(src0 != src1)

プレディケーションレジスタは、if pred、callnz pred、break pred以外に、次の構文を使って、任意の算術命令やテクスチャ命令の実行を制御できます。ただし、命令スロットを1消費します。

([!]p0[.成分]) 命令 dest, src0, ...

プレディケーションレジスタの成分の指定には、.xyzw, もしくは1つだけの成分、.x, .y. .z, .wを指定することができます。