C)    エフェクトファイルリファレンス

 

エフェクトファイルとして書くHLSLの言語仕様を見てみましょう。HLSLは、現状ではまだ簡単な言語ですが、それでも覚えなくてはならないことは山のようにあります。一度に全てを覚えることなど、とてもできないので、気になったとき(コンパイラにエラーだと言われた時ともいいますが)に、確認する程度の気楽な感じで眺めてください。

データ型

最初に気になるのが、どのような変数が使えるかということです。HLSLでは、ベクトルや行列が基本的な型に使えるといった他ではあまり見ない特徴をもっていたりします。また、セマンティクスと呼ばれる、頂点シェーダとピクセルシェーダの間等を橋渡しするためのキーワードを持っていたりします。といっても、それ以外はほとんどC言語なので、サンプルについているエフェクトファイル等のサンプルを見て、書き方に慣れていけば、そんなに不自然は感じないと思います。

 

      変数

 

HLSLでは、変数はc言語とほぼ同じような形式で宣言して使うことができます。最も一般的な形は次の形をしています。

[修飾子][const] 変数名 [配列数] [: セマンティクス] [= 初期値] [コメント] ;

C言語と同じように、「,」でつなげて同じ方の変数を複数宣言することができます。例えば、整数を2つ宣言するときには、

int i, j;

と、まとめて宣言することができます。

修飾子には、次のものがあります。

修飾子名

機能

static

この修飾子がつけられた変数はシェーダの外から参照することができなくなります。これは、シェーダのコンパイラが高速化をしやすくします。static が付いた変数は、特に指定しなければ0に初期化されます。

uniform

この修飾子がつけられた変数は、シェーダの外から参照することができなくなります。

extern

修飾子が付いた変数は、シェーダの外部から値が入力されることを明示します。

つまり、コンパイラは初期化しません。基本的には、static でないグローバル変数はexternな変数です。

shared

この修飾子がついた変数は、異なるエフェクトファイルで変数を共有します。

volatile

この修飾子がついた変数は、値が頻繁に変わることをコンパイラに教えます。コンパイラはこの変数を最適化と称して一時レジスタにおくことはしません。volatileは、コンパイルの手助けをする手法です。

 値の初期値には、{式, 式, ...}の形式が使えます。ベクトルや配列で無い値を設定するときには、{}で囲まなくてもかまいません。

セマンティクス(意味付け)は、頂点シェーダやピクセルシェーダのような異なるシェーダ間や、シェーダ前後の入出力について、結果や引数をどのレジスタに送るのか指定するために設けられた「関係付けのキーワード」です。セマンティクスを使うことによって、頂点データの各種データを好きな名前の入力に決めることができます。

コメントは、{ member_list } の形をした。文字列の式になります。例えば、後に出てくるサンプラの宣言は、

sampler TexSamp = sampler_state{Texture = <Tex>; AddressU = Clamp; AddressV = Clamp;};

のようになります({}でくくられた部分がコメントです)。Texture などのメンバ変数は、<Tex>などの値に初期化されますが、このデータはコンパイラにどのテクスチャを使うか等の情報を連絡します。コメントは、シェーダプログラムからは参照できません。あくまでも、レンダリングステートの設定など、コンパイラに渡しずらいデータを渡すのに使います。

 

 

      セマンティクス

 

セマンティクスをもう少し細かく見ていきましょう。セマンティクスは、シェーダ間でのデータの受け渡しに使われるのですが、頂点シェーダの入出力、ピクセルシェーダの入出力の4つの種類があります。

頂点シェーダ入力セマンティクスは、頂点シェーダに入力されるそれぞれのデータに関して、どの変数に代入するか宣言します。頂点宣言で使われる頂点データの使用法 D3DDECLUSAGE の頂点シェーダレジスタへの入力先です。頂点シェーダ入力セマンティクスには、次の種類があります。

POSITION[n]

位置座標

BLENDWEIGHT[n]

ブレンディングの重み

BLENDINDICES[n]

ブレンドのインデックス

NORMAL[n]

法線ベクトル

PSIZE[n]

ポイント サイズ

DIFFUSE[n]

ディフューズ色

SPECULAR[n]

スペキュラ色

TEXCOORD[n]

テクスチャ座標

TANGENT[n]

接ベクトル

BINORMAL[n]

従法線ベクトル

TESSFACTOR[n]

テセレーション係数

n は、いくつも入力データがあるときに区別するためのインデックスで、TEXCOORD0, TEXCOORD1のように使われます。nの数は、使える頂点シェーダのバージョンやグラフィックスチップでサポートされるレジスタの数に支配されます。

 

頂点シェーダ出力セマンティクスは、頂点シェーダからピクセルシェーダに引き渡すデータをどの出力レジスタに入れるか決めるためのセマンティクスです。頂点シェーダの出力レジスタと1対1に対応しています。

POSITION

位置座標

COLOR[n]

TEXCOORD[n]

テクスチャ座標

PSIZE

ポイント サイズ

FOG

頂点フォグ

 

ピクセルシェーダ入力セマンティクスは、頂点シェーダからピクセルシェーダに引き渡されたデータとピクセルシェーダでの変数名を結び付けます。ピクセルシェーダ入力セマンティクスには、次の種類があります。

COLOR[n]

TEXCOORD[n]

テクスチャ座標

実は、ピクセルシェーダ入力セマンティクスには頂点シェーダ出力セマンティクスが使えます。ただし、ピクセルシェーダ入力セマンティクスにない宣言は無視されますし、ピクセルシェーダ内部でそれら存在しないセマンティクスを使うことはできません。

 

ピクセルシェーダ出力セマンティクスは、ピクセルシェーダからの出力を宣言するために用意されています。

COLOR[n]

DEPTH

深度

COLORのnの値が1以上のセマンティクスやDEPTHは、ピクセルシェーダ2.0以上でないと使うことはできません。

 

      スカラー型

 

ここでいう「スカラー」とは、「ベクトルじゃない」という意味ぐらいに捉えてください。HLSLでは、変数などを宣言するときの基本的な型には次の型があります。C言語等と違う点は、それぞれの型に応じてデータの精度が決まっているということです。

型名

表現される数

bool

true もしくは false

int

32ビット符号付き整数

half

16ビット浮動小数点数

float

32ビット浮動小数点数

double

64ビット浮動小数点数

ただし、よく考えてみると、自由に書き込めるレジスタは一時レジスタしかありません。内部的にどのように計算されているのかは非常に大きな問題です。内部的にint型、half型やdouble型を持っていない場合が大いにありえます。そもそも、最初のシェーダ言語(頂点シェーダ1.0やピクセルシェーダ1.0)にはループ計算がありませんでした。それは命令数が少なくて、ループ計算が必要になる計算ができなかったりしたからです。そうすると、整数の変数は必要ありません。したがって、プログラマブルシェーダの最初の段階では小数を扱っていれば問題がありませんでした。さらに、ピクセルシェーダ2.0のレベルでは、まだループはサポートされていません。ピクセルシェ−ダ2.0用の回路は整数を扱えなくても支障はないはずです。そんなわけで、昔の歴史を紐解いてみると整数は冷遇されてきており、それを引きずる形で、HLSLでは整数演算がサポートされない環境も大目にみられています。int型がハードウェア的にサポートされていない時には、内部的にはfloat型で計算されます。整数演算が浮動小数点数で計算されると困ったことがでてきます。計算誤差が積み重なって、整数の計算と違う結果になる可能性があるということです。さいわい、整数型がサポートされないであろうピクセルシェーダ2.0までの環境では、使える命令数が少ないので、計算結果が違うほどの誤差は出ないと思いますが、「整数計算は確実ではない」という、普通のコンピュータの常識では考えられないことを頭の片隅にでも入れて置いてください。また、その他の型も信用できません。double 型が float 型で計算される場合もあります。現在のところ、型の精度はあくまでも計算するための速度や精度の目安程度に考えておきましょう。一つ付け加えておくと、half型は、現在のグラフィックチップの回路的に、一番高速に処理されるように作られているようです。したがって、最初にfloat 型で作っておいて、高速化を考える段階になって、float型をhalf型に置き換えると高速化が望めるかも知れません。もちろん、half型は、float型よりも精度が低いので、複雑な計算をしたときには見た目が大きく変わってしまう可能性があるので、見るに耐えない違いが出てしまった場合には、float型をhalf型に置き換えることはあきらめましょう。

 

 

      ベクトル型

 

HLSLでは、4次元までのベクトルが簡単に扱えます。ベクトル型は、次の構文を使います。

vector

4次元ベクトル。各成分は、float 型。

vector < type, size >

次元が size のベクトル。各成分の type はスカラー型。

たとえば、half型の3次元のベクトvルは、「vector<half,3> v」で定義することができます。

行列に関しては、次の宣言で使用します。

matrix

4 行 4 列の行列。各成分は float 型。

matrix < type, rows, columns >

rows 行 columns 列の行列。各成分の type はスカラー型。

といっても、このような、こむずかしい定義は使わないのが普通で、簡略化した次の型を使うのが普通だと思います。それぞれのスカラー型のベクトルは、次のものが用意されています。

ベクトル

1次元

2次元

3次元

4次元

bool1

bool2

bool3

bool4

int1

int2

int3

int4

half1

half2

half3

half4

float1

float2

float3

float4

double1

double2

double3

double4

行列の場合には、次の型が使えます。

行列

1行1列

1行2列

1行3列

1行4列

2行1列

4行4列

bool1x1

bool1x2

bool1x3

bool1x4

bool2x1

bool4x4

int1x1

int1x2

int1x3

int1x4

int2x1

int4x4

half1x1

half1x2

half1x3

half1x4

half2x1

half4x4

float1x1

float1x2

float1x3

float1x4

float2x1

float4x4

double1x1

double1x2

double1x3

double1x4

double2x1

double4x4

行と列の関係はプリプロセッサ「row_major」等を使えば変更することができます。

ベクトルのそれぞれの成分をスカラー型として使うときには、(例えば、「vector v」では)次の表記法が使えます。

1つめの成分

2つめの成分

3つめの成分

4つめの成分

v[0]

v[2]

v[2]

v[3]

v.x

v.y

v.z

v.w

v.r

v.g

v.b

v.a

ベクトルの特別な表記法として、v.yyzwや、v.rrra等の成分を入れ替えたベクトルが使えます。但し、v.xyrb のようなxyzwとrgbaの混ざった書き方はいけません。それに、成分の入れ替えはプログラムするシェーダのバージョンによって使えない可能性があります。バージョンの依存性は意外と見落としがちなので、注意点の一つに入れておいてください。

行列では、成分をスカラー値として扱う時に、次の書き方が使えます。

mat._11

mat._12

mat._13

mat._14

mat._21

mat._22

mat._23

mat._24

mat._31

mat._32

mat._33

mat._34

mat._41

mat._42

mat._43

mat._44

もしくは、次の形式が使えます。

mat._m00

mat._m01

mat._m02

mat._m03

mat._m10

mat._m11

mat._m12

mat._m13

mat._m20

mat._m21

mat._m22

mat._m23

mat._m30

mat._m31

mat._m32

mat._m33

行列の一部の列をベクトルとして扱いたいときが良くあるのですが、そのときには、次の表記法が使えます。

mat[0]

mat._m00_m01_m02_m03

mat._11_12_13_14

ただし、別々の表記法を混ぜた使い方

mat._m00_12_m02_14

は、できません。

[]を使った表記法は、それぞれの成分を取り出すのにも使えます。例えば行列matの24成分は、

mat[1].w

mat[1][3]

とも書けます。

 

      オブジェクト型

 

その他にいくつかの型が用意されています。

 

■文字列

 

ascii文字列を表現するためのオブジェクトとして、「string」が用意されています。ただし、シェーダ内では文字列に対して一切の操作はできません。文字列オブジェクトは、シェーダを呼び出すプログラムからシェーダ内での変数名を参照するとき等に使われます。

 

■頂点シェーダ

 

頂点シェーダ(vertexshader)オブジェクトは、頂点シェーダ(アセンブラ)を表します。例えば、シェーダアセンブラで書いたプログラム

vertexshader vs = asm { vs.2.0 mov oPos, c0 };

に使います。頂点シェーダオブジェクトは、シェーダの「テクニック」オブジェクトから、

technique TShader

{

    pass P0

    {

        VertexShader = <vs>;

    }

}

の構文で呼びだすことができます。その他に、HLSLで書かれた頂点シェーダプログラムに関しても、頂点シェーダオブジェクトを作ることができます。例えば、頂点シェーダの関数vsmain()に対しては、

vertexshader vs = compile vs_2_0 vsmain();

のように、バージョンを指定してコンパイルするように頼むと、頂点シェーダオブジェクトを生成することができます。

HLSL で作成したシェーダに関しては、テクニックから直接呼び出すこともできます。例えば、

technique TShader

{

    pass P0

    {

        VertexShader = compile vs_2_0 vsmain();

    }

}

のように呼び出します。

 

■ピクセルシェーダ

 

ピクセルシェーダ(pixelshader)オブジェクトは、ピクセルシェーダを表します。ピクセルシェーダオブジェクトも頂点シェーダオブジェクトと同じように、アセンブラ

pixelshader ps = asm { ps.2.0 mov oC0, c0 };                                          

として定義されたり、HLSLのピクセルシェーダをコンパイルした形式

pixelshader ps = compile ps_2_0 psmain();

によって作ることができます。呼び出される方法も、頂点シェーダオブジェクトと同じく、テクニックから

technique TShader

{

    pass P0

    {

        PixelShader = <ps>;

    }

}

technique TShader

{

    pass P0

    {

        PixelShader = compile ps_2_0 psmain();

    }

}

の方法を使います。

 

■テクスチャ

 

テクスチャ(texture)オブジェクトは、ポリゴンに張るBMPファイルなどの読み込んだテクスチャを表します。テクスチャオブジェクトには、次のメンバ変数が用意されています。

const string type

2D,CUBE, VOLUME 等のD3DSAMPLER_TEXTURE_TYPEから「D3DSTT_」を省いた形式

const string format

テクスチャフォーマット

const int width

テクスチャの幅

const int height

テクスチャの高さ

const int depth

テクスチャの奥行き(ボリュームテクスチャの時に使用)

例えば、xyzのそれぞれの大きさが8のボリュームテクスチャを使うときには、

texture Tex  < string type = "VOLUME"; int width = 8, height = 8, depth = 8; >;

のように宣言します。ただし、メンバ変数は無理して指定する必要はありません。また、「textureCUBE」のような明示的に型を指定した宣言も用意されています。

 

■サンプラ

 

サンプラ (sampler) オブジェクトは、サンプラステージを表します。サンプラとは、SetTexture命令で指定する、

ピクセルシェーダでテクスチャを読み込む時の読み込み回路のことです。テクスチャを読み込むときの補間方法やテクスチャからはみ出たテクスチャ座標を指定した時の振る舞いはサンプラで決まります。サンプラオブジェクトは、まさにその読み込み方法の指定をします。また、どのテクスチャを読み込むのかの指定もします。例えば、テクスチャオブジェクトTexを使うサンプラは次の形式でかかれます。

sampler TexSamp = sampler_state

{

    Texture = <Tex>;

    MinFilter = POINT;

    MagFilter = POINT;

    MipFilter = NONE;

    AddressU = Clamp;

    AddressV = Clamp;

};

テクスチャ以外のパラメータは、基本的には、 D3DSAMP_ が付かないD3DSAMPLERSTATETYPE 列挙型で、それぞれの値もD3DTEXF_やD3DSAMP_が付かない形式のD3DTEXTUREFILTERTYPE等の値になります。

 

      構造体型

 

自分で好きな構造体を定義して、一まとめのデータを変数として取り扱うこともできます。構造体の定義には、struct キーワードを使います。その構文は、

struct 構造体名 { メンバの宣言 }

になります。メンバの宣言は複数置くことができますが、変数の宣言と違って、修飾子や const は使えません。よく使われるのは、頂点シェーダの出力をピクセルシェーダに引き渡すときの構造体で、具体的な例は次のものです。

struct VS_OUTPUT

{

    float4 Pos      : POSITION;

    float4 Tex      : TEXCOORD0;

};

「:」以降は「頂点シェーダ出力セマンティクス」です。

 

      ユーザー定義型

 

型に別の名前を付けることができます。それをユーザー定義型と呼びます。ユーザー定義型の宣言には、typedef キーワードを使います。

typedef [const] 元の型 ユーザー定義型名[配列数];

それぞれの型の名前の後に配列のサフィックスを指定して、ベクトル型を宣言することもできます。例えばベクトル型のときに紹介した「float4」のような型は、あらかじめ

typedef vector float4;

のように宣言されています。また、次のユーザー定義型も自動的に設定されていて、自由に使うことができます。

typedef int DWORD;

typedef float FLOAT;

typedef vector VECTOR;

typedef matrix MATRIX;

typedef string STRING;

typedef texture TEXTURE;

typedef pixelshader PIXELSHADER;

typedef vertexshader VERTEXSHADER;

 

      型変換

 

型変換とは、数値を別の型の変数に代入するときに、代入先の型に合わせてから変換することをいいます。例えば、浮動小数点数を整数に代入するときには、小数部が切り捨てられて整数に代入されます(より正確に言うならば、0に近いほうの整数に丸め込まれます)。浮動小数点数や整数からBOOL型に型変換されるときは、値が0のときは FALSE、そうでないときはTRUEになり、BOOL型からそれらへの型変換は、FALSEが0、TRUEが1に変換されます。HLSLの変わった仕様として、別の型への暗黙の変換というのがあります。例えば、浮動小数点数をベクトルの初期化に使うことができます。

float4 v = 1.0;

この場合には、ベクトルの全ての成分に同じ値が入ります。すなわち、次の結果と同じになります。

float4 v;

v.x = 1.0;

v.y = 1.0;

v.z = 1.0;

v.w = 1.0;

同様に、行列への型変換も自動的に行うことができます。ベクトルから行列への型変換も可能ですが、そのときにはベクトルの次元と行列の列数が同じでなくてはなりません。変換できる法則は、無理をしない方法なら変換できるということです。詳細はDirectX SDKのヘルプを見ると書いてありますが、基本的には頭の中で各成分の行き先がどうなるか考えられれば、変換できると考えてよいでしょう。といっても、そう思い込んでしまって、いざというときにできなくても腹をたてないでくださいね。

 

構文

     

 

HLSLで使える「文」には、次の形式が使えます。まぁ、なんか複雑に書いてありますが、基本的にはc言語と同じ文が使えます。

[文の表現] ;

{ [いくつかの文] }

return [文の表現] ;

if ( 文の表現 ) 文 [else 構文]

for ( [文の表現もしくは変数宣言] ; [文の表現] ; [文の表現] ) 文

do 文 while ( 文の表現 ) ;

while ( 文の表現 ) 文 ;

[]は省略できるものです。for、do、while 文は、たまたま使えたりしますが、まだ正式なサポートはされていません。また、コメントは、C++で使われているようなコメントを使うことができます。

/* */

C 形式のコメント

//

C++ 形式のコメント

;

asm 文内のアセンブリ形式のコメント

 

     

 

式は、変数などを演算子で結合したものです。演算子には、次の種類があります。

演算子

使用方法

意味

結合法則

()

(式)

部分式

左から右

()

関数名(引数)

関数の呼び出し

左から右

 

(引数)

型コンストラクタ

左から右

[]

配列[int]

配列の添字

左から右

.

構造体.メンバ

メンバの選択

左から右

 

ベクトル.swizzle

成分の入れ換え

左から右

++

変数++

後置インクリメント(成分ごと)

左から右

--

変数--

後置デクリメント(成分ごと)

左から右

++

++変数

前置インクリメント(成分ごと)

右から左

--

--変数

前置デクリメント(成分ごと)

右から左

!

!値

論理否定(成分ごと)

右から左

-

-値

単項マイナス(成分ごと)

右から左

+

+値

単項プラス(成分ごと)

右から左

()

(型)値

型変換

右から左

*

*値

乗算(成分ごと)

左から右

/

/値

除算(成分ごと)

左から右

%

%値

剰余(成分ごと)

左から右

+

+値

加算(成分ごと)

左から右

-

-値

減算(成分ごと)

左から右

<

< 値

比較 : より小さい(成分ごと)

左から右

>

> 値

比較 : より大きい(成分ごと)

左から右

<=

<= 値

比較 : 以下(成分ごと)

左から右

>=

>= 値

比較 : 以上(成分ごと)

左から右

==

== 値

比較 : 等しい(成分ごと)

左から右

!=

!= 値

比較 : 等しくない(成分ごと)

左から右

&&

&& 値

論理積(成分ごと)

左から右

||

||値

論理和(成分ごと)

左から右

?:

float?値:値

条件

右から左

=

変数=値

代入(成分ごと)

右から左

*=

変数*=値

乗算代入(成分ごと)

右から左

/=

変数/=値

除算代入(成分ごと)

右から左

%=

変数%=値

剰余代入(成分ごと)

右から左

+=

変数+=値

加算代入(成分ごと)

右から左

-=

変数-=値

減算代入(成分ごと)

右から左

,

,値

コンマ

左から右

結合法則に「成分ごと」が付いている演算子は、ベクトル型などの計算をする時に、成分ごとに演算を行います。剰余計算「%」は、両辺とも正か、両辺とも負の場合に使うことができます。整数型以外にも、浮動小数点数のデータも「%」計算を行うことができます。2項演算子などで両辺の型が違う時には、両方の型が同じになるように型変換されてから演算が行なわれます。例えば、(int3 + float) の場合には、(float3 + float3) に型変換してから計算されます。結果も型変換後の float3 型になります。

float3 v = {1.0, 1.5, 2.0, 2.5};

int3   a = {1,2,3,4};

float3 va = v+a;          // 結果は、{2.0, 3.5, 5.0, 6.5}

 

関数

      ユーザー定義関数

 

HLSL で使う関数は、次の形式で定義します。

[static inline target] [const] 出力型 関数名 ( [パラメータ・・・] ) ;

[static inline target] [const] 出力型 関数名 ( [パラメータ・・・] ) { [文] } ;

target は、関数が作成されたプラットフォームを示します。プラットフォームが違えば同じ関数名をつけることができます。その他に出力する型や引数のパラメータが違っても同じ名前を付けることができます。と、言いたいところですが、現在のバージョンでは、実際には同じ名前を付けることはできません。今言ったことは、コンパイラがもう少し賢くなったらできるようになるはずです。さらに、今のコンパイラでは、全ての関数はインライン展開されます。コンパイルは全ての関数を一度展開してからレジスタの番号付け等をします。したがって、inlineキーワードは不要なのですが、今後のバージョンで高速化のための指示をするために用意されています。

引数として使うパラメータは、「,」で区切っていくつかの変数を並べたものになります。それぞれのパラメータの形式は、

[uniform in out inout] 型 変数名 [: セマンティクス] [= 初期値]

最初の修飾子は、与える引数の種類を指定します。

uniform

パラメータの値を(外部プログラムから設定する)定数データから所得します。

on

パラメータを入力値として使います。

out

結果を呼び出し元の関数に戻します。C++言語の参照のような感じでしょうか。

inout

in と out を両方指定します。

修飾子に何も指定しない場合には、「in」が使われます。

出力する型として、セマンティクスを指定する場合には、

float4 PS( VS_OUTPUT In ) : COLOR

{

    return 0;

}

のように、引数パラメータの後に指定します。

 

      組み込み関数

 

あらかじめ準備されている関数が組み込み関数です。組み込み関数は、とりあえず実装できそうなものは用意しておくといった感じで、必ずしも処理が軽い命令ばかりではありません。命令が用意されているからといって不用意に使うと、実用にならない速度にしか仕上がらない場合もあります。算術命令の組み込み関数には、次のような命令があります。

 

名前

使い方

機能

abs

abs(x)

絶対値 (成分ごと)。

all

all(x)

x のすべての成分が 0 以外の値かどうかをテストします。

any

any(x)

x のいずれかの成分が 0 以外の値かどうかをテストします。

ceil

ceil(x)

x 以上の最小の整数を返します。

clamp

clamp(x, min, max)

x を [min, max] の範囲に制限します。

clip

clip(x)

x のいずれかの成分が 0 より小さい場合、現在のピクセルを破棄します。x の各成分が面からの距離を表す場合、この関数を使って、クリップ面をシミュレーションします。

cross

cross(a, b)

2 つの 3D ベクトル a と b の外積を返します。

D3DCOLORtoUBYTE4

D3DCOLORtoUBYTE4(x)

4D ベクトル x の成分を入れ換えおよびスケーリングして、GeForce3などの一部のハードウェアにある UBYTE4 サポートの不足を補正します。

ddx

ddx(x)

スクリーン空間の x 座標について、x の偏微分を返します。

ddy

ddy(x)

スクリーン空間の y 座標について、x の偏微分を返します。

degrees

degrees(x)

x をラジアン単位から度数に変換します。

determinant

determinant(m)

正方行列 m の行列式を返します。

distance

distance(a, b)

2 つの点 a と b 間の距離を返します。

dot

dot(a, b)

2 つのベクトル a と b の内積を返します。

faceforward

faceforward(n, i, ng)

-n * sign(dot(i, ng)) を返します。

floor

floor(x)

x 以下の最大の整数を返します。

fmod

fmod(a, b)

a = i * b + f となるような、a / b の浮動小数点数の剰余 f を返します。ここで、i は整数、f は x と符号が同じで、その絶対値は b の絶対値よりも小さくなります。

frac

frac(x)

f が 0 より大きく、1 より小さい値となるような、x の小数部 f を返します。

frc

frc(a)

小数部 (成分ごと)。

frexp

frexp(x, out exp)

x の仮数と指数を返します。frexp は仮数を返し、指数は出力引数 exp に格納されします。x が 0 の場合、関数は仮数と指数の両方に 0 を返します。

fwidth

fwidth(x)

abs(ddx(x))+abs(ddy(x)) を返します。

isfinite

isfinite(x)

x が有限の場合は TRUE を返す。それ以外の場合は FALSE を返します。

isinf

isinf(x)

x が +INF か -INF の場合は TRUE を返します。それ以外の場合は FALSE を返します。

isnan

isnan(x)

x が NAN か QNAN の場合は TRUE を返します。それ以外の場合は FALSE を返します。

len

len(a)

ベクトルの長さ。

length

length(v)

ベクトル v の長さを返します。

lerp

lerp(a, b, s)

a + s(b - a) を返します。この関数は、s が 0 の場合は a を返し、1 の場合は b を返すよう、a と b の間を線形補間します。

lit

lit(ndotl, ndoth, m)

ライティングのベクトル (アンビエント、ディフューズ、スペキュラ、1) を返します。アンビエント = 1; ディフューズ = (ndotl < 0) ?0 : ndotl; スペキュラ = (ndotl < 0) || (ndoth < 0) ?0 : (ndoth * m);

max

max(a, b)

a と b の大きい方を選択します。

min

min(a, b)

a と b の小さい方を選択します。

modf

modf(x, out ip)

x を、それぞれが x と同じ符号を持った小数部と整数部に分けます。x の符号付き小数部が返されます。整数部は出力引数 ip に格納されます。

mul

mul(a, b)

a と b の間の行列乗算を実行します。a がベクトルの場合、行ベクトルとして処理します。b がベクトルの場合、列ベクトルとして処理します。内部ディメンジョンの a 列 と b 行 は等しくなければなりません。a 行 b 列の行列が得られます。

noise

noise(x)

実装されていません。

normalize

normalize(v)

正規化されたベクトル v / length(v) を返します。v の長さが 0 の場合、結果は無限となります。

radians

radians(x)

x を度数からラジアン単位に変換します。

reflect

reflect(i, n)

反射ベクトル(入射方向 i、サーフェイス法線 n とした場合の、v = i - 2 * dot(i, n) * n)を返します。

refract

refract(i, n, eta)

入射方向 i、サーフェイス法線 n、屈折 eta の相対インデックスが与えられた場合の、屈折ベクトル v を返します。i と n の間の入射角が指定された eta よりも大きすぎると、(0,0,0) を返します。

round

round(x)

x を最も近い整数に丸めます。

saturate

saturate(x)

x を [0, 1] の範囲に制限します。

step

step(a, x)

(x >= a) ? 1 : 0 を返します。

transpose

transpose(m)

行列 m の転置行列を返します。入力する行列が m 行n 列の場合、結果はn 列m 行の行列になります。

 

数学的な解析関数も用意されています。これらの多くはべき級数展開などの方法で実装されるので、常に正確な値を返すとは限りません。

名前

使い方

機能

acos

acos(x)

x の各成分の逆余弦。各成分は、[-1, 1] の範囲になります。

asin

asin(x)

x の各成分の逆正弦。各成分は、[-pi/2, pi/2] の範囲になります。

atan

atan(x)

x の各成分の逆正接。戻り値は、[-pi/2, pi/2] の範囲になります。

atan2

atan2(y, x)

y/x の逆正接。y と x の符号を使って [-pi, pi] の範囲にある戻り値の象限を判断します。atan2 は、原点以外の各点に対して十分に定義されています。

cos

cos(x)

x の余弦。

cosh

cosh(x)

x の双曲余弦。

exp

exp(x)

e を底とする指数 ex。

exp2

exp2(a)

2 を底とする指数 (成分ごと)。

ldexp

ldexp(x, exp)

x * 2exp。

log

log(x)

x の、底が e の自然対数を返します。x が負の場合、この関数は無限を返します。x が 0 の場合、+INF を返します。

log10

log10(x)

x の、底が 10 の自然対数を返します。x が負の場合、この関数は無限を返します。x が 0 の場合、+INF を返します。

log2

log2(x)

x の、底が 2 の自然対数を返します。x が負の場合、この関数は無限を返します。x が 0 の場合、+INF を返します。

pow

pow(x, y)

x^y。

rsqrt

rsqrt(x)

1 / sqrt(x)。

sign

sign(x)

x の符号を求めます。x が 0 よりも小さい場合は -1、0 と等しい場合は 0、0 よりも大きい場合は 1 を返します。

sin

sin(x)

x の正弦。

sincos

sincos(x, out s, out c)

x の正弦と余弦。sin(x) は出力引数 s に格納され、cos(x) は出力引数 c に格納されます。

sinh

sinh(x)

x の双曲正弦。

smoothstep

smoothstep(min, max, x)

x < min の場合は 0 を返します。x > max の場合は 1 を返します。x が [min, max] の範囲内であれば、0 と 1 の間の滑らかなエルミート補間を返します。

sqrt

sqrt(a)

平方根 (成分ごと)。

tan

tan(x)

x の正接。

tanh

tanh(x)

x の双曲正接。

 

テクスチャを読み込む命令には次の命令があります。テクスチャの種類によって使う命令が違うので、読み込むテクスチャの種類にはいつも気をつけましょう。

名前

使い方

機能

tex1D

tex1D(s, t)

1D のテクスチャ参照。s はサンプラまたは sampler1D オブジェクト。t はスカラー。

tex1D

tex1D(s, t, ddx, ddy)

微分を指定した、1D のテクスチャ参照。s はサンプラまたは sampler1D オブジェクト。t、ddx、ddy はスカラー。

tex1Dproj

tex1Dproj(s, t)

1D の射影テクスチャ参照。s はサンプラまたは sampler1D オブジェクト。t は 4D ベクトル。t は、参照が実行される直前の成分で除算されます。

tex1Dbias

tex1Dbias(s, t)

1D のバイアス テクスチャ参照。s はサンプラまたは sampler1D オブジェクト。t は 4D ベクトル。参照を実行する前に、ミップ レベルに t.w のバイアスがかけられます。

tex2D

tex2D(s, t)

2D のテクスチャ参照。s はサンプラまたは sampler2D オブジェクト。t は 2D テクスチャ座標。

tex2D

tex2D(s, t, ddx, ddy)

微分を指定した、2D のテクスチャ参照。s はサンプラまたは sampler2D オブジェクト。t、ddx、ddy は 2D ベクトル。

tex2Dproj

tex2Dproj(s, t)

2D の射影テクスチャ参照。s はサンプラまたは sampler2D オブジェクト。t は 4D ベクトル。t は、参照が実行される直前の成分で除算されます。

tex2Dbias

tex2Dbias(s, t)

2D のバイアス テクスチャ参照。s はサンプラまたは sampler2D オブジェクト。t は 4D ベクトル。参照を実行する前に、ミップ レベルに t.w のバイアスがかけられます。

tex3D

tex3D(s, t)

3D のボリューム テクスチャ参照。s はサンプラまたは sampler3D オブジェクト。t は 3D テクスチャ座標。

tex3D

tex3D(s, t, ddx, ddy)

微分を指定した、3D のボリューム テクスチャ参照。s はサンプラまたは sampler3D オブジェクト。t、ddx、ddy は 3D ベクトル。

tex3Dproj

tex3Dproj(s, t)

3D の射影ボリューム テクスチャ参照。s はサンプラまたは sampler3D オブジェクト。t は 4D ベクトル。t は、参照が実行される直前の成分で除算されます。

tex3Dbias

tex3Dbias(s, t)

3D のバイアス テクスチャ参照。s はサンプラまたは sampler3D オブジェクト。t は 4D ベクトル。参照を実行する前に、ミップ レベルに t.w のバイアスがかけられます。

texCUBE

texCUBE(s, t)

3D のキューブ テクスチャ参照。s はサンプラまたは samplerCUBE オブジェクト。t は 3D テクスチャ座標。

texCUBE

texCUBE(s, t, ddx, ddy)

微分を指定した、3D のキューブ テクスチャ参照。s はサンプラまたは samplerCUBE オブジェクト。t、ddx、ddy は 3D ベクトル。

texCUBEproj

texCUBEproj(s, t)

3D 射影のキューブ テクスチャ参照。s はサンプラまたは samplerCUBE オブジェクト。t は 4D ベクトル。t は、参照が実行される直前の成分で除算されます。

texCUBEbias

texCUBEbias(s, t)

3D のバイアス キューブ テクスチャ参照。s はサンプラまたは samplerCUBE オブジェクト。t は 4D ベクトル。参照を実行する前に、ミップ レベルに t.w のバイアスがかけられます。

 

その他

 

      予約語

 

次の言葉は、内部ですでに使われているので使うことはできません。太字の言葉は、大文字小文字の区別もしないので、大文字、小文字の両方で使うことはできません。予約語の中にはまだ使われていない言葉もありますが、将来のバージョンのことも考えて使えないようになっています。

asm

auto

break

bool

case

catch

char

class

compile

const

const_cast

continue

decl

default

delete

do

double

dynamic_cast

else

enum

explicit

extern

false

float

for

friend

goto

half

if

in

inline

inout

int

long

matrix

mutable

out

namespace

new

operator

pass

pixelshader

private

protected

public

register

reinterpret_cast

return

sampler

shared

short

signed

sizeof

static

static_cast

string

struct

switch

technique

template

texture

this

throw

true

try

typedef

typename

uniform

union

unsigned

using

vector

vertexshader

virtual

void

volatile

while

 

 

 

 

      プリプロセッサ ディレクティブ

 

シェーダコンパイラを使うときには、c言語と同じようにプリプロセッサが働きます。使えるプリプロセッサは次の

#define

#define a b」で、aと書かれた部分をbに置き換えます(#define clamp(x) (max(1,min(0,(x))))のような関数形式のマクロは使えません)

#elif

#if等による分岐を中断し、別の条件分岐を実行します

#else

#if等による分岐を中断し、条件が満たされていない場合について以降の文を実行します

#endif

#if等による条件分岐を終了します

#error

エラー説明のメッセージを指定します

#if

条件分岐をします

#ifdef

#ifdef a」でaがすでに定義されていれば、以降の文を実行します

#ifndef

#ifndef a」でaが定義されていなければ、以降の文を実行します

#include

外部ファイルを読み込みます(ファイルからコンパイルするときだけ使える)

#line

__LINE__等で使う行番号を変更します

#pragma

ほとんどの場合、無視されます

#undef

#define による定義を無効にします

#column_major

float[m]x[n]の行列をm行n列で数えます (定数レジスタはn個使います)

#row_major

float[m]x[n]の行列をn行m列で数えます (定数レジスタはm個使います)

また、次のdefineは、DirectXの内部ですでに定義されています。

#define D3DX

#define D3DX_VERSION 0x0900

#define DIRECT3D

#define DIRECT3D_VERSION 0x0900

#define __FILE__

#define __LINE__

row_major と column_major による格納方法の指定は、#pragma でも指定することができます。

#pragma PACK_MATRIX (ROW_MAJOR)

#pragma PACK_MATRIX (COLUMN_MAJOR)

その他には、定数レジスタを変数名と結びつける「register」が用意されています。例えば頂点シェーダの定数レジスタ14と変数vColorを結びつける命令は

float4 vColor : register(vs_2_0, c14) ; 

のようになります(シェーダのバージョンを指定しないならば、vs_2_0の変わりにvsが使えます)。

シェーダ内で使うときには、シェーダのターゲットを省略して、

float4 vColor : register (c14);

を使うこともできます。