Skip to content

CustomShadingModels

2272字约8分钟

2022-07-17

背景

为了扩展UE的渲染风格,或者想深入了解整个渲染过程和管线设置,可以参考本文。

步骤

准备IDE

  • Rider for UnrealEngine
    • 用于代码编辑,Rider的高亮和HLSL高亮跳转远远优于VS。
  • Visual Studio 2019
    • 用于编译和调试,测试中VS的编译速度高于Rider,或许略有出入。

获取源码

这一部分非本文核心,给出一些参考文档:

C++部分

Engine/Source/Runtime/Engine/Classes/Engine/EngineTypes.h

这一部分中定义了着色模型的枚举类型,首先需要在此处增加我们的着色模型。这里需要注意:为了保持其他部分代码中的顺序一致,建议新增ShadingModel放置于MSM_NUM上方或MSM_Unlit上方。此外,由于EngineTypes涉及引擎的各个方面,且一旦改动会导致引用EngineTypes的CPP文件需要重新编译,数量极大建议一次改完。

UENUM()
enum EMaterialShadingModel
{
   MSM_Unlit              UMETA(DisplayName="Unlit"),
   MSM_DefaultLit          UMETA(DisplayName="Default Lit"),
   MSM_Subsurface          UMETA(DisplayName="Subsurface"),
   MSM_PreintegratedSkin     UMETA(DisplayName="Preintegrated Skin"),
   MSM_ClearCoat           UMETA(DisplayName="Clear Coat"),
   MSM_SubsurfaceProfile     UMETA(DisplayName="Subsurface Profile"),
   MSM_TwoSidedFoliage          UMETA(DisplayName="Two Sided Foliage"),
   MSM_Hair               UMETA(DisplayName="Hair"),
   MSM_Cloth              UMETA(DisplayName="Cloth"),
   MSM_Eye                   UMETA(DisplayName="Eye"),
   MSM_SingleLayerWater      UMETA(DisplayName="SingleLayerWater"),
   MSM_ThinTranslucent          UMETA(DisplayName="Thin Translucent"),
   // Feat: Add New Custom Shading Model
   // Author: Wanghu
   // Date: 2021/12/20
   MSM_Astroite            UMETA(DisplayName="Astroite"),
   /** Number of unique shading models. */
   MSM_NUM                   UMETA(Hidden),
   /** Shading model will be determined by the Material Expression Graph,
      by utilizing the 'Shading Model' MaterialAttribute output pin. */
   MSM_FromMaterialExpression UMETA(DisplayName="From Material Expression"),
   MSM_MAX
};

Engine/Source/Runtime/Engine/Private/Materials/MaterialShader.cpp

在此处设置上一步骤中定义的着色模型在材质编辑器中应该显示什么名字。

/** Converts an EMaterialShadingModel to a string description. */
FString GetShadingModelString(EMaterialShadingModel ShadingModel)
{
   FString ShadingModelName;
   switch(ShadingModel)
   {
      case MSM_Unlit:             ShadingModelName = TEXT("MSM_Unlit"); break;
      case MSM_DefaultLit:      ShadingModelName = TEXT("MSM_DefaultLit"); break;
      case MSM_Subsurface:      ShadingModelName = TEXT("MSM_Subsurface"); break;
      case MSM_PreintegratedSkin:    ShadingModelName = TEXT("MSM_PreintegratedSkin"); break;
      case MSM_ClearCoat:          ShadingModelName = TEXT("MSM_ClearCoat"); break;
      case MSM_SubsurfaceProfile:    ShadingModelName = TEXT("MSM_SubsurfaceProfile"); break;
      case MSM_TwoSidedFoliage:  ShadingModelName = TEXT("MSM_TwoSidedFoliage"); break;
      case MSM_Cloth:             ShadingModelName = TEXT("MSM_Cloth"); break;
      case MSM_Eye:           ShadingModelName = TEXT("MSM_Eye"); break;
      case MSM_SingleLayerWater: ShadingModelName = TEXT("MSM_SingleLayerWater"); break;
      case MSM_ThinTranslucent:  ShadingModelName = TEXT("MSM_ThinTranslucent"); break;
      // Feat: Add New Custom Shading Model
      // Author: Wanghu
      // Date: 2021/12/17
      case MSM_Astroite:       ShadingModelName = TEXT("MSM_Astroite"); break;
      default: ShadingModelName = TEXT("Unknown"); break;
   }
   return ShadingModelName;
}

Engine/Source/Runtime/Engine/Private/Materials/Material.cpp

这一部分可以定义我们的着色模型需要使用哪些材质参数,我们开启一下CustomData0和CustomData1,这两参数都是值域为[0,1]的float类型值:

case MP_CustomData0:
   // Feat: Add New Custom Shading Model
   // Author: Wanghu
   // Date: 2021/12/17
   Active = ShadingModels.HasAnyShadingModel({ MSM_ClearCoat, MSM_Hair, MSM_Cloth, MSM_Eye, MSM_Astroite });
   break;
case MP_CustomData1:
   // Feat: Add New Custom Shading Model
   // Author: Wanghu
   // Date: 2021/12/17
   Active = ShadingModels.HasAnyShadingModel({ MSM_ClearCoat, MSM_Eye, MSM_Astroite });
   break;

Engine/Source/Runtime/Engine/Private/Materials/MaterialShared.cpp

同时还可以自定义两个CustomData在材质面板上的显示名称:

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"});
   // Feat: Add New Custom Shading Model
   // Author: Wanghu
   // Date: 2021/12/17
   CustomPinNames.Add({ MSM_Astroite, "AS Data 1" });
   return FText::FromString(GetPinNameFromShadingModelField(Material->GetShadingModels(), CustomPinNames, "Custom Data 0"));
case MP_CustomData1:
   CustomPinNames.Add({ MSM_ClearCoat, "Clear Coat Roughness" });
   CustomPinNames.Add({MSM_Eye, "Iris Distance"});
   // Feat: Add New Custom Shading Model
   // Author: Wanghu
   // Date: 2021/12/17
   CustomPinNames.Add({ MSM_Astroite, "AS Data 2" });
   return FText::FromString(GetPinNameFromShadingModelField(Material->GetShadingModels(), CustomPinNames, "Custom Data 1"));

Engine/Source/Runtime/Engine/Private/Materials/HLSLMaterialTranslator.cpp

添加了着色模型之后,需要让引擎翻译HLSL时知道走我们设置的路径,在GetMaterialEnvironment函数中设置一个分支即可。

// Feat: Add New Custom Shading Model
// Author: Wanghu
// Date: 2021/12/17
if (ShadingModels.HasShadingModel(MSM_Astroite)) 
{
   OutEnvironment.SetDefine(TEXT("MATERIAL_SHADINGMODEL_ASTROITE"), TEXT("1"));
   NumSetMaterials++;
}

Engine/Source/Editor/PixelInspector/Private/PixelInspectorDetailsCustomization.cpp

FPixelInspectorDetailsCustomization方法中可以定制材质部分可以隐藏哪些部分:

case MSM_Unlit:
{
   DetailBuilder.HideProperty(SubSurfaceColorProp);
   DetailBuilder.HideProperty(SubSurfaceProfileProp);
   DetailBuilder.HideProperty(OpacityProp);
   DetailBuilder.HideProperty(ClearCoatProp);
   DetailBuilder.HideProperty(ClearCoatRoughnessProp);
   DetailBuilder.HideProperty(WorldNormalProp);
   DetailBuilder.HideProperty(BackLitProp);
   DetailBuilder.HideProperty(ClothProp);
   DetailBuilder.HideProperty(EyeTangentProp);
   DetailBuilder.HideProperty(IrisMaskProp);
   DetailBuilder.HideProperty(IrisDistanceProp);
}

Engine/Source/Editor/PixelInspector/Private/PixelInspectorResult.h

Inspector的序列化部分

#define PIXEL_INSPECTOR_SHADINGMODELID_UNLIT 0
#define PIXEL_INSPECTOR_SHADINGMODELID_DEFAULT_LIT 1
#define PIXEL_INSPECTOR_SHADINGMODELID_SUBSURFACE 2
#define PIXEL_INSPECTOR_SHADINGMODELID_PREINTEGRATED_SKIN 3
#define PIXEL_INSPECTOR_SHADINGMODELID_CLEAR_COAT 4
#define PIXEL_INSPECTOR_SHADINGMODELID_SUBSURFACE_PROFILE 5
#define PIXEL_INSPECTOR_SHADINGMODELID_TWOSIDED_FOLIAGE 6
#define PIXEL_INSPECTOR_SHADINGMODELID_HAIR 7
#define PIXEL_INSPECTOR_SHADINGMODELID_CLOTH 8
#define PIXEL_INSPECTOR_SHADINGMODELID_EYE 9
#define PIXEL_INSPECTOR_SHADINGMODELID_SINGLELAYERWATER 10
#define PIXEL_INSPECTOR_SHADINGMODELID_THIN_TRANSLUCENT 11
// Feat: Add New Custom Shading Model
// Author: Wanghu
// Date: 2021/12/17
#define PIXEL_INSPECTOR_SHADINGMODELID_ASTROITE 12
#define PIXEL_INSPECTOR_SHADINGMODELID_MASK 0xF

Engine/Source/Editor/PixelInspector/Private/PixelInspectorResult.cpp

EMaterialShadingModel PixelInspectorResult::DecodeShadingModel(float InPackedChannel)
{
   int32 ShadingModelId = ((uint32)FMath::RoundToInt(InPackedChannel * (float)0xFF)) & PIXEL_INSPECTOR_SHADINGMODELID_MASK;
   switch (ShadingModelId)
   {
   case PIXEL_INSPECTOR_SHADINGMODELID_UNLIT:
      return EMaterialShadingModel::MSM_Unlit;
   case PIXEL_INSPECTOR_SHADINGMODELID_DEFAULT_LIT:
      return EMaterialShadingModel::MSM_DefaultLit;
   case PIXEL_INSPECTOR_SHADINGMODELID_SUBSURFACE:
      return EMaterialShadingModel::MSM_Subsurface;
   case PIXEL_INSPECTOR_SHADINGMODELID_PREINTEGRATED_SKIN:
      return EMaterialShadingModel::MSM_PreintegratedSkin;
   case PIXEL_INSPECTOR_SHADINGMODELID_CLEAR_COAT:
      return EMaterialShadingModel::MSM_ClearCoat;
   case PIXEL_INSPECTOR_SHADINGMODELID_SUBSURFACE_PROFILE:
      return EMaterialShadingModel::MSM_SubsurfaceProfile;
   case PIXEL_INSPECTOR_SHADINGMODELID_TWOSIDED_FOLIAGE:
      return EMaterialShadingModel::MSM_TwoSidedFoliage;
   case PIXEL_INSPECTOR_SHADINGMODELID_HAIR:
      return EMaterialShadingModel::MSM_Hair;
   case PIXEL_INSPECTOR_SHADINGMODELID_CLOTH:
      return EMaterialShadingModel::MSM_Cloth;
   case PIXEL_INSPECTOR_SHADINGMODELID_EYE:
      return EMaterialShadingModel::MSM_Eye;
   case PIXEL_INSPECTOR_SHADINGMODELID_SINGLELAYERWATER:
      return EMaterialShadingModel::MSM_SingleLayerWater;
   case PIXEL_INSPECTOR_SHADINGMODELID_THIN_TRANSLUCENT:
      return EMaterialShadingModel::MSM_ThinTranslucent;
   case PIXEL_INSPECTOR_SHADINGMODELID_ASTROITE:
      return EMaterialShadingModel::MSM_Astroite;
   };
   return EMaterialShadingModel::MSM_DefaultLit;
}

Shader部分

C++部分涉及的文件较多,主要在实现面板和引擎内的各种细节,Shader部分才是我们需要主要关注的。

Engine/Shaders/Private/ShadingCommon.ush

这里在HLSL层面定义我们的着色模型,注意和之前在CPP中的顺序需要一致,必要时修改一下NUM的顺序。从注释上看,Unreal似乎只支持16个着色模型,算一算快用完了。此处下方可以为自定义的着色模型设置一个颜色,以方便调试。

// SHADINGMODELID_* occupy the 4 low bits of an 8bit channel and SKIP_* occupy the 4 high bits
#define SHADINGMODELID_UNLIT            0
#define SHADINGMODELID_DEFAULT_LIT       1
#define SHADINGMODELID_SUBSURFACE        2
#define SHADINGMODELID_PREINTEGRATED_SKIN  3
#define SHADINGMODELID_CLEAR_COAT        4
#define SHADINGMODELID_SUBSURFACE_PROFILE  5
#define SHADINGMODELID_TWOSIDED_FOLIAGE       6
#define SHADINGMODELID_HAIR                7
#define SHADINGMODELID_CLOTH            8
#define SHADINGMODELID_EYE             9
#define SHADINGMODELID_SINGLELAYERWATER       10
#define SHADINGMODELID_THIN_TRANSLUCENT       11
#define SHADINGMODELID_ASTROITE             12
#define SHADINGMODELID_NUM             13
#define SHADINGMODELID_MASK                0xF       // 4 bits reserved for ShadingModelID     
// for debugging and to visualize
float3 GetShadingModelColor(uint ShadingModelID)
{
   // TODO: PS4 doesn't optimize out correctly the switch(), so it thinks it needs all the Samplers even if they get compiled out
   // This will get fixed after launch per Sony...
#if PS4_PROFILE
       if (ShadingModelID == SHADINGMODELID_UNLIT) return float3(0.1f, 0.1f, 0.2f); // Dark Blue
   else if (ShadingModelID == SHADINGMODELID_DEFAULT_LIT) return float3(0.1f, 1.0f, 0.1f); // Green
   else if (ShadingModelID == SHADINGMODELID_SUBSURFACE) return float3(1.0f, 0.1f, 0.1f); // Red
   else if (ShadingModelID == SHADINGMODELID_PREINTEGRATED_SKIN) return float3(0.6f, 0.4f, 0.1f); // Brown
   else if (ShadingModelID == SHADINGMODELID_CLEAR_COAT) return float3(0.1f, 0.4f, 0.4f); 
   else if (ShadingModelID == SHADINGMODELID_SUBSURFACE_PROFILE) return float3(0.2f, 0.6f, 0.5f); // Cyan
   else if (ShadingModelID == SHADINGMODELID_TWOSIDED_FOLIAGE) return float3(0.2f, 0.2f, 0.8f); // Blue
   else if (ShadingModelID == SHADINGMODELID_HAIR) return float3(0.6f, 0.1f, 0.5f);
   else if (ShadingModelID == SHADINGMODELID_CLOTH) return float3(0.7f, 1.0f, 1.0f); 
   else if (ShadingModelID == SHADINGMODELID_EYE) return float3(0.3f, 1.0f, 1.0f); 
   else if (ShadingModelID == SHADINGMODELID_SINGLELAYERWATER) return float3(0.5f, 0.5f, 1.0f);
   else if (ShadingModelID == SHADINGMODELID_THIN_TRANSLUCENT) return float3(1.0f, 0.8f, 0.3f);
   else if (ShadingModelID == SHADINGMODELID_Astroite) return float3(0.49f, 0.73f, 0.91f);
   else return float3(1.0f, 1.0f, 1.0f); // White
#else
   switch(ShadingModelID)
   {
      case SHADINGMODELID_UNLIT: return float3(0.1f, 0.1f, 0.2f); // Dark Blue
      case SHADINGMODELID_DEFAULT_LIT: return float3(0.1f, 1.0f, 0.1f); // Green
      case SHADINGMODELID_SUBSURFACE: return float3(1.0f, 0.1f, 0.1f); // Red
      case SHADINGMODELID_PREINTEGRATED_SKIN: return float3(0.6f, 0.4f, 0.1f); // Brown
      case SHADINGMODELID_CLEAR_COAT: return float3(0.1f, 0.4f, 0.4f); // Brown
      case SHADINGMODELID_SUBSURFACE_PROFILE: return float3(0.2f, 0.6f, 0.5f); // Cyan
      case SHADINGMODELID_TWOSIDED_FOLIAGE: return float3(0.2f, 0.2f, 0.8f); // Cyan
      case SHADINGMODELID_HAIR: return float3(0.6f, 0.1f, 0.5f);
      case SHADINGMODELID_CLOTH: return float3(0.7f, 1.0f, 1.0f);
      case SHADINGMODELID_EYE: return float3(0.3f, 1.0f, 1.0f);
      case SHADINGMODELID_SINGLELAYERWATER: return float3(0.5f, 0.5f, 1.0f);
      case SHADINGMODELID_THIN_TRANSLUCENT: return float3(1.0f, 0.8f, 0.3f);
      case SHADINGMODELID_ASTROITE: return float3(0.49f, 0.73f, 0.91f);
      default: return float3(1.0f, 1.0f, 1.0f); // White
   }
#endif
}

Engine/Shaders/Private/Definitions.usf

这里为全局定义我们的着色模型。

// Feat: Add New Custom Shading Model
// Author: Wanghu
// Date: 2021/12/20
#ifndef MATERIAL_SHADINGMODEL_ASTROITE
#define MATERIAL_SHADINGMODEL_ASTROITE             0
#endif

Engine/Shaders/Private/BasePassCommon.ush

这里将我们的着色模型需要的自定义参数加入Gbuffer输出。

// Only some shader models actually need custom data.
// Feat: Add New Custom Shading Model
// Author: Wanghu
// Date: 2021/12/20
#define WRITES_CUSTOMDATA_TO_GBUFFER      (USES_GBUFFER && (MATERIAL_SHADINGMODEL_SUBSURFACE || MATERIAL_SHADINGMODEL_PREINTEGRATED_SKIN || MATERIAL_SHADINGMODEL_SUBSURFACE_PROFILE || MATERIAL_SHADINGMODEL_CLEAR_COAT || MATERIAL_SHADINGMODEL_TWOSIDED_FOLIAGE || MATERIAL_SHADINGMODEL_HAIR || MATERIAL_SHADINGMODEL_CLOTH || MATERIAL_SHADINGMODEL_EYE || MATERIAL_SHADINGMODEL_ASTROITE))

Engine/Shaders/Private/DeferredShadingCommon.ush

这里可以设置是否使用Subsurface等,我们先开启CustomData的写入。

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
      || ShadingModelID == SHADINGMODELID_ASTROITE;
}

Engine/Shaders/Private/TiledDeferredLightShaders.usf

由于UE支持对着色模型混合,我们的材质模型需要开启这一功能的话,也是需要做这一步的。

#if USE_PASS_PER_SHADING_MODEL
      EXECUTE_SHADING_LOOPS_SINGLE_SM(SHADINGMODELID_DEFAULT_LIT, PixelShadingModelID, CompositedLighting, PixelPos, NumLightsAffectingTile, NumSimpleLightsAffectingTile, CameraVector, WorldPosition);
      EXECUTE_SHADING_LOOPS_SINGLE_SM(SHADINGMODELID_SUBSURFACE, PixelShadingModelID, CompositedLighting, PixelPos, NumLightsAffectingTile, NumSimpleLightsAffectingTile, CameraVector, WorldPosition);
      EXECUTE_SHADING_LOOPS_SINGLE_SM(SHADINGMODELID_PREINTEGRATED_SKIN, PixelShadingModelID, CompositedLighting, PixelPos, NumLightsAffectingTile, NumSimpleLightsAffectingTile, CameraVector, WorldPosition);
      EXECUTE_SHADING_LOOPS_SINGLE_SM(SHADINGMODELID_CLEAR_COAT, PixelShadingModelID, CompositedLighting, PixelPos, NumLightsAffectingTile, NumSimpleLightsAffectingTile, CameraVector, WorldPosition);
      EXECUTE_SHADING_LOOPS_SINGLE_SM(SHADINGMODELID_SUBSURFACE_PROFILE, PixelShadingModelID, CompositedLighting, PixelPos, NumLightsAffectingTile, NumSimpleLightsAffectingTile, CameraVector, WorldPosition);
      EXECUTE_SHADING_LOOPS_SINGLE_SM(SHADINGMODELID_TWOSIDED_FOLIAGE, PixelShadingModelID, CompositedLighting, PixelPos, NumLightsAffectingTile, NumSimpleLightsAffectingTile, CameraVector, WorldPosition);
      EXECUTE_SHADING_LOOPS_SINGLE_SM(SHADINGMODELID_HAIR, PixelShadingModelID, CompositedLighting, PixelPos, NumLightsAffectingTile, NumSimpleLightsAffectingTile, CameraVector, WorldPosition);
      EXECUTE_SHADING_LOOPS_SINGLE_SM(SHADINGMODELID_CLOTH, PixelShadingModelID, CompositedLighting, PixelPos, NumLightsAffectingTile, NumSimpleLightsAffectingTile, CameraVector, WorldPosition);
      EXECUTE_SHADING_LOOPS_SINGLE_SM(SHADINGMODELID_EYE, PixelShadingModelID, CompositedLighting, PixelPos, NumLightsAffectingTile, NumSimpleLightsAffectingTile, CameraVector, WorldPosition);
      EXECUTE_SHADING_LOOPS_SINGLE_SM(SHADINGMODELID_SINGLELAYERWATER, PixelShadingModelID, CompositedLighting, PixelPos, NumLightsAffectingTile, NumSimpleLightsAffectingTile, CameraVector, WorldPosition);
      EXECUTE_SHADING_LOOPS_SINGLE_SM(SHADINGMODELID_ASTROITE, PixelShadingModelID, CompositedLighting, PixelPos, NumLightsAffectingTile, NumSimpleLightsAffectingTile, CameraVector, WorldPosition);
      // SHADINGMODELID_THIN_TRANSLUCENT - skipping because it can not be opaque
#else // !USE_PASS_PER_SHADING_MODEL
      ExecuteShadingLoops(CompositedLighting, ScreenSpaceData, NumLightsAffectingTile, NumSimpleLightsAffectingTile, CameraVector, WorldPosition);
#endif // USE_PASS_PER_SHADING_MODEL

Engine/Shaders/Private/ClusteredDeferredShadingPixelShader.usf

在ClusteredShadingPixelShader循环获取光照参数。

#if USE_PASS_PER_SHADING_MODEL

   GET_LIGHT_GRID_LOCAL_LIGHTING_SINGLE_SM(SHADINGMODELID_DEFAULT_LIT, PixelShadingModelID, CompositedLighting, ScreenUV, CulledLightGridData, Dither, FirstNonSimpleLightIndex);
   GET_LIGHT_GRID_LOCAL_LIGHTING_SINGLE_SM(SHADINGMODELID_SUBSURFACE, PixelShadingModelID, CompositedLighting, ScreenUV, CulledLightGridData, Dither, FirstNonSimpleLightIndex);
   GET_LIGHT_GRID_LOCAL_LIGHTING_SINGLE_SM(SHADINGMODELID_PREINTEGRATED_SKIN, PixelShadingModelID, CompositedLighting, ScreenUV, CulledLightGridData, Dither, FirstNonSimpleLightIndex);
   GET_LIGHT_GRID_LOCAL_LIGHTING_SINGLE_SM(SHADINGMODELID_CLEAR_COAT, PixelShadingModelID, CompositedLighting, ScreenUV, CulledLightGridData, Dither, FirstNonSimpleLightIndex);
   GET_LIGHT_GRID_LOCAL_LIGHTING_SINGLE_SM(SHADINGMODELID_SUBSURFACE_PROFILE, PixelShadingModelID, CompositedLighting, ScreenUV, CulledLightGridData, Dither, FirstNonSimpleLightIndex);
   GET_LIGHT_GRID_LOCAL_LIGHTING_SINGLE_SM(SHADINGMODELID_TWOSIDED_FOLIAGE, PixelShadingModelID, CompositedLighting, ScreenUV, CulledLightGridData, Dither, FirstNonSimpleLightIndex);
   GET_LIGHT_GRID_LOCAL_LIGHTING_SINGLE_SM(SHADINGMODELID_HAIR, PixelShadingModelID, CompositedLighting, ScreenUV, CulledLightGridData, Dither, FirstNonSimpleLightIndex);
   GET_LIGHT_GRID_LOCAL_LIGHTING_SINGLE_SM(SHADINGMODELID_CLOTH, PixelShadingModelID, CompositedLighting, ScreenUV, CulledLightGridData, Dither, FirstNonSimpleLightIndex);
   GET_LIGHT_GRID_LOCAL_LIGHTING_SINGLE_SM(SHADINGMODELID_EYE, PixelShadingModelID, CompositedLighting, ScreenUV, CulledLightGridData, Dither, FirstNonSimpleLightIndex);
   GET_LIGHT_GRID_LOCAL_LIGHTING_SINGLE_SM(SHADINGMODELID_SINGLELAYERWATER, PixelShadingModelID, CompositedLighting, ScreenUV, CulledLightGridData, Dither, FirstNonSimpleLightIndex);
   GET_LIGHT_GRID_LOCAL_LIGHTING_SINGLE_SM(SHADINGMODELID_ASTROITE, PixelShadingModelID, CompositedLighting, ScreenUV, CulledLightGridData, Dither, FirstNonSimpleLightIndex);
   // SHADINGMODELID_THIN_TRANSLUCENT - skipping because it can not be opaque
#else // !USE_PASS_PER_SHADING_MODEL

Engine/Shaders/Private/ShadingModelsMaterial.ush

对于需要CusotmData的着色模型,可以在SetGBufferForShadingModel函数中处理Gbuffer中的数据。

    // Feat: Add New Custom Shading Model
   // Author: Wanghu
   // Date: 2021/12/20
#if MATERIAL_SHADINGMODEL_ASTROITE
   else if (ShadingModel == SHADINGMODELID_ASTROITE)
   {
      GBuffer.CustomData.rgb = float3(0.49f, 0.73f, 0.91f);
      GBuffer.CustomData.a = 0.5f;      
   }
#endif

Engine/Shaders/Private/ShadingModels.ush

这里是实现着色模型计算的地方,所有的BxDF都在IntegrateBxDF中调用。参考DefaultLit的写法,我们先简单实现一下ASBxDF。

FDirectLighting IntegrateBxDF( FGBufferData GBuffer, half3 N, half3 V, half3 L, float Falloff, float NoL, FAreaLight AreaLight, FShadowTerms Shadow )
{
   switch( GBuffer.ShadingModelID )
   {
      case SHADINGMODELID_DEFAULT_LIT:
      case SHADINGMODELID_SINGLELAYERWATER:
      case SHADINGMODELID_THIN_TRANSLUCENT:
         return DefaultLitBxDF( GBuffer, N, V, L, Falloff, NoL, AreaLight, Shadow );
      case SHADINGMODELID_SUBSURFACE:
         return SubsurfaceBxDF( GBuffer, N, V, L, Falloff, NoL, AreaLight, Shadow );
      case SHADINGMODELID_PREINTEGRATED_SKIN:
         return PreintegratedSkinBxDF( GBuffer, N, V, L, Falloff, NoL, AreaLight, Shadow );
      case SHADINGMODELID_CLEAR_COAT:
         return ClearCoatBxDF( GBuffer, N, V, L, Falloff, NoL, AreaLight, Shadow );
      case SHADINGMODELID_SUBSURFACE_PROFILE:
         return SubsurfaceProfileBxDF( GBuffer, N, V, L, Falloff, NoL, AreaLight, Shadow );
      case SHADINGMODELID_TWOSIDED_FOLIAGE:
         return TwoSidedBxDF( GBuffer, N, V, L, Falloff, NoL, AreaLight, Shadow );
      case SHADINGMODELID_HAIR:
         return HairBxDF( GBuffer, N, V, L, Falloff, NoL, AreaLight, Shadow );
      case SHADINGMODELID_CLOTH:
         return ClothBxDF( GBuffer, N, V, L, Falloff, NoL, AreaLight, Shadow );
      case SHADINGMODELID_EYE:
         return EyeBxDF( GBuffer, N, V, L, Falloff, NoL, AreaLight, Shadow );
      case SHADINGMODELID_ASTROITE:
         return ASBxDF(GBuffer, N, V, L, Falloff, NoL, AreaLight, Shadow);
      default:
         return (FDirectLighting)0;
   }
}

// 着色计算的核心
FDirectLighting ASBxDF(FGBufferData GBuffer, half3 N, half3 V, half3 L, float Falloff, float NoL, FAreaLight AreaLight, FShadowTerms Shadow)
{
   BxDFContext Context;
   ...//省略着色计算
}

至此,一个完整的着色模型已经可以跑起来了,按照步骤点击编译,然后就可以起来活动一下筋骨了。

img

参考

贡献者: Astroite