![35baad0797dad656378de0d49a27217b.png](https://img-blog.csdnimg.cn/img_convert/35baad0797dad656378de0d49a27217b.png)
之前的2篇介绍UE4渲染框架文章主要介绍了UE4中主线程和渲染线程的同步以及主线程中的数据如何同步到渲染线程,在UE4中为了避免主线程与渲染线程的race condition,会为渲染线程准备一份数据,比如
Mage Anti:UE4渲染框架解析之数据更新zhuanlan.zhihu.com![1efc315a2699217036c23f5fe5e3dbbe.png](https://img-blog.csdnimg.cn/img_convert/1efc315a2699217036c23f5fe5e3dbbe.png)
这篇文章中提到的Primitives,其实就是由渲染线程维护的数据结构,也是渲染数据的来源,既然获得了场景中所有渲染的数据了,接下来就可以对这些数据进行预处理了,也就是这篇文章的主题InitViews。当然,这篇文章讲的还是Mobile渲染框架。
在InitViews函数中最重要的函数就是ComputeViewVisibility,它主要负责对需要渲染的数据进行剔除、筛选等操作:
![c3083381aa59d40cc037f677d65ac6f8.png](https://img-blog.csdnimg.cn/img_convert/c3083381aa59d40cc037f677d65ac6f8.png)
进入到ComputeViewVisibility函数中,首先会初始化很多标记Primitive属性的变量,比如:
![1b708ab565c75ba72337132017afd4f5.png](https://img-blog.csdnimg.cn/img_convert/1b708ab565c75ba72337132017afd4f5.png)
接着进行LightInfo相关的初始化操作,接下来比较重要的是视锥剔除,视锥剔除的作用是剔除位于摄像机的视锥体外面的物体,这些物体对于摄像机是不可见的,比如下图中的灰色的物体都是被剔除掉的。
![167ca817c7b51234031426bc328a08db.png](https://img-blog.csdnimg.cn/img_convert/167ca817c7b51234031426bc328a08db.png)
在UE4中为了利用多线程加快视锥剔除的效率,使用了ParallalFor循环,实际上还是使用了TaskGraph的工作线程来完成任务,这里我们主要关心对于当前的一个Primitive是怎么做视锥剔除的。首先根据物体的设置信息调整它的MaxDrawDistance和MinDrawDistanceSq,然后判断是否被裁剪掉,判断条件如下图所示,可以看到主要是判断与相机的距离以及物体的包围盒是否与视锥体相交。
![4d882b8158b2aa64229ad49a1a3f2a08.png](https://img-blog.csdnimg.cn/img_convert/4d882b8158b2aa64229ad49a1a3f2a08.png)
如果没有被裁剪掉那么就需要看看物体与相机的距离是否大于物体的最大绘制距离MaxDrawDistance,如果大于并且使用了DistanceCullFade的话就记FadingBits为1;如果上面的条件都不满足的话就表示物体是可见的,在这种情况下也需要检测是否为Fading。检查完毕之后需要将结果分别保存到View.PrimitiveVisibilityMap和View.PotentiallyFadingPrimitiveMap中,至此视锥剔除就完成了。完成视锥剔除之后,处理Fading的Primitive的信息,然后根据是否有Hidden Primitives和Show Only Primitives设置PrimitiveVisibilityMap信息。
在处理完了视锥剔除之后,就需要做遮挡剔除了,遮挡剔除的作用是剔除掉那些被前面的物体遮挡住的物体。
![6609e1d5b228edded0e36b2dbed3fadc.png](https://img-blog.csdnimg.cn/img_convert/6609e1d5b228edded0e36b2dbed3fadc.png)
UE4中的遮挡剔除使用的是软光栅化的算法,里面使用到的算法比较复杂一些,之后会专门写一篇文章分析遮挡剔除相关的内容。
在处理玩视锥剔除和遮挡剔除之后,会更新可见的需要更新的静态物体,主要是静态物体改变了位置,方向之类的,重新缓存MeshDrawCommand。这一步结束之后就需要计算和标记Relevance了。
ComputeRelevance函数的主要任务就是根据PrimitiveViewRelevance将物体分类到不同组中,比如有的物体是透明物体,有的是静态物体、有的是动态物体等。
MarkRelevant函数的主要功能是根据静态物体的属性将其MeshDrawCommand分发到不同的MeshPass中,由于静态物体在加入到场景中的时候相应的MeshDrawCommand已经创建并缓存好了,所以只需要从场景的CachedMeshDrawCommandStateBuckets结构体中取出数据即可,如果没有缓存的话则加入到DynamicBuildRequests中,之后创建MeshDrawCommand。
![404d759a5c72e71e18b03fc1c173ff4e.png](https://img-blog.csdnimg.cn/img_convert/404d759a5c72e71e18b03fc1c173ff4e.png)
上面的过程也是通过TaskGraph的工作线程多线程执行的,执行完成之后,渲染线程拷贝生成的命令到ViewCommand.MeshCommands。至此静态物体的MeshDrawCommand创建完成。
下一节中主要介绍一下如何收集动态物体的数据并创建MeshDrawCommand。