UE4移动端卡通渲染 Posted on Jul 6, 2019
前期准备 最近学习UE4,尝试改UE4引擎,做一个卡通渲染的shading model。使用的UE4版本是4.19。
首先需要有源码版的UE4引擎,根据这篇UE4官方文档 ,去Github把源码pull下来。然后根据这篇官方文档 从源码构建引擎。我这里在vs上踩了坑,除了要装c++桌面开发的unreal相关外,还要在.NET桌面开发中勾上.NET Framework 4.6.2。以及可以根据这篇博文 做一些修改,装一些实用工具,其中还有六篇教程,对新手入门改UE4源码非常有帮助。
接下来主要参考这篇知乎的文章 ,实际上他也是根据上面Medium的教程做的。但是这篇教程是针对PC端的,PC端和Mobile使用的是完全不一样的渲染管线,这里新做一个shading model参考一下他们的做法,然后自己研究了一下改mobile。
添加新的shading model 在以下文件中分别做如下修改
EngineTypes.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 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_Toon UMETA(DisplayName = "Toon"), MSM_MAX, };
MaterialShared.cpp
1 2 3 4 5 6 7 8 switch(GetShadingModel()) { ... case MSM_Eye: OutEnvironment.SetDefine(TEXT("MATERIAL_SHADINGMODEL_EYE"), TEXT("1")); break; case MSM_Toon: OutEnvironment.SetDefine(TEXT("MATERIAL_SHADINGMODEL_TOON"), TEXT("1")); break; default: ... };
DeferredShadingCommon.ush
1 2 3 4 5 6 7 8 9 10 11 12 13 #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_TOON 10 #define SHADINGMODELID_NUM 11 #define SHADINGMODELID_MASK 0xF
这样就可以使用自己的shading model了
接口名称修改 在Material.cpp中想要的接口处添加自己的shading model,如想要customdata0接口,这样添加这个接口就被激活了
1 2 case MP_CustomData0: Active = ShadingModel == MSM_ClearCoat || ShadingModel == MSM_Hair || ShadingModel == MSM_Cloth || ShadingModel == MSM_Eye || ShadingModel == MSM_Toon;
然后修改接口的名字,在MaterialGragh.cpp中,比如修改metallic接口名,找到这个函数,改成这样
1 2 3 4 5 6 7 8 9 10 FText UMaterialGraph::GetMetallicPinName() const { switch (Material->GetShadingModel()) { case MSM_Toon: return LOCTEXT("ShadowStrength", "Shadow Strength"); default: return Material->GetShadingModel() == MSM_Hair ? LOCTEXT("Scatter", "Scatter") : LOCTEXT("Metallic", "Metallic"); } }
想改specular或roughness的话,由于没有这个函数,需要自己添加,添加后在此处调用函数
1 2 3 4 MaterialInputs.Add( FMaterialInputInfo( GetBaseColorPinName(), MP_BaseColor, LOCTEXT( "BaseColorToolTip", "Defines the overall color of the Material. Each channel is automatically clamped between 0 and 1" ) ) ); MaterialInputs.Add( FMaterialInputInfo( GetMetallicPinName(), MP_Metallic, LOCTEXT( "MetallicToolTip", "Controls how \"metal-like\" your surface looks like") ) ); MaterialInputs.Add( FMaterialInputInfo( GetSpecularPinName(), MP_Specular, LOCTEXT("SpecularToolTip", "Used to scale the current amount of specularity on non-metallic surfaces and is a value between 0 and 1, default at 0.5") ) ); MaterialInputs.Add( FMaterialInputInfo( GetRoughnessPinName(), MP_Roughness, LOCTEXT( "RoughnessToolTip", "Controls how rough the Material is. Roughness of 0 (smooth) is a mirror reflection and 1 (rough) is completely matte or diffuse" ) ) );
另外在MaterialGragh.h中需要添加新函数的声明,这样接口就变成了这样
贴图采样 mobile使用的就是前向渲染,主要实现基本在MobileBasePassPixelShader.usf中,用宏MATERIAL_SHADINGMODEL_TOON控制toon要进行的计算和不需要进行的,关键的几个数据N、L、V、Shadow原本代码里就已经算过了,可以直接用,关键在于如何自己采样贴图,想办法获取到从接口输入的贴图。
先顺着basecolor的来源,发现来源于PixelMaterialInputs中的数据
1 2 3 4 half3 GetMaterialBaseColorRaw(FPixelMaterialInputs PixelMaterialInputs) { return PixelMaterialInputs.BaseColor; }
然后发现PixelMaterialInputs的定义是这样的
1 2 3 4 struct FPixelMaterialInputs { %s };
%s处是根据用户的蓝图填充进去的,于是自己连了一个材质,看了一下生成的hlsl,找到一处关键代码
1 2 MaterialFloat4 Local0 = ProcessMaterialColorTextureLookup(Texture2DSampleBias(Material.Texture2D_0,Material.Texture2D_0Sampler,Parameters.TexCoords[0].xy,View.MaterialTextureMipBias)); PixelMaterialInputs.BaseColor = Local0.rgb;
于是在MobileBasePassPixelShader.usf中尝试把Material.Texture2D_0当贴图用,结果真的可以直接用,后面的编号应该是内存中贴图的顺序,先被接入贴图的节点中的贴图排前面,比如emissive节点先被接入一张贴图,那么它就是_0,后面接入新的贴图节点只是给原来的_0贴图重新赋值。所以使用这个shading model的话要注意贴图的连入顺序。应该是有个地方有绑定之类的操作,但这样改起来非常复杂,可以直接给引擎组的人提需求了……
最后就可以使用了,这是一个使用ramp图做暗部映射,另外添加一个边缘光的卡通shading model