エフェクトファイルとして書く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);
を使うこともできます。