在材质编辑器中添加Toon Shading节点,ShadingModel即切换为SHADINGMODELID_STYLIZED_SHADOW
注意:添加节点后不再受编辑器中的ShadingModel变量控制
Add Toon Shading node in material editor, and ShadingModel property will be replaced as toon shading model.
注意该教程在引擎版本4.26时作成
-
继承UMaterialExpressionCustomOutput
使用虚幻中UMaterialExpressionCustomOutput类型可在代码编译时插入条件编译宏的特性将自定义的ShadingModelId添加进Shader编译流程
插件中重写的GetFunctionName返回的GetToonShading在shader对应的宏为NUM_MATERIAL_OUTPUTS_GETTOONSHADING -
进入引擎Engine/Shader目录修改和添加Shader文件
-
修改ShadingCommon.ush中添加新的ShadingModel宏定义
-
添加宏SHADINGMODELID_STYLIZED_SHADOW,且修改SHADINGMODELID_NUM的数量(注意当前最多支持16个)
#define SHADINGMODELID_STYLIZED_SHADOW 12 #define SHADINGMODELID_NUM 13
-
修改GetShadingModelColor函数,新增SHADINGMODELID_STYLIZED_SHADOW的调试颜色
-
-
修改BasePassCommon.ush与DeferredShadingCommon.ush开启自定义GBuffer的CustomData写入
-
BasePassCommon.ush WRITES_CUSTOMDATA_TO_GBUFFER宏,支持SHADINGMODELID_STYLIZED_SHADOW写入
#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 || SHADINGMODELID_STYLIZED_SHADOW))
-
DeferredShadingCommon.ush 修改HasCustomGBufferData函数,支持SHADINGMODELID_STYLIZED_SHADOW写入
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_STYLIZED_SHADOW; }
-
-
修改BasePassPixelShader.usf中ShadingModel的初始化
#if NUM_MATERIAL_OUTPUTS_GETTOONSHADING uint ShadingModel = SHADINGMODELID_STYLIZED_SHADOW; #else uint ShadingModel = GetMaterialShadingModel(PixelMaterialInputs); #endif
-
修改ShadingModelsMaterial.ush将额外的数据写入GBuffer的CustomData
// 支持 MaterialExpressionCustomOutput 形式 #if NUM_MATERIAL_OUTPUTS_GETTOONSHADING else if (ShadingModel == SHADINGMODELID_STYLIZED_SHADOW) { GBuffer.CustomData.x = saturate( GetToonShading0(MaterialParameters) ); // SpecularRange GBuffer.CustomData.y = saturate( GetToonShading1(MaterialParameters) ); // Offset } // 支持 ShadingModelId 形式 #elif SHADINGMODELID_STYLIZED_SHADOW else if (ShadingModel == SHADINGMODELID_STYLIZED_SHADOW) { GBuffer.CustomData.x = saturate( GetMaterialCustomData0(MaterialParameters) ); // SpecularRange GBuffer.CustomData.y = saturate( GetMaterialCustomData1(MaterialParameters) ); // Offset } #endif
-
修改ShadingModels.ush支持添加的ShadingModel的自定义BxDF函数
IntegrateBxDF函数中添加SHADINGMODELID_STYLIZED_SHADOW的casecase SHADINGMODELID_STYLIZED_SHADOW: return StylizedShadowBxDF(GBuffer, N, V, L, Falloff, NoL, AreaLight, Shadow);
-
修改DeferredLightingCommon.ush自定义光照
修改GetDynamicLightingSplit函数,通过GBuffer.ShadingModelID判断SHADINGMODELID_STYLIZED_SHADOW执行自定义光照逻辑// STYLIZEDSHADOW SHADING if (GBuffer.ShadingModelID == SHADINGMODELID_STYLIZED_SHADOW) { float3 Attenuation = 1; float offset = GBuffer.CustomData.y; float TerminatorRange = saturate(GBuffer.Roughness - 0.5); offset = offset * 2 - 1; BRANCH if (offset >= 1) { Attenuation = 1; } else { float NoL = (dot(N, L) + 1) / 2; float NoLOffset = saturate(NoL + offset); float LightAttenuationOffset = saturate( Shadow.SurfaceShadow + offset); float ToonSurfaceShadow = smoothstep(0.5 - TerminatorRange, 0.5 + TerminatorRange, LightAttenuationOffset); Attenuation = smoothstep(0.5 - TerminatorRange, 0.5 + TerminatorRange, NoLOffset) * ToonSurfaceShadow; } LightAccumulator_AddSplit( LightAccumulator, Lighting.Diffuse, Lighting.Specular, Lighting.Diffuse, LightColor * LightMask * Shadow.SurfaceShadow * Attenuation * 0.25, > bNeedsSeparateSubsurfaceLightAccumulation); } else { LightAccumulator_AddSplit( LightAccumulator, Lighting.Diffuse, Lighting.Specular, Lighting.Diffuse, LightColor * LightMask * Shadow.SurfaceShadow, bNeedsSeparateSubsurfaceLightAccumulation ); }
FMaterialShadingModelField::AddShadingModel 存在check(InShadingModel < MSM_NUM)检查导致没法Hack,导致新增的ShadingModel数量肯定超过MSM_NUM,引发断言导致编辑器crash
-
ToonShader模块
该模块实现了UMaterialExpressionCustomOutput的子类,为运行时模块 -
ToonShaderBootstrap模块
该模块会在引擎启动Shader编译前加载,用以向虚幻引擎Shader文件夹中替换默认Shader文件
ShadersOverride文件夹下存放了shader文件- Default文件用来恢复
- Override用来做替换,新增的Shader文件都需要存放在Toon目录下