使用C++解决UE4的SkeletalMesh多Pass渲染问题

使用C++解决UE4的SkeletalMesh多Pass渲染问题

零、前言

上一篇关于UE4卡通渲染的文章中,曾提到增加一个PoseableMeshComponent当作多Pass渲染,这么做会有一个问题——模型动起来后会穿帮,本来我解决这个问题的想法很简单:在Tick函数中去更新PoseableMeshComponent,但是实际操作后会产生非常明显的“拖影”——PoseableMesh始终与SkeletalMesh合不上拍。之后我又尝试将PoseableMeshComponent替换成SkeletalMeshComponent(即一个Actor有两个除材质外完全一样的SkeletalMeshComponent),虽然解决了“拖影”问题,但总觉得这种做法不够王道,于是花费了大概半天时间从C++层面来解决多Pass渲染问题。

一、添加新的属性

这次主要修改的类有:SkinnedMeshComponent和FSkeletalMeshSceneProxy。

首先是SkinnedMeshComponent,我们要添加两个新的属性,方便我们设置第二个Pass的材质:

然后是非常重要的一步!我们要去修改GetUsedMaterials这个函数,修改它的原因是,UE4在合并模型的时候会查询你当前设置的材质是否是“可用的”,如果不去修改这个函数,我们添加的SecondPassMaterial便不会起作用:

二、让我们的属性在渲染线程当中起作用

UE4有一系列XXXProxy类来一一对应逻辑线程当中的SkeletalMeshComponent等组件,这里由于只关心SkeletalMesh,所以只修改FSkeletalMeshSceneProxy的构造函数:

-----------------------------2019.5.20修改-----------------------------

在构造函数之前,我们需要先去在Proxy中定义这两个变量:

--------------------------------修改结束-------------------------------------

三、让模型多绘制一次

最后一件事情就是让模型多绘制一次,换句话说就是将模型被Collector多收集一次,直接调用一次GetDynamicElementsSection函数即可:

四、蓝图以及效果

可以看到只使用了一个SkeletalMeshComponent

------------------------------------2019.7.13修改--------------------------------------

感谢 @kpios 同学的修改,对于多片段的骨骼模型,每一个片段按道理讲都应该有单独的SecondMaterial,以下内容由kpios同学提供:

文章中有两个UMaterialInterface*变量,都改成TArray<UMaterialInterface*>。GetDynamicElementsSection函数那里的判断条件改成if(NeedSecondPass && TheSecondPassMater.Num()>SectionElementInfo.UseMaterialIndex && TheSecondPassMater[SectionElementInfo.UseMaterialIndex])。
SecondInfo.Material = TheSecondPassMaterial;改成SecondInfo.Material = TheSecondPassMater[SectionElementInfo.UseMaterialIndex];
我是研究了下代码的上文,猜测SectionElementInfo.UseMaterialIndex是材质id,结果是能实现多个描边材质的效果,描边材质会对应原本的材质id,暂时没发现有问题。

另外由kpios同学亲身实践,如果模型使用了形变动画,需要做如下处理:

终于能顺利运行了,是变形动画的原因,虽然我是改了变量,但理论上和你的是一样的,如果角色有morph targets的话,描边的材质里面要勾选那个used with morph targets,这样就不会卡死了。

---------------------------------------修改结束------------------------------------------

编辑于 2019-07-13