시작하며
커스텀 셰이딩 모델을 추가한 뒤 막상 이를 사용해서 머티리얼을 만들려고 하면 파라미터를 전달할 핀이 부족한 경우가 생겨요. 그래서 이번에는 현재 머티리얼 도메인에 비활성화 돼있는 핀을 활성화하고 그 핀들에 노드를 연결하여 커스텀 파라미터를 셰이더에 전달해 보려고 해요.
앞서와 마찬가지로 먼저 엔진 코드를 수정하고 빌드한 후에 셰이더 코드를 수정해 보기로 하죠. Custom Data ##은 간단하게 몇몇 코드를 수정하는 것으로 활성화 됩니다. 이들은 스칼라고 셰이더에서는 half로 전달 돼요. 3차원 벡터를 전달하는 방법에 대해서는 나중에 얘기로 하기로 할게요.
엔진 코드 수정하기
Material.cpp
어떤 셰이딩 모델에서 커스텀 데이타 핀을 쓸지 알려줍니다
static bool IsPropertyActive_Internal(EMaterialProperty InProperty,
EMaterialDomain Domain,
EBlendMode BlendMode,
FMaterialShadingModelField ShadingModels,
ETranslucencyLightingMode TranslucencyLightingMode,
bool bBlendableOutputAlpha,
bool bUsesDistortion,
bool bUsesShadingModelFromMaterialExpression,
bool bIsTranslucencyWritingVelocity,
bool bIsThinSurface,
bool bIsSupported)
{
// [...]
else
{
switch (InProperty)
{
// [...]
// [ CUSTOM ] Custom data - scalar
case MP_CustomData0:
Active = ShadingModels.HasAnyShadingModel({ MSM_ClearCoat, MSM_Hair, MSM_Cloth, MSM_Eye, MSM_SubsurfaceProfile, MSM_CustomLit});
break;
// [...]
}
}
// [...]
}
MaterialAttributeDefinitionMap.cpp
커스텀 데이터 핀의 이름을 정해줍니다
FText FMaterialAttributeDefinitionMap::GetAttributeOverrideForMaterial(const FGuid& AttributeID, UMaterial* Material)
{
// [...]
case MP_CustomData0:
CustomPinNames.Add({ MSM_ClearCoat, "Clear Coat" });
CustomPinNames.Add({ MSM_Hair, "Backlit" });
CustomPinNames.Add({ MSM_Cloth, "Cloth" });
CustomPinNames.Add({ MSM_Eye, "Iris Mask" });
CustomPinNames.Add({ MSM_SubsurfaceProfile, "Curvature" });
// [ CUSTOM ] Custom data - Adding custom scalar pin name
CustomPinNames.Add({ MSM_CustomLit, "Shading Param 0" });
return FText::FromString(GetPinNameFromShadingModelField(Material->GetShadingModels(), CustomPinNames, "Custom Data 0"));
// [...]
}
ShaderGenerationUtil.cpp
커스텀 데이터 핀을 활성화 시킵니다
static void SetSlotsForShadingModelType(bool Slots[], EMaterialShadingModel ShadingModel, bool bMergeCustom)
{
switch (ShadingModel)
{
// [...]
// [ CUSTOM ] Custom data
case MSM_CustomLit:
SetSharedGBufferSlots(Slots);
if (bMergeCustom)
{
Slots[GBS_CustomData] = true;
}
else
{
Slots[GBS_Opacity] = true;
}
break;
// [...]
}
}
ShaderMaterialDerivedHelpers.cpp
어떤 셰이딩 모델에서 커스텀 데이터를 GBuffer로 전달할지 알려줍니다
FShaderMaterialDerivedDefines RENDERCORE_API CalculateDerivedMaterialParameters(
const FShaderMaterialPropertyDefines& Mat,
const FShaderLightmapPropertyDefines& Lightmap,
const FShaderGlobalDefines& SrcGlobal,
const FShaderCompilerDefines& Compiler,
ERHIFeatureLevel::Type FEATURE_LEVEL)
{
// [...]
// [ CUSTOM ] Custom data
Dst.WRITES_CUSTOMDATA_TO_GBUFFER = (Dst.USES_GBUFFER && (Mat.MATERIAL_SHADINGMODEL_SUBSURFACE || Mat.MATERIAL_SHADINGMODEL_PREINTEGRATED_SKIN || Mat.MATERIAL_SHADINGMODEL_SUBSURFACE_PROFILE || Mat.MATERIAL_SHADINGMODEL_CLEAR_COAT || Mat.MATERIAL_SHADINGMODEL_TWOSIDED_FOLIAGE || Mat.MATERIAL_SHADINGMODEL_HAIR || Mat.MATERIAL_SHADINGMODEL_CLOTH || Mat.MATERIAL_SHADINGMODEL_EYE || Mat.MATERIAL_SHADINGMODEL_CUSTOM_LIT));
// [...]
}
빌드하기
셰이더 코드 수정하기
DeferredShadingCommon.ush
커스텀 데이터를 사용할 셰이딩 모델을 정합니다
bool HasCustomGBufferData(int ShadingModelID)
{
return ShadingModelID == SHADINGMODELID_SUBSURFACE
|| ShadingModelID == SHADINGMODELID_PREINTEGRATED_SKIN
|| ShadingModelID == SHADINGMODELID_CLEAR_COAT
|| ShadingModelID == SHADINGMODELID_SUBSURFACE_PROFILE
|| ShadingModelID == SHADINGMODELID_TWOSIDED_FOLIAGE
|| ShadingModelID == SHADINGMODELID_HAIR
|| ShadingModelID == SHADINGMODELID_CLOTH
|| ShadingModelID == SHADINGMODELID_EYE
// [ CUSTOM ] Custom data
|| ShadingModelID == SHADINGMODELID_CUSTOM_LIT;
}
ShadingModelsMaterial.ush
GBuffer에 커스텀 데이터를 전달합니다
void SetGBufferForShadingModel(
in out FGBufferData GBuffer,
in out FMaterialPixelParameters MaterialParameters,
const float Opacity,
const half3 BaseColor,
const half Metallic,
const half Specular,
const float Roughness,
const float Anisotropy,
const float3 SubsurfaceColor,
const float SubsurfaceProfile,
const float Dither,
const uint ShadingModel)
{
// [...]
// [ CUSTOM ] Custom data
#if MATERIAL_SHADINGMODEL_CUSTOM_LIT
else if (ShadingModel == SHADINGMODELID_CUSTOM_LIT)
{
GBuffer.CustomData.x = GetMaterialCustomData0(MaterialParameters);
GBuffer.CustomData.y = GetMaterialCustomData1(MaterialParameters);
GBuffer.CustomData.a = Opacity;
}
#endif
// [...]
}
결과
마치며
커스텀 셰이딩 모델에서 커스텀 데이터 핀을 활성화 시킬 수 있도록 엔진 코드와 셰이더 코드를 수정해 봤어요. 다음으로는 GBuffer를 확장하거나 수정하는 방법을 알아볼까 합니다. GBuffer를 수정하는 일은 그다지 권장할 만한 일은 아니지만 UE의 지연 렌더링 수행을 이해하는데 도움이 될 수 있어요.
참고
Learning Unreal Engine 4: Implement Cel-Shading w/ Outline Using Custom Shading Model in UE4.22 (1)
Create Your Own Shading Model
medium.com
'UE5' 카테고리의 다른 글
[UE5]Custom Shader : PART5_Editing GBuffer (2) | 2023.10.26 |
---|---|
[UE5]Custom Shader : PART4_Custom Material Ouput (1) | 2023.10.16 |
[UE5]Custom Shader : PART3_Adding shading models_2 (0) | 2023.09.27 |
[UE5]Custom Shader : PART1_Adding shading models_1 (0) | 2023.09.19 |