前書き
こちらは
https://qiita.com/YKVKDX12/items/5a2cc3d175b9f6324422
の補足資料
の兄弟資料です
シェーダーレジスターって?
つまりはCPP側とHLSL側両方が使ってもよい道具になる
もっと言えばメモリ読み書きのルールを定めて使用できる共有リソースである。
詳しく話すとマルチスレッドプログラミングの話になってくるので、ここでは
「意外と繊細なルールを決めないといけないんだよ♡」と述べるに留める
興味がある人は
を読んでください
VS_INPUT 構造体(頂点シェーダー入力)
IA(Input Assembler)ステージからのデータ受け取り構造で、C++側のCreateShaders内定義した入力レイアウトと完全に対応
float4 pos(SV_POSITION)は頂点のローカル座標、
float3 normal(NORMAL)は頂点の法線ベクトル、
float2 tex(TEXCOORD0)はテクスチャUV座標を格納
TEXCOORD1へworldPos(注釈による追加メンバー)でワールド座標も埋め込み
また、
セマンティクス(:SV_POSITION等)はシェーダーリフレクションを通じて
C++の入力レイアウトと紐付け
レイアウトに記載されたフォーマットと、シェーダーで定義された構造体のメンバの型のミスマッチはコンパイルエラーになる
定数バッファ(Constant Buffer)の役割
cbuffer ConstantBuffer(デフォルトスロットb0)には、C++側CreateBuffers関数で計算されたWorld・View・Projectionの4×4行列が格納
register(b0)指定でシェーダースロット0にバインドされ、
フレーム毎に更新可能な共有リソースとして機能
バッファは読み取り専用で、GPU側での書き込みはできず、CPU→GPU への一方向データ転送モデル
VS_OUTPUT 構造体(頂点シェーダー出力)
VertexShader.hlslのmain関数で計算された値をラスタライザーステージ経由でピクセルシェーダーへ伝播する構造
float4 pos(SV_POSITION)は変換後のスクリーン座標で自動的に透視除算・ビューポート変換がかかる
float3 normal、float2 tex、float3 worldPos は補間(Perspective-Correct Interpolation)を経由してピクセル毎に異なる値となり、PixelShader.hlsl内でのライト計算に利用
セマンティクスの種類と個数はVS_INPUTと独立で、必要な値のみを出力する最小化設計が可能
頂点シェーダー内の座標変換パイプライン
VertexShader.hlsl内で mul(input.pos, World) → mul(worldPosition, View) → mul(viewPosition, Projection) という3段階の行列乗算を実行
ローカル座標→ワールド座標→ビュー座標→クリップ座標へと逐次変換
mul関数:行列乗算
右辺ベクトル × 左辺行列の順序
となる。DirectXではそうやる。
output.worldPos = worldPosition.xyzでワールド座標を保存して
PixelShader内でのライト方向計算に供給し、output.normal = mul(float4(input.normal, 0.0f), World).xyzで法線もワールド空間へ変換(w=0.0で平行移動を無視)
法線をワールド変換したらどうなるのか?
あんまり絵にするのが想像しずらいが・・・
つまりはローカル空間にエフェクトをかけていたのを、ワールド空間に持ってくる
もっとわかりやすく言えば控室でメイクした後、舞台に出てくる
というべきか
コード