BlueRose
文章97
标签28
分类7
UE4通过修改FMeshBatch参数实现反向剔除

UE4通过修改FMeshBatch参数实现反向剔除

之前我有写过两篇通过自定义场景代理来实现描边的文章:
https://zhuanlan.zhihu.com/p/69139579
https://zhuanlan.zhihu.com/p/69156465

当时有一个问题没解决,就是不知道如何将材质设置为反向剔除,因为UE4只有双面渲染选项,毕竟只有卡通渲染等一些非真实渲染才需要这种功能。但经过MeshDraw框架的学习,我发现只需要在场景代理中设置一下FMeshBatch剔除属性即可,而且这个方法没有任何副作用。其他代码可以参考我的插画。效果如图(没有使用深度偏移)


StaticMesh

StaticMesh的改法非常简单,只需要在绘制前加上一句MeshBatch.ReverseCulling = !MeshBatch.ReverseCulling;即可。

FMeshBatch MeshBatch;

if (GetShadowMeshElement(LODIndex, BatchIndex, PrimitiveDPG, MeshBatch, bAllSectionsUseDitheredLODTransition))
{
    bUseUnifiedMeshForShadow = bAllSectionsCastShadow;

    MeshBatch.CastShadow = bUseUnifiedMeshForShadow;
    MeshBatch.bUseForDepthPass = bUseUnifiedMeshForDepth;
    MeshBatch.bUseAsOccluder = bUseUnifiedMeshForDepth;
    MeshBatch.bUseForMaterial = false;

    PDI->DrawMesh(MeshBatch, ScreenSize);

    const FLODInfo& ProxyLODInfo = LODs[LODIndex];
    UMaterialInterface* MaterialInterface = ProxyLODInfo.Sections[0].Material;

    const UOutlineStaticMeshComponent* OutlineStaticMeshComponent = dynamic_cast<const UOutlineStaticMeshComponent *>(ComponentPtr);
    if (MaterialInterface == OutlineStaticMeshComponent->OutlinePassMaterial)
    {
        continue;
    }
    if (OutlineStaticMeshComponent->NeedOutlinePass) {
        if (OutlineStaticMeshComponent->OutlinePassMaterial == nullptr) {
            continue;
        }
        MeshBatch.MaterialRenderProxy = OutlineStaticMeshComponent->OutlinePassMaterial->GetRenderProxy();
        MeshBatch.ReverseCulling = !MeshBatch.ReverseCulling;
        PDI->DrawMesh(MeshBatch, FLT_MAX);
    }
}

SkeletalMesh

SkeletalMesh会比较麻烦因为一些关键函数是private、protect类型的或是类型没有声明在h中。

  • 重写FSkeletalMeshSceneProxy::GetDynamicElementsSection()
  • 实现CreateBaseMeshBatch(),其中BatchElement.VertexFactoryUserData需要GPUSkinCacheEntry,这就需要一些小技巧了。
  • 你需要使用继承FSkeletalMeshObjectGPUSkin,再编写Public函数来取得SkinCacheEntry。
  • 创建FGPUSkinCacheEntry(从源码里复制即可,再把一些不可访问的函数略加去除即可,只需要保证类内的变量内存结构与原版的相同即可)

具体可以参考:https://gist.github.com/blueroseslol/5ff2c26fc3b77305a88b2378772527ac

额外思考

其实可以看到FMeshBatch还是指定顶点工厂,那是不是在指定了自定义顶点工厂,再修改BasePassVertexShader.usf与BasePassPixelShader.usf就可以实现添加顶点数据的功能呢?

不过因为本人为非游戏及影视的UE4业余爱好者,时间与心力不足,只能转行以后再探究了。