Material Expressionはどこから見れるの?
1. HLSL Codeから追う
Material EditorのWindow -> Shader Code -> HLSL Codeを開けばMaterial 全体のHLSLが見れます。
適当なEditorにコピペして「desaturation」を検索しますがヒットしません。
これは困った。
実際にはちゃんと実装されているんですが、それは後程解説します。
因みにIncludeされている .ush ですが、これらはUnreal Shader Fileの略称(だと思います)で、色々と便利な関数等が登録されています。
2. MaterialExpression.cpp を追う
実際のMaterial Expressionの実装についてはMaterialExpression.cpp を追うのが一番確実でしょう。
Engine\Source\Runtime\Engine\Private\Materials\MaterialExpression.cpp 内に記述があります。
Desaturationの実装については、UMaterialExpressionDesaturation() を追っていきます。
UMaterialExpressionDesaturation::UMaterialExpressionDesaturation(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
{
struct FConstructorStatics
{
FText NAME_Color;
FText NAME_Utility;
FConstructorStatics()
: NAME_Color(LOCTEXT( "Color", "Color" ))
, NAME_Utility(LOCTEXT( "Utility", "Utility" ))
{
}
};
static FConstructorStatics ConstructorStatics;
LuminanceFactors = FLinearColor(0.3f, 0.59f, 0.11f, 0.0f);
#if WITH_EDITORONLY_DATA
MenuCategories.Add(ConstructorStatics.NAME_Color);
MenuCategories.Add(ConstructorStatics.NAME_Utility);
#endif
}
#if WITH_EDITOR
int32 UMaterialExpressionDesaturation::Compile(class FMaterialCompiler* Compiler, int32 OutputIndex)
{
if(!Input.GetTracedInput().Expression)
return Compiler->Errorf(TEXT("Missing Desaturation input"));
int32 Color = Compiler->ForceCast(Input.Compile(Compiler), MCT_Float3, MFCF_ExactMatch|MFCF_ReplicateValue),
Grey = Compiler->Dot(Color,Compiler->Constant3(LuminanceFactors.R,LuminanceFactors.G,LuminanceFactors.B));
if(Fraction.GetTracedInput().Expression)
return Compiler->Lerp(Color,Grey,Fraction.Compile(Compiler));
else
return Grey;
}
#endif
パッと見は何をしているのかよくわからないかもしれませんが、実装自体は非常にシンプルです。
UMaterialExpressionDesaturation::Compile() 内の一部分だけを見ればよいです。
int32 UMaterialExpressionDesaturation::Compile(class FMaterialCompiler* Compiler, int32 OutputIndex)
{
...
int32 Color = Compiler->ForceCast(Input.Compile(Compiler), MCT_Float3, MFCF_ExactMatch|MFCF_ReplicateValue),
Grey = Compiler->Dot(Color,Compiler->Constant3(LuminanceFactors.R,LuminanceFactors.G,LuminanceFactors.B));
if(Fraction.GetTracedInput().Expression)
return Compiler->Lerp(Color,Grey,Fraction.Compile(Compiler));
else
return Grey;
}
入力されたColorにDot() でLuminanceFactorsを指定し
入力されたFractionがある場合にはLerpして、ない場合にはDot() の結果を返しています。
LuminanceFactors はUMaterialExpressionDesaturation() で定義されており、カラーからモノトーンな色に変換するための適当な係数です。
LuminanceFactors = FLinearColor(0.3f, 0.59f, 0.11f, 0.0f);
3. HLSL Codeでは追えないの?
1. でコピーしたHLSLをもう一度見てみます。
3000行近いコードが生成されて何がなんだか……という感じなのですが、実際に見るべきは
CalcPixelMaterialInputs() 内を見れば良いです。
void CalcPixelMaterialInputs(in out FMaterialPixelParameters Parameters, in out FPixelMaterialInputs PixelMaterialInputs)
{
PixelMaterialInputs.Normal = MaterialFloat3(0.00000000,0.00000000,1.00000000);
float3 MaterialNormal = GetMaterialNormal(Parameters, PixelMaterialInputs);
#if MATERIAL_TANGENTSPACENORMAL
#if SIMPLE_FORWARD_SHADING
Parameters.WorldNormal = float3(0, 0, 1);
#endif
#if FEATURE_LEVEL >= FEATURE_LEVEL_SM4
MaterialNormal = normalize(MaterialNormal);
#endif
Parameters.WorldNormal = TransformTangentNormalToWorld(Parameters.TangentToWorld, MaterialNormal);
#else
Parameters.WorldNormal = normalize(MaterialNormal);
#endif
#if MATERIAL_TANGENTSPACENORMAL
Parameters.WorldNormal *= Parameters.TwoSidedSign;
#endif
Parameters.ReflectionVector = ReflectionAboutCustomWorldNormal(Parameters, Parameters.WorldNormal, false);
#if !PARTICLE_SPRITE_FACTORY
Parameters.Particle.MotionBlurFade = 1.0f;
#endif
MaterialFloat3 Local0 = lerp(MaterialFloat3(0.00000000,0.00000000,0.00000000),Material.VectorExpressions[1].rgb,MaterialFloat(Material.ScalarExpressions[0].x));
MaterialFloat Local1 = MaterialStoreTexCoordScale(Parameters, Parameters.TexCoords[0].xy, 0);
MaterialFloat4 Local2 = ProcessMaterialLinearColorTextureLookup(Texture2DSampleBias(Material.Texture2D_0, Material.Texture2D_0Sampler,Parameters.TexCoords[0].xy,View.MaterialTextureMipBias));
MaterialFloat Local3 = MaterialStoreTexSample(Parameters, Local2, 0);
MaterialFloat Local4 = dot(Local2.rgb, MaterialFloat3(0.30000001,0.58999997,0.11000000));
MaterialFloat3 Local5 = lerp(Local2.rgb,MaterialFloat3(Local4,Local4,Local4),MaterialFloat(0.75000000));
PixelMaterialInputs.EmissiveColor = Local0;
PixelMaterialInputs.Opacity = 1.00000000;
PixelMaterialInputs.OpacityMask = 1.00000000;
PixelMaterialInputs.BaseColor = Local5;
PixelMaterialInputs.Metallic = 0.00000000;
PixelMaterialInputs.Specular = 0.50000000;
PixelMaterialInputs.Roughness = 0.50000000;
PixelMaterialInputs.Anisotropy = 0.00000000;
PixelMaterialInputs.Tangent = MaterialFloat3(1.00000000,0.00000000,0.00000000);
PixelMaterialInputs.Subsurface = 0;
PixelMaterialInputs.AmbientOcclusion = 1.00000000;
PixelMaterialInputs.Refraction = 0;
PixelMaterialInputs.PixelDepthOffset = 0.00000000;
PixelMaterialInputs.ShadingModel = 1;
#if MATERIAL_USES_ANISOTROPY
Parameters.WorldTangent = CalculateAnisotropyTangent(Parameters, PixelMaterialInputs);
#else
Parameters.WorldTangent = 0;
#endif
}
またしても長くて何がなんだか……という感じなのですが、実際に見るべき箇所はたったの2行です。
MaterialFloat Local4 = dot(Local2.rgb, MaterialFloat3(0.30000001,0.58999997,0.11000000));
MaterialFloat3 Local5 = lerp(Local2.rgb,MaterialFloat3(Local4,Local4,Local4),MaterialFloat(0.75000000));
この処理をよく見るとDesaturation() の記述はないものの、実行している処理は先程MaterialExpression.cpp で見たものと同じです。
入力されたColor に対してdot() で LuminanceFactors = FLinearColor(0.3f, 0.59f, 0.11f, 0.0f);と同じ係数を使用して
入力されたFractionに対してLerp() を使用しているだけです。