Unreal Engine 4 (UE4) その2 Advent Calendar 2018 の23日目です
#発端
ある日神は仰った
「(超ヘビー級)ブレンドレイヤーを最適化するにはどうすればいいか」
違う神は答えた。
「ブレンドレイヤーがベースレイヤーで書かれる事が多いなら動的分岐で弾くと良いのではないか」
民は思った。
「ブレンドレイヤーをいちいち全部カスタムノードに移植する作業はやりたくないなぁ」
#目標
ノードに適当において動くTrueDyanmicBranchを作る。
完璧は求めない。とりあえずそれっぽく動くやつ
#前知識
適当に使ってもあんまり効果は無いうえに逆に効率が低下することもありうるシェーダーの
[branch]if
命令ですが、上手に使うと最適化に効果が見込めます。
それじゃあUE4でどう使うといいのか見ていきます。
##DyanmicBranchマテリアル関数
コメントだけ見ると「すごく・・・DynamicBranchです・・・」と感じますがこれは罠です。
よく見ると マテリアル関数 なんです。
ノード自体をダブルクリックすると・・・
ただのIfです。本当にありがとうございました。
実際にShaderDebugInfo下に出力されたシェーダーを見てみると
ただの3項演算子x2になっていることがわかります。
悲しいです。リクエスト自体は上がっているので今後実装されて書き換わるんでしょうか?
新しノードができたとしてもMaterialFunctionでの提供になってしまうとusf中で関数として分離してしまうので、
コンパイラのバックエンドが自動で最適化していくれるとかでない限り有用なシェーダーができることはないと思うので
これがリプレースされることはなさそうな予感がします。
##custom nodeを使う
UE4のマテリアルにはカスタムノードという機能があります
これをに if を入れてコンパイルしてみると以下のようなコードが出力されます。
まずカスタムノードはusfファイル内に一つの関数として出力されます。
float3 CustomExpression0(FMaterialPixelParameters Parameters, float Alpha, float3 TrueValue, float3 FalseValue)
{
float3 Result = FalseValue;
[branch]
if( Alpha > 0.0 )
{
Result = TrueValue;
}
return Result;
}
この関数がCalcPixelMaterialInputs関数の内部から呼び出される形です。
float3 Local20 = (Local4 + Local19);
float3 Local21 = (Local20 * 0.20000000);
float3 Local22 = CustomExpression0(Parameters,Local3,Local21, float3 (0.00000000,0.00000000,0.00000000));
PixelMaterialInputs.EmissiveColor = Material_VectorExpressions[2].rgb;
PixelMaterialInputs.Opacity = 0.50000000;
PixelMaterialInputs.OpacityMask = 1.00000000;
PixelMaterialInputs.BaseColor = Local22;
[branch]if 命令はそのブロックの中身だけを動的分岐の対象にするため、
分岐で省略したい命令をすべてブロック内部に書ききる必要があります。
例えば上記の例は1ピコセカンドも早くなりません。
実際にUE4を使った様々なタイトルで、gpuの負荷をシコシコ削るためにCustomNodeを使った最適化が行われています。(多分)
あなたがこの仕様に完全に満足が行ってるなら、すぐさま回れ右をしてCustomNodeを書く作業に戻ってもよい。
#実装
まずマテリアルエクスプレッションを足します!
##要求仕様
-分岐の比較値パラメータ
-分岐が真だった場合の値
-分岐が偽だった場合の値
の三個を受け取り
[branch]
float3 Result = FalseValue;
if( InScalarValue > 0.0 )
{
Result = TrueValue;
}
というノードを吐き出す。
##参考コード
MaterialExpressionの定義は
UnrealEngine/Engine/Source/Runtime/Engine/Classes/Materials/MaterialExpression***.h
というパスに格納されています。
他のソースもこの周りにあります。
##gitへのリンクについて
このページからリンクが張られているコードはEpicGames/UnrealEngineをフォークしたブランチなので
EpicGames/UnrealEngineへの登録が必要なようです。
登録されていない場合404画面になります。
##マテリアルエクスプレッションの追加
###MaterialExpressionDynamicBranch.h
新規追加
特に説明はありません
コメントをリプレースできてないのでモロバレですが、MaterialExpressionFresnel.hをコピペして改変しただけです。
MaterialExpressionDynamicBranch.h on github
###MaterialExpressions.cpp
マテリアルエクスプレッションの実態コードはこのソースファイルに含めるのがお作法のようなのでここに含めましたが、
既存のコードに追記するとしばしばエンジンのバージョンアップに伴ってマージするときにコンフリクトしたりするので
別ファイルに分離したほうがいい気がしますね。
MaterialExpressions.cpp on github
###MaterialCompiler.h
FMaterialCompiler::DyanmicBranch
FProxyMaterialCompiler::DyanmicBranch
を追加します。前者はpure virtualです。
###HLSLMaterialTranslator.h
いわゆるusfシェーダーファイルの中核をなすクラスがあります。
超でかいです。
AddCodeChunkを二発入れているのがオシャレで気に入ってます。
一つ目のAddCodeChunkで
float3 Local111 = Local110/*FalseValue*/;
を挿入して、すぐさまこの左辺値を次のコードで利用します。
動的分岐内では新しい変数の追加の必要はないので、左辺値は破棄します。
float3 Local112/*Dummy*/ = 0.0f; //この行は無意味
[branch]
if( Local109/*比較参照値*/ > 0.0 )
{
Local111/*一つ目のChunkの左辺値*/ = Local108/*TrueValue*/;
}
###シェーダーファイルを見てみましょう
これでエクスプレッションの追加は終わりです。
これをマテリアルに適用してみると以下のようなusfファイルが吐き出されます。
float Local0 = (-1.00000000 + View_MaterialTextureMipBias);
float4 Local1 = ProcessMaterialColorTextureLookup(Texture2DSampleLevel(Material_Texture2D_0,Material_Texture2D_0Sampler,Parameters.TexCoords[0].xy, float (Local0)));
float3 Local2 = (Local1.rgb + Material_VectorExpressions[1].rgb);
float4 Local3 = ProcessMaterialColorTextureLookup(Texture2DSampleBias(Material_Texture2D_0,Material_Texture2D_0Sampler,Parameters.TexCoords[0].xy,View_MaterialTextureMipBias));
float Local4 = (-1.00000000 + View_MaterialTextureMipBias);
float4 Local5 = ProcessMaterialColorTextureLookup(Texture2DSampleLevel(Material_Texture2D_0,Material_Texture2D_0Sampler,Local3.rgb.rg, float (Local4)));
float Local6 = (-1.00000000 + View_MaterialTextureMipBias);
float4 Local7 = ProcessMaterialColorTextureLookup(Texture2DSampleLevel(Material_Texture2D_0,Material_Texture2D_0Sampler,Parameters.TexCoords[0].xy, float (Local6)));
float3 Local8 = (Local5.rgb + Local7.rgb);
float3 Local9 = (Local8 + Local1.rgb);
float3 Local10 = 0.0;
float3 Local11 = 0.0;
[branch]
if(Local1.a >= 0.0){
Local10 = Local9;
};
PixelMaterialInputs.EmissiveColor = Local2;
PixelMaterialInputs.Opacity = 1.00000000;
PixelMaterialInputs.OpacityMask = 1.00000000;
PixelMaterialInputs.BaseColor = Local10;
PixelMaterialInputs.Metallic = 0.00000000;
PixelMaterialInputs.Specular = 0.50000000;
PixelMaterialInputs.Roughness = 0.50000000;
PixelMaterialInputs.Subsurface = 0;
PixelMaterialInputs.AmbientOcclusion = Local21;
PixelMaterialInputs.Refraction = 0;
PixelMaterialInputs.PixelDepthOffset = 0.00000000;
[branch]ifを挿入することができました!
合格!
ただしブランチブロックの中身がこれでは最適化の意味がないですね。
つづいてこれらを並び替えるコードを書いていきます。
##USFのコード並び替えによる動的分岐の有効化
ここからが本題です。
生成されたUSFファイルを解析して並び替えます
###最適化仕様
入力されたusfファイルに含まれる動的分岐ブロックの中にその分岐ブロックにしか依存しないコード行を突っ込む
入力はマテリアルから変換されたファイル出力前の文字列で
出力は最適化された後の文字列。
コードはおおざっぱに4つのブロックからなります。
###DynamicBranchReorderer.cpp解説
####1.入力を行単位に分割する
####2.行ごとの左辺値と右辺値、属性を調べる
まず、正規表現で左辺値が見つかった場合はその変数番号を記憶します。
usfはLocal\d+
の形で変数を連番で出力していくのでそれを使って抽出します。
次に右辺値をを同様に解析して行情報に追加していきます。
####3.依存関係を考慮して、ソート用キー値を行情報に付与する
2.で作った情報をもとに先頭からイテレーションして分岐内部に差し掛かったところで
最適化対象のコードをブラックリストと照合しながら分別します。
ブラックリストは分岐の後のコードと分岐条件のコード、すでに動的分岐ブロックに入っているコードの右辺値です。
このようなusfの場合
オレンジのブランチ内部ブロックの位置に
グリーンのブロック中からコードを移動します。
青枠及び赤枠の中にあるコードは変更しません。
加えて青枠と赤枠のなかから参照されている値は分岐ブロック以外に依存関係をもつので移動できません。
githubのコードではサンプラーを含む行のコードがあります。
これはサンプラー行の右辺に変数参照があった場合にdevergence gradientエラーがしてしまうのを、
その参照元だけブランチブロックの外側においておけばエラーを回避できるのではないかと思って足してみたのですが
結果はダメでした。
devergence gradient エラーを回避するためには 右辺値を持つサンプラー行はブランチブロックに含めない対処が必要です。
####4.3で作成したソート用キーでstablesortして出力
特筆する点はなし。
###コード並び替えの処理結果
二つのDynamicBranchを含むMaterialをコンパイルした結果です。
もともとは変数の番号順にならんでいたものが最適化されてブランチブロックの中に移動しているのがわかります。
float Local0 = (-1.00000000 + View_MaterialTextureMipBias);
float4 Local1 = ProcessMaterialColorTextureLookup(Texture2DSampleLevel(Material_Texture2D_0,Material_Texture2D_0Sampler,Parameters.TexCoords[0].xy, float (Local0)));
float Local2 = (Local1.r - 0.50000000);
float3 Local8 = 0.00000000;
[branch]
if(Local2 >= 0.0){
float Local3 = (-1.00000000 + View_MaterialTextureMipBias);
float4 Local4 = ProcessMaterialColorTextureLookup(Texture2DSampleLevel(Material_Texture2D_1,Material_Texture2D_1Sampler,Parameters.TexCoords[0].xy, float (Local3)));
float Local5 = (-1.00000000 + View_MaterialTextureMipBias);
float4 Local6 = ProcessMaterialColorTextureLookup(Texture2DSampleLevel(Material_Texture2D_2,Material_Texture2D_2Sampler,Parameters.TexCoords[0].xy, float (Local5)));
float3 Local7 = (Local4.rgb + Local6.rgb);
float3 Local9 = 0.0;
Local8 = Local7;
};
float3 Local10 = (Local8 + Material_VectorExpressions[1].rgb);
float Local11 = (-1.00000000 + View_MaterialTextureMipBias);
float4 Local12 = ProcessMaterialColorTextureLookup(Texture2DSampleLevel(Material_Texture2D_3,Material_Texture2D_3Sampler,Parameters.TexCoords[0].xy, float (Local11)));
float Local13 = (Local12.r - 0.20000000);
float3 Local32 = 0.00000000;
[branch]
if(Local13 >= 0.0){
float Local14 = MaterialExpressionNoise(GetWorldPosition(Parameters),1.00000000,1.00000000,0.00000000,1.00000000,6.00000000,-1.00000000,1.00000000,2.00000000,0.00000000,0.00000000,512.00000000);
float Local15 = (-1.00000000 + View_MaterialTextureMipBias);
float4 Local16 = ProcessMaterialColorTextureLookup(Texture2DSampleLevel(Material_Texture2D_4,Material_Texture2D_4Sampler,Parameters.TexCoords[0].xy, float (Local15)));
float Local17 = (-1.00000000 + View_MaterialTextureMipBias);
float4 Local18 = ProcessMaterialColorTextureLookup(Texture2DSampleLevel(Material_Texture2D_5,Material_Texture2D_5Sampler,Parameters.TexCoords[0].xy, float (Local17)));
float3 Local19 = (Local16.rgb + Local18.rgb);
float Local20 = (-1.00000000 + View_MaterialTextureMipBias);
float4 Local21 = ProcessMaterialColorTextureLookup(Texture2DSampleLevel(Material_Texture2D_6,Material_Texture2D_6Sampler,Parameters.TexCoords[0].xy, float (Local20)));
float3 Local22 = (Local19 + Local21.rgb);
float Local23 = (-1.00000000 + View_MaterialTextureMipBias);
float4 Local24 = ProcessMaterialColorTextureLookup(Texture2DSampleLevel(Material_Texture2D_7,Material_Texture2D_7Sampler,Parameters.TexCoords[0].xy, float (Local23)));
float Local25 = (-1.00000000 + View_MaterialTextureMipBias);
float4 Local26 = ProcessMaterialColorTextureLookup(Texture2DSampleLevel(Material_Texture2D_8,Material_Texture2D_8Sampler,Parameters.TexCoords[0].xy, float (Local25)));
float3 Local27 = (Local24.rgb + Local26.rgb);
float3 Local28 = (Local27 + Local12.rgb);
float3 Local29 = (Local22 + Local28);
float3 Local30 = (Local14 + Local29);
float3 Local31 = (Local30 * 0.20000000);
float3 Local33 = 0.0;
Local32 = Local31;
};
PixelMaterialInputs.EmissiveColor = Local10;
PixelMaterialInputs.Opacity = 0.50000000;
PixelMaterialInputs.OpacityMask = 1.00000000;
PixelMaterialInputs.BaseColor = Local32;
PixelMaterialInputs.Metallic = 0.00000000;
PixelMaterialInputs.Specular = 0.50000000;
PixelMaterialInputs.Roughness = 0.50000000;
PixelMaterialInputs.Subsurface = 0;
PixelMaterialInputs.AmbientOcclusion = 1.00000000;
PixelMaterialInputs.Refraction = float2 ( float2 ( float2 (1.00000000,0.00000000).r,0).r,Material_ScalarExpressions[0].x);
PixelMaterialInputs.PixelDepthOffset = 0.00000000;
#おまちかねの計測
さっそくマテリアルを作って効果のほどを見てみましょう!
※計測結果はハードウェアやマテリアルなど、いろいろな要素が絡みます。
数字は参考程度のものですので正しい方法でプロファイルを取ることをお勧めします。
##ブレンドレイヤー編
###マテリアル全景
※ベースレイヤー以外のテクスチャーサンプルはdevergence gradient エラー対策で MipLevel設定になっています
###レベルの外観
ペイントされたランドスケープだけです。
###計測条件
ウィンドウ解像度1280x720
r.ScreenPercentage 400
t.MaxFPS 600
Geforce1060
Ryzen1600
F2キー押し下げにより、Unlit表示に
ColorGrading以外のポストプロセス等はなし
SampleLevelをつかってMipLevel0を強制している関係で表面のサーフェスに接写
###計測
####TrueDynamicBranchなし
####TrueDynamicBranchあり
####ブレンドレイヤー計測結果
マテリアル | ベースレイヤー部 | 非ベースレイヤー部 |
---|---|---|
ブランチなし | 3.6ms | 3.6ms |
ブランチあり | 3.2ms | 3.8ms |
ベース部分だけのQuadGroup(Warp?WaveFront?)の部分は負荷軽減が望めるが、非ベースレイヤー部の負荷は増加してしまう。
ブレンドレイヤーはUVを加工するために通常のMipmap処理が適用できずにLevel指定版のサンプラを使っているのが根本的に
パフォーマンスを劣化させるので、VertexInterpolatorなどを使ってPixelShader内でのUVの加工を回避するなどの対策が必要。
うん。なんともいえない結果になりました。ワーストケースで負荷が増してしまうのはかなり適用しにくいです。
やっぱり簡単ではないですね。
フォーラムでもいくつか議論があるようですね。
https://forums.unrealengine.com/development-discussion/rendering/29346-landscape-layer-switch
【余談】
手元でLandSpaceCoordにVertexInterpolatorを指してみたところシェーダーコンパイルエラーが発生した。
LandScapeVertexFactory.ushがVertexInterpolatorに対応していない模様。ushを修正してビルドは通すようにすることは可能だがマテリアルのUVが正しく伝播しない。追加調査が必要だが、時間がないので割愛。
###生成されたUSFファイル比較
####TrueDynamicBranchなし
void CalcPixelMaterialInputs(in out FMaterialPixelParameters Parameters, in out FPixelMaterialInputs PixelMaterialInputs)
{
float4 Local0 = Texture2DSample(Material_Texture2D_0,Material_Texture2D_0Sampler,Parameters.TexCoords[3].xy);
float Local1 = dot(Local0, Material_VectorExpressions[1]);
float Local2 = (0.00000000 + Local1);
float4 Local3 = Texture2DSample(Material_Texture2D_0,Material_Texture2D_0Sampler,Parameters.TexCoords[3].xy);
float Local4 = dot(Local3, Material_VectorExpressions[2]);
float Local5 = (Local2 + Local4);
float4 Local6 = Texture2DSample(Material_Texture2D_0,Material_Texture2D_0Sampler,Parameters.TexCoords[3].xy);
float Local7 = dot(Local6, Material_VectorExpressions[3]);
float Local8 = (Local5 + Local7);
float Local9 = (1.00000000 / Local8);
float Local10 = dot(Parameters.TexCoords[0].xy, float2 (-0.00000000,1.00000000));
float Local11 = dot(Parameters.TexCoords[0].xy, float2 (1.00000000,0.00000000));
float2 Local12 = (1.00000000 * float2 (Local11,Local10));
float2 Local13 = (Local12 + float2 (0.00000000,0.00000000));
float4 Local14 = UnpackNormalMap(Texture2DSampleBias(Material_Texture2D_1,Material_Texture2D_1Sampler,Local13,View_MaterialTextureMipBias));
float3 Local15 = (Local14.rgb * Local1);
float3 Local16 = (0.00000000 + Local15);
float Local17 = (-1.00000000 + View_MaterialTextureMipBias);
float4 Local18 = UnpackNormalMap(Texture2DSampleLevel(Material_Texture2D_2,Material_Texture2D_2Sampler,Local13, float (Local17)));
float Local19 = (-1.00000000 + View_MaterialTextureMipBias);
float4 Local20 = UnpackNormalMap(Texture2DSampleLevel(Material_Texture2D_3,Material_Texture2D_3Sampler,Local13, float (Local19)));
float3 Local21 = (Local18.rgb + Local20.rgb);
float3 Local22 = (Local21 * Local4);
float3 Local23 = (Local16 + Local22);
float3 Local24 = (Local20.rgb * Local7);
float3 Local25 = (Local23 + Local24);
PixelMaterialInputs.Normal = Local25;
float3 MaterialNormal = GetMaterialNormal(Parameters, PixelMaterialInputs);
#line 1892 "/Engine/Generated/Material.ush"
MaterialNormal = normalize(MaterialNormal);
Parameters.WorldNormal = TransformTangentNormalToWorld(Parameters.TangentToWorld, MaterialNormal);
#line 1907 "/Engine/Generated/Material.ush"
Parameters.WorldNormal *= Parameters.TwoSidedSign;
Parameters.ReflectionVector = ReflectionAboutCustomWorldNormal(Parameters, Parameters.WorldNormal, false);
Parameters.Particle.MotionBlurFade = 1.0f;
float4 Local26 = Texture2DSample(Material_Texture2D_0,Material_Texture2D_0Sampler,Parameters.TexCoords[3].xy);
float Local27 = dot(Local26, Material_VectorExpressions[1]);
float Local28 = (0.00000000 + Local27);
float4 Local29 = Texture2DSample(Material_Texture2D_0,Material_Texture2D_0Sampler,Parameters.TexCoords[3].xy);
float Local30 = dot(Local29, Material_VectorExpressions[2]);
float Local31 = (Local28 + Local30);
float4 Local32 = Texture2DSample(Material_Texture2D_0,Material_Texture2D_0Sampler,Parameters.TexCoords[3].xy);
float Local33 = dot(Local32, Material_VectorExpressions[3]);
float Local34 = (Local31 + Local33);
float Local35 = (1.00000000 / Local34);
float4 Local36 = ProcessMaterialColorTextureLookup(Texture2DSampleBias(Material_Texture2D_4,Material_Texture2D_4Sampler,Local13,View_MaterialTextureMipBias));
float3 Local37 = (Local36.rgb * Local27);
float3 Local38 = (0.00000000 + Local37);
float Local39 = (-1.00000000 + View_MaterialTextureMipBias);
float4 Local40 = ProcessMaterialColorTextureLookup(Texture2DSampleLevel(Material_Texture2D_5,Material_Texture2D_5Sampler,Local13, float (Local39)));
float3 Local41 = (Local40.rgb * Local30);
float3 Local42 = (Local38 + Local41);
float Local43 = (-1.00000000 + View_MaterialTextureMipBias);
float4 Local44 = ProcessMaterialColorTextureLookup(Texture2DSampleLevel(Material_Texture2D_6,Material_Texture2D_6Sampler,Local13, float (Local43)));
float3 Local45 = (Local44.rgb * Local33);
float3 Local46 = (Local42 + Local45);
PixelMaterialInputs.EmissiveColor = Material_VectorExpressions[5].rgb;
PixelMaterialInputs.Opacity = 1.00000000;
PixelMaterialInputs.OpacityMask = 1.00000000;
PixelMaterialInputs.BaseColor = Local46;
PixelMaterialInputs.Metallic = 0.00000000;
PixelMaterialInputs.Specular = 0.50000000;
PixelMaterialInputs.Roughness = 0.50000000;
PixelMaterialInputs.Subsurface = 0;
PixelMaterialInputs.AmbientOcclusion = 1.00000000;
PixelMaterialInputs.Refraction = 0;
PixelMaterialInputs.PixelDepthOffset = 0.00000000;
###TrueDynamicBranchあり
void CalcPixelMaterialInputs(in out FMaterialPixelParameters Parameters, in out FPixelMaterialInputs PixelMaterialInputs)
{
float4 Local0 = Texture2DSample(Material_Texture2D_0,Material_Texture2D_0Sampler,Parameters.TexCoords[3].xy);
float Local1 = dot(Local0, Material_VectorExpressions[1]);
float Local2 = (1.00000000 - Local1);
float Local13 = dot(Parameters.TexCoords[0].xy, float2 (-0.00000000,1.00000000));
float Local14 = dot(Parameters.TexCoords[0].xy, float2 (1.00000000,0.00000000));
float2 Local15 = (1.00000000 * float2 (Local14,Local13));
float2 Local16 = (Local15 + float2 (0.00000000,0.00000000));
float4 Local17 = UnpackNormalMap(Texture2DSampleBias(Material_Texture2D_1,Material_Texture2D_1Sampler,Local16,View_MaterialTextureMipBias));
float Local20 = (-1.00000000 + View_MaterialTextureMipBias);
float Local22 = (-1.00000000 + View_MaterialTextureMipBias);
float3 Local29 = Local17.rgb;
[branch]
if(Local2 > 0.0){
float4 Local3 = Texture2DSample(Material_Texture2D_0,Material_Texture2D_0Sampler,Parameters.TexCoords[3].xy);
float Local4 = dot(Local3, Material_VectorExpressions[1]);
float Local5 = (0.00000000 + Local4);
float4 Local6 = Texture2DSample(Material_Texture2D_0,Material_Texture2D_0Sampler,Parameters.TexCoords[3].xy);
float Local7 = dot(Local6, Material_VectorExpressions[2]);
float Local8 = (Local5 + Local7);
float4 Local9 = Texture2DSample(Material_Texture2D_0,Material_Texture2D_0Sampler,Parameters.TexCoords[3].xy);
float Local10 = dot(Local9, Material_VectorExpressions[3]);
float Local11 = (Local8 + Local10);
float Local12 = (1.00000000 / Local11);
float3 Local18 = (Local17.rgb * Local4);
float3 Local19 = (0.00000000 + Local18);
float4 Local21 = UnpackNormalMap(Texture2DSampleLevel(Material_Texture2D_2,Material_Texture2D_2Sampler,Local16, float (Local20)));
float4 Local23 = UnpackNormalMap(Texture2DSampleLevel(Material_Texture2D_3,Material_Texture2D_3Sampler,Local16, float (Local22)));
float3 Local24 = (Local21.rgb + Local23.rgb);
float3 Local25 = (Local24 * Local7);
float3 Local26 = (Local19 + Local25);
float3 Local27 = (Local23.rgb * Local10);
float3 Local28 = (Local26 + Local27);
float3 Local30 = 0.0;
Local29 = Local28;
};
PixelMaterialInputs.Normal = Local29;
float3 MaterialNormal = GetMaterialNormal(Parameters, PixelMaterialInputs);
#line 1901 "/Engine/Generated/Material.ush"
MaterialNormal = normalize(MaterialNormal);
Parameters.WorldNormal = TransformTangentNormalToWorld(Parameters.TangentToWorld, MaterialNormal);
#line 1916 "/Engine/Generated/Material.ush"
Parameters.WorldNormal *= Parameters.TwoSidedSign;
Parameters.ReflectionVector = ReflectionAboutCustomWorldNormal(Parameters, Parameters.WorldNormal, false);
Parameters.Particle.MotionBlurFade = 1.0f;
float4 Local41 = ProcessMaterialColorTextureLookup(Texture2DSampleBias(Material_Texture2D_4,Material_Texture2D_4Sampler,Local16,View_MaterialTextureMipBias));
float Local44 = (-1.00000000 + View_MaterialTextureMipBias);
float Local48 = (-1.00000000 + View_MaterialTextureMipBias);
float3 Local52 = Local41.rgb;
[branch]
if(Local2 > 0.0){
float4 Local31 = Texture2DSample(Material_Texture2D_0,Material_Texture2D_0Sampler,Parameters.TexCoords[3].xy);
float Local32 = dot(Local31, Material_VectorExpressions[1]);
float Local33 = (0.00000000 + Local32);
float4 Local34 = Texture2DSample(Material_Texture2D_0,Material_Texture2D_0Sampler,Parameters.TexCoords[3].xy);
float Local35 = dot(Local34, Material_VectorExpressions[2]);
float Local36 = (Local33 + Local35);
float4 Local37 = Texture2DSample(Material_Texture2D_0,Material_Texture2D_0Sampler,Parameters.TexCoords[3].xy);
float Local38 = dot(Local37, Material_VectorExpressions[3]);
float Local39 = (Local36 + Local38);
float Local40 = (1.00000000 / Local39);
float3 Local42 = (Local41.rgb * Local32);
float3 Local43 = (0.00000000 + Local42);
float4 Local45 = ProcessMaterialColorTextureLookup(Texture2DSampleLevel(Material_Texture2D_5,Material_Texture2D_5Sampler,Local16, float (Local44)));
float3 Local46 = (Local45.rgb * Local35);
float3 Local47 = (Local43 + Local46);
float4 Local49 = ProcessMaterialColorTextureLookup(Texture2DSampleLevel(Material_Texture2D_6,Material_Texture2D_6Sampler,Local16, float (Local48)));
float3 Local50 = (Local49.rgb * Local38);
float3 Local51 = (Local47 + Local50);
float3 Local53 = 0.0;
Local52 = Local51;
};
PixelMaterialInputs.EmissiveColor = Material_VectorExpressions[5].rgb;
PixelMaterialInputs.Opacity = 1.00000000;
PixelMaterialInputs.OpacityMask = 1.00000000;
PixelMaterialInputs.BaseColor = Local52;
PixelMaterialInputs.Metallic = 0.00000000;
PixelMaterialInputs.Specular = 0.50000000;
PixelMaterialInputs.Roughness = 0.50000000;
PixelMaterialInputs.Subsurface = 0;
PixelMaterialInputs.AmbientOcclusion = 1.00000000;
PixelMaterialInputs.Refraction = 0;
PixelMaterialInputs.PixelDepthOffset = 0.00000000;
}
##ヤケクソ半透明編
もやっとする結果に終わったのでわかりやすい例も作って自己満に浸る
###マテリアル全景
むやみにテクスチャをサンプルして適当に合成
TrueDyanmicBranchと組み込みの偽DyanmicBranchを比較する
###レベル外観
プレーンにマテリアルを張り付けて、それぞれ10枚コピペします。
###計測条件
ブレンドレイヤーとほぼ同じ。
F2は押してない
####やけくそ半透明マテリアル計測結果
マテリアル | Translucent |
---|---|
ブランチなし | 55msくらい |
ブランチあり | 14msくらい |
わかりやすく変わりました。
サーフェスの一部を選択してサンプラーを酷使するようなカスタムポストプロセスマテリアルなんかでも有用な気がします!
###やけくそ半透明マテリアルのUSF
void CalcPixelMaterialInputs(in out FMaterialPixelParameters Parameters, in out FPixelMaterialInputs PixelMaterialInputs)
{
PixelMaterialInputs.Normal = float3 (0.00000000,0.00000000,1.00000000);
float3 MaterialNormal = GetMaterialNormal(Parameters, PixelMaterialInputs);
#line 1863 "/Engine/Generated/Material.ush"
MaterialNormal = normalize(MaterialNormal);
Parameters.WorldNormal = TransformTangentNormalToWorld(Parameters.TangentToWorld, MaterialNormal);
#line 1878 "/Engine/Generated/Material.ush"
Parameters.WorldNormal *= Parameters.TwoSidedSign;
Parameters.ReflectionVector = ReflectionAboutCustomWorldNormal(Parameters, Parameters.WorldNormal, false);
Parameters.Particle.MotionBlurFade = 1.0f;
float Local0 = (-1.00000000 + View_MaterialTextureMipBias);
float4 Local1 = ProcessMaterialColorTextureLookup(Texture2DSampleLevel(Material_Texture2D_0,Material_Texture2D_0Sampler,Parameters.TexCoords[0].xy, float (Local0)));
float Local2 = (Local1.r - 0.50000000);
float Local3 = (-1.00000000 + View_MaterialTextureMipBias);
float Local5 = (-1.00000000 + View_MaterialTextureMipBias);
float3 Local8 = Local1.rgb;
[branch]
if(Local2 > 0.0){
float4 Local4 = ProcessMaterialColorTextureLookup(Texture2DSampleLevel(Material_Texture2D_1,Material_Texture2D_1Sampler,Parameters.TexCoords[0].xy, float (Local3)));
float4 Local6 = ProcessMaterialColorTextureLookup(Texture2DSampleLevel(Material_Texture2D_2,Material_Texture2D_2Sampler,Parameters.TexCoords[0].xy, float (Local5)));
float3 Local7 = (Local4.rgb + Local6.rgb);
float3 Local9 = 0.0;
Local8 = Local7;
};
float3 Local10 = (Local8 + Material_VectorExpressions[1].rgb);
float Local11 = (-1.00000000 + View_MaterialTextureMipBias);
float4 Local12 = ProcessMaterialColorTextureLookup(Texture2DSampleLevel(Material_Texture2D_3,Material_Texture2D_3Sampler,Parameters.TexCoords[0].xy, float (Local11)));
float Local13 = (Local12.r - 0.20000000);
float Local15 = (-1.00000000 + View_MaterialTextureMipBias);
float Local17 = (-1.00000000 + View_MaterialTextureMipBias);
float Local20 = (-1.00000000 + View_MaterialTextureMipBias);
float Local23 = (-1.00000000 + View_MaterialTextureMipBias);
float Local25 = (-1.00000000 + View_MaterialTextureMipBias);
float3 Local32 = Local12.rgb;
[branch]
if(Local13 > 0.0){
float Local14 = MaterialExpressionNoise(GetWorldPosition(Parameters),1.00000000,1.00000000,0.00000000,1.00000000,6.00000000,-1.00000000,1.00000000,2.00000000,0.00000000,0.00000000,512.00000000);
float4 Local16 = ProcessMaterialColorTextureLookup(Texture2DSampleLevel(Material_Texture2D_4,Material_Texture2D_4Sampler,Parameters.TexCoords[0].xy, float (Local15)));
float4 Local18 = ProcessMaterialColorTextureLookup(Texture2DSampleLevel(Material_Texture2D_5,Material_Texture2D_5Sampler,Parameters.TexCoords[0].xy, float (Local17)));
float3 Local19 = (Local16.rgb + Local18.rgb);
float4 Local21 = ProcessMaterialColorTextureLookup(Texture2DSampleLevel(Material_Texture2D_6,Material_Texture2D_6Sampler,Parameters.TexCoords[0].xy, float (Local20)));
float3 Local22 = (Local19 + Local21.rgb);
float4 Local24 = ProcessMaterialColorTextureLookup(Texture2DSampleLevel(Material_Texture2D_7,Material_Texture2D_7Sampler,Parameters.TexCoords[0].xy, float (Local23)));
float4 Local26 = ProcessMaterialColorTextureLookup(Texture2DSampleLevel(Material_Texture2D_8,Material_Texture2D_8Sampler,Parameters.TexCoords[0].xy, float (Local25)));
float3 Local27 = (Local24.rgb + Local26.rgb);
float3 Local28 = (Local27 + Local12.rgb);
float3 Local29 = (Local22 + Local28);
float3 Local30 = (Local14 + Local29);
float3 Local31 = (Local30 * 0.20000000);
float3 Local33 = 0.0;
Local32 = Local31;
};
PixelMaterialInputs.EmissiveColor = Local10;
PixelMaterialInputs.Opacity = 0.50000000;
PixelMaterialInputs.OpacityMask = 1.00000000;
PixelMaterialInputs.BaseColor = Local32;
PixelMaterialInputs.Metallic = 0.00000000;
PixelMaterialInputs.Specular = 0.50000000;
PixelMaterialInputs.Roughness = 0.50000000;
PixelMaterialInputs.Subsurface = 0;
PixelMaterialInputs.AmbientOcclusion = 1.00000000;
PixelMaterialInputs.Refraction = float2 ( float2 ( float2 (1.00000000,0.00000000).r,0).r,Material_ScalarExpressions[0].x);
PixelMaterialInputs.PixelDepthOffset = 0.00000000;
}
#おわりに
ながながと取り留めのないことをつらつらと書いてきましたが
ある程度成果がでてよかったです。
修正すべき点はまだまだあるのでもう少し改良を加えたらプルリクエストしてみようと思います。
明日は@nano06126728さんです!