HLSLシェーダーの魔導書まとめ
1.2.1 メモリ転送
メモリへのデータ転送の方法として、PIO方式とDMA方式がある。
PIO(Programmed Input/Output)
CPUがコンピュータ内部の各デバイスとメインメモリ間のデータ転送する方法。
回路はシンプルになるが、CPUに負荷がかかり、転送中はCPUの処理が止まるため効率が悪い。
DMA(Direct Memory Access)
CPUを使わずに、バスを通じて周辺機能(アナログ機能、通信機能など)とメモリ間(フラッシュメモリ、ROM、RAM)のデータ転送を直接行う機能のこと
ハードウェアを用いているため、PIO方式より転送効率が高い。
1.3.2 レンダリングパイプライン
描画結果を得るための手順をレンダリングパイプラインと言う(ざっくり過ぎ)
DirectX12のパイプライン(DirectX12の魔導書参照)
- Input Assembler(IA)
- Vertex Shader(VS)
- Hull Shader(HS)
- Tesselator(TS)
- Domain Shader(DS)
- Geometry Shader(GS)
- Rasterizer(RS)
- Pixel Shader(PS)
- Output-Merger(OM)
HLSL魔導書では、IA, VS, RS, PSについて触れられている。
実際出力する際の最小構成がこれなので、必要な処理ってことらしい。
IA, VS, RS, PSの詳細な流れ
-
入力アセンブラー(IA)
メッシュの頂点バッファー, インデックスバッファー, プリミティブタイプなどの情報を必要なデータ形式として用意する。ドローコールが実行されると、GPUはグラフィックスメモリから必要なデータをレジスタに運ぶ。
頂点バッファー & インデックスバッファーの必要性については以下のサイトが分かりやすい。
そもそもなぜ三角形で分割するのかという点は、分割可能な最小の多角形であること、頂点をどのように動かしても、描画が破綻しないので扱いやすいからと言えると思う。
2. 頂点シェーダー(VS)
メッシュの頂点座標をスクリーン空間に変換する。
描画の出力先のスクリーンをビューポートとも言う。(範囲はx: -1 ~ 1 y: -1 ~ 1 z: 0 ~ 1)
基本的な手順
ローカル座標系 → ワールド座標系 → カメラ座標系 → スクリーン座標系
3. ラスタライザ(RS)
座標変換されたメッシュを塗りつぶすためのピクセルを決定する。
ほぼプログラマが関与する部分はないが、DirectXでは色々設定が用意されている。
D3D12_FILL_MODE_WIREFRAME: ワイヤーフレームで塗りつぶされる。
D3D12_FILL_MODE_SOLID: 面が塗りつぶされる。
カリング設定も用意されている。
D3D12_CULL_MODE_FRONT: ポリゴンの表側をカリング
D3D12_CULL_MODE_BACK: ポリゴンの裏側をカリング
D3D12_CULL_MODE_NONE: ポリゴンをカリングしない
基本的にゲームエンジンでは裏側をカリングしてますね。
4. ピクセルシェーダー(PS)
ラスタライザーで決められたピクセルのカラーを決定する。
陰影とか、ライティングを考慮したカラーを計算したりする。
色々とやることが多い。
主に頂点シェーダーとピクセルシェーダーをいじる機会が多いと思う。
2.3 頂点シェーダー入門
魔導書を元に描いた頂点シェーダー
// 頂点シェーダーへの入力頂点構造体
struct VSInput
{
float4 pos : POSITION;
};
// 頂点シェーダーの出力
struct VSOutput
{
float4 pos : SV_POSITION;
};
// 頂点シェーダー
// 1. 引数は変換前の頂点情報
// 2. 戻り値は変換後の頂点情報
VSOutput VSMain(VSInput In)
{
VSOutput vsOut = (VSOutput) 0;
// step-1 入力された頂点座標を出力データに代入する
vsOut.pos = In.pos;
// step-2 入力された頂点座標を2倍に拡大する
vsOut.pos.x *= 2.0f;
vsOut.pos.y *= 2.0f;
// step-3 入力されたX座標を1.5倍、Y座標を0.5倍にして出力
vsOut.pos.x *= 1.5f;
vsOut.pos.y *= 0.5f;
return vsOut;
}
とてもシンプルでありがたい。
HLSLというかシェーダー全体として、基本的に入出力のデータ構造はユーザーが定義する。
また、どのメンバ変数が頂点 or UV or 法線...データなのかを定義するために、
「: POSITION」のようなセマンティクスをつけてあげる必要がある。
また、入力構造体は頂点の数分保持されていて、頂点バッファーという。
シェーダーファイルの拡張子.fxと.hlslの違いはなんだろう...?
調べた感じはあまり変わらなそう。