enum EMaterialProperty
{
...
MP_PixelDepthOffset,
MP_Tangent,
MP_Anisotropy,
//^^^ New material properties go above here ^^^^
...
UPROPERTY()
FScalarMaterialInput PixelDepthOffset;
UPROPERTY()
FVectorMaterialInput Tangent;
UPROPERTY()
FScalarMaterialInput Anisotropy;
UPROPERTY()
FExpressionInput PixelDepthOffset;
UPROPERTY()
FExpressionInput Tangent;
UPROPERTY()
FExpressionInput Anisotropy;
MaterialInputs.Add(FMaterialInputInfo(LOCTEXT("PixelDepthOffset", "Pixel Depth Offset"), MP_PixelDepthOffset));
MaterialInputs.Add(FMaterialInputInfo(LOCTEXT("Tangent", "Tangent"), MP_Tangent));
MaterialInputs.Add(FMaterialInputInfo(LOCTEXT("Anisotropy", "Anisotropy"), MP_Anisotropy));
Chunk[MP_PixelDepthOffset] = Material->CompilePropertyAndSetMaterialProperty(MP_PixelDepthOffset,this);
Chunk[MP_Tangent] = Material->CompilePropertyAndSetMaterialProperty(MP_Tangent, this);
Chunk[MP_Anisotropy] = Material->CompilePropertyAndSetMaterialProperty(MP_Anisotropy, this);
LazyPrintf.PushParam(*GenerateFunctionCode(MP_PixelDepthOffset));
LazyPrintf.PushParam(*GenerateFunctionCode(MP_Tangent));
LazyPrintf.PushParam(*GenerateFunctionCode(MP_Anisotropy));
DoMaterialAttributeReorder(&PixelDepthOffset, Ar.UE4Ver());
DoMaterialAttributeReorder(&Tangent, Ar.UE4Ver());
DoMaterialAttributeReorder(&Anisotropy, Ar.UE4Ver());
static_assert(MP_MAX == 30, "New material properties must have DoMaterialAttributesReorder called on them to ensure that any future reordering of property pins is correctly applied.");
FExpressionInput* UMaterial::GetExpressionInputForProperty(EMaterialProperty InProperty)
...
case MP_PixelDepthOffset: return &PixelDepthOffset;
case MP_Tangent: return &Tangent;
case MP_Anisotropy: return &Anisotropy;
int32 UMaterial::CompilePropertyEx( FMaterialCompiler* Compiler, EMaterialProperty Property )
...
case MP_PixelDepthOffset: return PixelDepthOffset.CompileWithDefault(Compiler, Property);
case MP_Tangent: return Tangent.CompileWithDefault(Compiler, Property);
case MP_Anisotropy: return Anisotropy.CompileWithDefault(Compiler, Property);
case MP_PixelDepthOffset:
Active = !IsTranslucentBlendMode((EBlendMode)BlendMode);
break;
case MP_Tangent:
case MP_Anisotropy:
Active = ShadingModel == MSM_Anisotropy;
break;
int32 UMaterialExpressionMakeMaterialAttributes::Compile(class FMaterialCompiler* Compiler, int32 OutputIndex, int32 MultiplexIndex)
...
static_assert(MP_MAX == 30,
"New material properties should be added to the end of the inputs for this expression. \
The order of properties here should match the material results pins, the make material attriubtes node inputs and the mapping of IO indices to properties in GetMaterialPropertyFromInputOutputIndex().\
Insertions into the middle of the properties or a change in the order of properties will also require that existing data is fixed up in DoMaterialAttriubtesReorder().\
");
EMaterialProperty Property = GetMaterialPropertyFromInputOutputIndex(MultiplexIndex);
switch (Property)
....
case MP_PixelDepthOffset: Ret = PixelDepthOffset.Compile(Compiler); Expression = PixelDepthOffset.Expression; break;
case MP_Tangent: Ret = Tangent.Compile(Compiler); Expression = Tangent.Expression; break;
case MP_Anisotropy: Ret = Anisotropy.Compile(Compiler); Expression = Anisotropy.Expression; break;
};
UMaterialExpressionBreakMaterialAttributes::UMaterialExpressionBreakMaterialAttributes(const FObjectInitializer& ObjectInitializer)
...
static_assert(MP_MAX == 30,
"New material properties should be added to the end of the outputs for this expression. \
The order of properties here should match the material results pins, the make material attriubtes node inputs and the mapping of IO indices to properties in GetMaterialPropertyFromInputOutputIndex().\
Insertions into the middle of the properties or a change in the order of properties will also require that existing data is fixed up in DoMaterialAttriubtesReorder().\
");
...
Outputs.Add(FExpressionOutput(TEXT("PixelDepthOffset"), 1, 1, 1, 1, 0));
Outputs.Add(FExpressionOutput(TEXT("Tangent"), 1, 1, 1, 1, 0));
Outputs.Add(FExpressionOutput(TEXT("Anisotropy"), 1, 1, 1, 1, 0));
}
EMaterialValueType GetMaterialPropertyType(EMaterialProperty Property)
...
case MP_PixelDepthOffset: return MCT_Float;
case MP_Tangent: return MCT_Float3;
case MP_Anisotropy: return MCT_Float;
};
const TMapCreatePropertyToIOIndexMap()
...
static_assert(MP_MAX == 30,
"New material properties should be added to the end of \"real\" properties in this map. Immediately before MP_MaterialAttributes . \
The order of properties here should match the material results pins, the inputs to MakeMaterialAttriubtes and the outputs of BreakMaterialAttriubtes.\
Insertions into the middle of the properties or a change in the order of properties will also require that existing data is fixed up in DoMaterialAttriubtesReorder().\
");
...
Ret.Add(MP_PixelDepthOffset, 24);
Ret.Add(MP_Tangent, 25);
Ret.Add(MP_Anisotropy, 26);
//^^^^ New properties go above here ^^^^
int32 GetDefaultExpressionForMaterialProperty(FMaterialCompiler* Compiler, EMaterialProperty Property)
...
case MP_Refraction: return Compiler->Constant3(1, 0, 0);
case MP_Tangent: return Compiler->Constant3(1, 0, 0);
case MP_Anisotropy: return Compiler->Constant(0.0f);
FString GetNameOfMaterialProperty(EMaterialProperty Property)
...
case MP_PixelDepthOffset: return TEXT("PixelDepthOffset");
case MP_Tangent: return TEXT("Tangent");
case MP_Anisotropy: return TEXT("Anisotropy");
};
struct FMaterialPixelParameters
...
#if (ES2_PROFILE || ES3_1_PROFILE)
float4 LayerWeights;
#endif
half3 WorldTangent;
};
FMaterialPixelParameters MakeInitializedMaterialPixelParameters()
...
MPP.TangentToWorld = float3x3(1,0,0,0,1,0,0,0,1);
MPP.WorldTangent = 0;
return MPP;
}
float GetMaterialPixelDepthOffset(FMaterialPixelParameters Parameters)
{
%s;
}
half3 GetMaterialTangentRaw(FMaterialPixelParameters Parameters)
{
%s;
}
half3 GetMaterialTangent(FMaterialPixelParameters Parameters)
{
half3 RetTangent;
RetTangent = GetMaterialTangentRaw(Parameters);
return RetTangent;
}
float GetMaterialAnisotropy(FMaterialPixelParameters Parameters)
{
%s;
}
void CalcMaterialParameters(
...
#if !PARTICLE_SPRITE_FACTORY
Parameters.Particle.MotionBlurFade = 1.0f;
#endif // !PARTICLE_SPRITE_FACTORY
half3 TangentTangent = GetMaterialTangent(Parameters);
#if MATERIAL_TANGENTSPACENORMAL
TangentTangent *= Parameters.TwoSidedSign;
#if FEATURE_LEVEL >= FEATURE_LEVEL_SM4
// ES2 will rely on only the final normalize for performance
TangentTangent = normalize(TangentTangent);
#endif
// normalizing after the tangent space to world space conversion improves quality with sheared bases (UV layout to WS causes shrearing)
Parameters.WorldTangent = normalize(TransformTangentVectorToWorld(Parameters.TangentToWorld, TangentTangent));
#else
Parameters.WorldNormal = normalize(TangentTangent);
#endif
}
#define SHADINGMODELID_TWOSIDED_FOLIAGE 6
#define SHADINGMODELID_ANISOTROPY 7
#define SHADINGMODELID_NUM 8
float3 EncodeTangentAndAnisotropy(half3 WorldTangent, float Anisotropy)
{
float TangentXYLength = length(WorldTangent.xy);
float ZAngle = atan2(WorldTangent.y, WorldTangent.x); // -PI <= ZAngle <= PI
ZAngle = ZAngle / PI * 0.5f + 0.5f; // -> 0 <= ZAngle <= 1.0
float ZSign = WorldTangent.z >= 0.0f ? 0.0f : 128.0f;
float ZSign_and_Anisotropy = (ZSign + (Anisotropy * 127.0f)) / 255.0f;
return float3(TangentXYLength, ZAngle, ZSign_and_Anisotropy);
}
void DecodeTangentAndAnisotropy(out float3 WorldTangent, out float Anisotropy, float3 CustomData)
{
// Decompress WorldTanget and Anisotropy by polar coordination.
float polarLength = CustomData.x;
float polarAngle = (CustomData.y * 2.0f - 1.0f) * 3.1415926;
float s, c;
sincos(polarAngle, s, c);
float2 txy = float2(c, s) * polarLength;
float zSign = CustomData.z >= (127.5f / 255.0f) ? -1.0f : 1.0f;
WorldTangent = float3(txy, zSign * sqrt(max(1.0f - dot(txy.xy, txy.xy), 0.0f)));
Anisotropy = (zSign < 0.0f) ? CustomData.z - 0.5f : CustomData.z;
Anisotropy = Anisotropy * 255.0f / 127.0f;
}
#elif MATERIAL_SHADINGMODEL_TWOSIDED_FOLIAGE
GBuffer.ShadingModelID = SHADINGMODELID_TWOSIDED_FOLIAGE;
GBuffer.CustomData = EncodeSubsurfaceColor(SubsurfaceColor);
#elif MATERIAL_SHADINGMODEL_ANISOTROPY
GBuffer.ShadingModelID = SHADINGMODELID_ANISOTROPY;
half3 WorldTangent = MaterialParameters.WorldTangent;
float Anisotropy = GetMaterialAnisotropy(MaterialParameters);
GBuffer.CustomData = EncodeTangentAndAnisotropy(WorldTangent, Anisotropy);
float3 GGXAnisoShading( FGBufferData GBuffer, float3 LobeRoughness, float3 LobeEnergy, float3 L, float3 V, half3 N, float2 DiffSpecMask )
{
float3 H = normalize(V + L);
float NoL = saturate( dot(N, L) );
float NoV = max( dot(N, V), 1e-5 );
float NoH = saturate( dot(N, H) );
float VoH = saturate( dot(V, H) );
float3 WorldTangent;
float Anisotropy;
DecodeTangentAndAnisotropy(WorldTangent, Anisotropy, GBuffer.CustomData);
float3 B = normalize(cross(N, WorldTangent));
float3 T = normalize(cross(B, N));
// Generalized microfacet specular
float aspect = sqrt(1.0f - Anisotropy * 0.9f);
float anisoXRoughness = max(0.01f, LobeRoughness[1] / aspect);
float anisoYRoughness = max(0.01f, LobeRoughness[1] * aspect);
float D = D_GGXaniso( anisoXRoughness, anisoYRoughness, NoH, H, T, B ) * LobeEnergy[1];
float Vis = Vis_SmithJointApprox( LobeRoughness[1], NoV, NoL );
float3 F = F_Schlick( GBuffer.SpecularColor, VoH );
float3 Diffuse = Diffuse_Lambert( GBuffer.DiffuseColor );
return Diffuse * (LobeEnergy[2] * DiffSpecMask.r) + (D * Vis * DiffSpecMask.g) * F;
}
// @param DiffSpecMask .r: diffuse, .g:specular e.g. float2(1,1) for both, float2(1,0) for diffuse only
float3 SurfaceShading( FGBufferData GBuffer, float3 LobeRoughness, float3 LobeEnergy, float3 L, float3 V, half3 N, float2 DiffSpecMask )
...
case SHADINGMODELID_CLEAR_COAT:
// this path does not support DiffSpecMask yet
return ClearCoatShading( GBuffer, LobeRoughness, LobeEnergy, L, V, N );
case SHADINGMODELID_ANISOTROPY:
return GGXAnisoShading( GBuffer, LobeRoughness, LobeEnergy, L, V, N, DiffSpecMask);
if( GBuffer.ShadingModelID != SHADINGMODELID_UNLIT )
{
float3 N = GBuffer.WorldNormal;
float3 V = -CameraToPixel;
if( GBuffer.ShadingModelID == SHADINGMODELID_ANISOTROPY )
{
float3 WorldTangent;
float Anisotropy;
DecodeTangentAndAnisotropy(WorldTangent, Anisotropy, GBuffer.CustomData);
float3 B = normalize(cross(N, WorldTangent));
float3 AnisoTangent = cross(B, V);
float3 AnisoNormal = cross(AnisoTangent, B);
N = normalize(lerp(N, AnisoNormal, Anisotropy));
}
float3 N = GBuffer.WorldNormal;
const float SceneDepth = CalcSceneDepth(UV);
const float3 PositionTranslatedWorld = mul( float4( ScreenPos * SceneDepth, SceneDepth, 1 ), View.ScreenToTranslatedWorld ).xyz;
const float3 V = normalize(View.TranslatedViewOrigin.xyz - PositionTranslatedWorld);
if( GBuffer.ShadingModelID == SHADINGMODELID_ANISOTROPY )
{
float3 WorldTangent;
float Anisotropy;
DecodeTangentAndAnisotropy(WorldTangent, Anisotropy, GBuffer.CustomData);
float3 B = normalize(cross(N, WorldTangent));
float3 AnisoTangent = cross(B, V);
float3 AnisoNormal = cross(AnisoTangent, B);
N = normalize(lerp(N, AnisoNormal, Anisotropy));
}
Author:monsho
ゲームプログラマ?