LuminoEngine/Lumino

構成ごとの Shader 自動生成

Opened this issue · 0 comments

lriki commented
  • #164 書き方の整理
  • 自動生成

Motivation

Instancing 有効、NormalMap 有効、など、構成の組み合わせがかなり増えてきているので、自動的に作りたい。

開発中のタイトル HC4 では背景モデルに対してシェーダを適用したいが、対象は NormalMap 有無など複数の構成を書かなければならず、シェーダ開発が非効率になっている。

Proposal

現状の構成は次の通り。

PS の出力方法 (Phase)

  • Default
  • ShadowCaster -> PS 固定
  • LightDisc -> VS/PS 固定
  • GBufferPrepass -> PS 固定

VS の種類

  • StaticMesh Default
  • StaticMesh Instancing
  • SkinnedMesh Default
  • SkinnedMesh Instancing

Phase が Default のときの PS 種類 (ShadingModel)

  • Default
  • Unlit

PS のオプション

  • NormalMap
  • RoughnessMap

ユーザーカスタマイズを考慮した基本的なシェーダサンプル

方針:VSMain, PSMain は直接書くことにして、オプションの変更はマクロなどで対応する。
Unity のサーフェスシェーダみたいなのを作ることになるとシェーダコンパイラに手を入れる必要があり、かなり重い作業になるため。

struct MyVSOutput
{
	LN_VS_OUTPUT_DATA;	// float3 Pos : SV_POSITION; など
	float4 MyData : TEXCOORD0;
};

struct MyPSInput
{
	LN_PS_INPUT_DATA;
	float4 MyData : TEXCOORD0;
};

MyVSOutput VSMain(LN_VSInput input)
{
	MyVSOutput output;
	LN_ProcessVertex(input, output);	// マクロ。output.Pos などへ代入。スキニングやモーフィングもここで計算する。
	
	output.MyData = /* ユーザー定義データの構築 */;
	
	return output;
}

float4 PSMain(MyPSInput input) : SV_TARGET0
{
	//LN_Surface surface = LN_InitSurface();	// 初期化するだけ
	LN_Surface surface = LN_ProcessSurface(input);	// input.TexUV 等を使って、Albedo など各要素をデフォルト構築する。
	
	surface.Albedo = /* ユーザー定義で模様を付けたりする。デフォルトシェーダでは何もしない。 */;
	
	// surface は Unity の SurfaceShader の Output 相当。
	// LN_ProcessPixel は UE4 の Output ノード相当。
	// LN_ProcessPixel の中で ShadingModel に応じて PBR の計算をしたり、環境光, Fog の適用などが行われる。
	return LN_ProcessPixel(surface);
}

technique Default
{
	pass Pass1
	{
		VertexShader = VSMain;  // VS はほどんと定型になるので、LN_VSDefault とかを用意してもいいかも。
		PixelShader = PSMain;
	}
}

自動生成の方針

  • technique 名が "Default" であるものについてのみ、自動生成を行う。
    • Default 以外はほとんど内部用途なので、がんばって直書きする。
  • 上記構成だけでも、128 個組み合わせができる。実行速度との相談になるが、コンパイルオプション以外の方法で動的に切り替えができそうならそっちを検討する方がよさそう。初期化時間がすごく長くなるので。
    • Instancing 有無は入力頂点の定義を変える必要があるので、コンパイルオプションで。
    • StaticMesh/SkinningMesh は uniform で切り替えられそう。VTF で動かしてるので、そのテクスチャサイズが 0 なら Static、とか if で判断する、でいいかも。
    • ShadingModel はその有無で実行コードがかなり変わる。Unlit なのに PBR 用のコードや uniform が含まれてしまうと、主に C++ 側に初期化時・実行時共に余計なオーバーヘッドが入ってくるので、コンパイルオプションにしたい。
    • NormalMap や RoughnessMap は、青テクスチャや白テクスチャを使うことでデフォルトを表せる。テクスチャレジスタやFetchが増えるが実際に動かしてみたあと、実行速度と相談で。
  • ↑のようにしておくことで、現状の ShadingModel だと組み合わせは 4 パターンで済みそう。

Note

4パターンくらいならまだ手打ちでもなんとかなるので、まずは上記サンプルの形に、ビルトインシェーダを全部直す。