构建pvs
FStaticLightingSystem::BeginLightmassProcess在lightmass的构建过程中,如果设置了pvs的构建则会一起构建。执行InitiateLightmassProcessor,然后在里面执行LightmassProcessor->InitiateExport
在里面如果选择了生成pvs则会创建FGuid::NewGuid
然后执行Exporter->WriteToChannel(Statistics, DebugMappingGuid);将VisibilityBucketGuids写入scene里面。
然后通过swarm来分布式写入文件Swarm.WriteChannel( Channel, &Scene, sizeof(Scene) );
PrecomputedVisibility体积计算与存储
然后在FLightmassExporter::WriteToChannel里通过WriteVisibilityData写入可见数据。
在FLightmassExporter::WriteVisibilityData里会拿所有的APrecomputedVisibilityVolume然后通过Volume->GetComponentsBoundingBox拿到这个
APrecomputedVisibilityVolume放置的范围。
并且如果有设置APrecomputedVisibilityOverrideVolume则会拿到希望覆盖的区域的范围并写入文件。
限制:
然后执行ApplyPrecomputedVisibility,这里会建立CombinedPrecomputedVisibilityCells,如果格子的x和y范围都在10000以内则开始遍历获取可见对象。
对cell范围内的对象执行SpreadVisibilityCell,取获取其他cell里面的可见对象信息。
这里面的AccumulateVisibility就是会将邻居的可见性与当前单元格的可见性相结合,这样可以减少可见性错误,但代价是剔除效率较低。
然后讲数据压缩为NAME_Zlib模式
运行时执行pvs:
在FDeferredShadingSceneRenderer::InitViews执行ComputeViewVisibility来获取可视信息。
FSceneRenderer::ComputeViewVisibility中执行View.PrecomputedVisibilityData = ViewState->GetPrecomputedVisibilityData(View, Scene);获取可见数据。
计算可见几何体
在FSceneRenderer::ComputeViewVisibility计算出可是对象后,通过执行OcclusionCull来剔除对象。
在SceneVisibility.cpp的OcclusionCull中如果拿到View.PrecomputedVisibilityData的数据说明有pvs的数据。他遍历View.PrimitiveVisibilityMap中的所有几何体数据,如果(View.PrecomputedVisibilityData[VisibilityId.ByteIndex] & VisibilityId.BitMask)也就是pvs的数据和当前的几何对象数据不重合,说明不在可视范围内,则把他隐藏。
获取数据:
在SceneOcclusion.cpp中FSceneViewState::GetPrecomputedVisibilityData是获取具体的视野和场景里面的可见对象列表。
Bucket和Cell:
首先如果开启了pvs则GAllowPrecomputedVisibility会为true
如果有pvs的数据,那么他的数据是通过Bucket和Bucket下的Cell组成的。通过Handler.PrecomputedVisibilityCellBuckets来遍历Bucket以及Bucket下的cell来设置视锥内的显示对象
cell下的视锥范围pvs对象
然后根据视锥内的索引起点来确定bucket的视野偏移索引的xy。让PrecomputedVisibilityBucketIndex平铺为一维数组。然后通过Handler.PrecomputedVisibilityCellBuckets来获取视锥内的可视对象。然后遍历这个bucket下的cell,看每个cell是否在视锥范围内。
如果在范围内则记录到从CachedVisibilityChunk中拿到PrecomputedVisibilityData数据或者从压缩的FCompressedVisibilityChunk里面拿到数据。
解压数据并缓存
CachedVisibilityChunk中自然是之前缓存下来的数据。而FCompressedVisibilityChunk中就要通过FCompression::UncompressMemory然后通过类型为NAME_Zlib的方式解压zlib格式的数据。最终还是存在CachedVisibilityChunk中,然后返回PrecomputedVisibilityData数据出去。