简介
渐进网格是一种特殊对象,可用于提高渲染性能。例如,一个具有大量面的大型壳体在屏幕上可能非常小,通常所有面都会独立渲染,无论它们(以及整个壳体)在屏幕上有多小。
渐进网格允许您更改细节级别 (LOD) 并获得原始壳体更合适的版本。例如,它可以降低当前的 LOD,使壳体包含的面数显著减少,并且由于它在屏幕上很小,因此不会注意到任何视觉缺陷。
与其他 LOD 相关技术不同,渐进网格允许实时切换 LOD,从 0(最小可用表示)到最大 LOD(原始壳体表示)的任何 LOD。
从内存使用角度来看,占用的内存可以分为两组:当前 LOD 表示和提供 LOD 之间切换的 LOD 信息列表。
- 第一组的大小取决于当前的 LOD:如果为零,表示非常小,并随着 LOD 的增加而线性增长。
- 第二组的大小对于每个 LOD 都是恒定的,其大小与最大 LOD 表示的内存使用量相当。
ODA 从 22.10 版本开始支持渐进网格的部分加载。在渐进网格部分加载期间,所描述的 LOD 信息列表不存储在 RAM 中,而是保存在文件流中,这显著减少了内存使用。在这种情况下,LOD 切换会变慢,但性能下降可能微不足道。
使用 OdGiProgressiveMesh 进行部分加载
OdGiProgressiveMesh 接口已扩展以支持渐进网格部分加载。它不将 LOD 信息保存在内存中,而是使用客户实现的 OdGiDataExtractor 实例在需要时访问 LOD 数据。
OdGiProgressiveMesh 部分加载方法
对于部分加载,OdGiProgressiveMeshGenerator 具有以下方法:
virtual OdGiProgressiveMeshPtr createPartialProgressiveMeshFrom( OdStreamBuf* pBuff, OdGiDataExtractor* pDataExtractor,
const OdGiProgressiveMeshObjectIdConverter* pConverter = NULL,
OdGiProgressiveMesh::ProgressiveMeshStreamVersion version = OdGiProgressiveMesh::kVersionActual ) const = 0;
此外,OdGiProgressiveMeshEx 具有以下方法:
virtual bool readPartialProgressiveMeshExFrom( OdStreamBuf* pBuff, OdGiDataExtractor* pDataExtractor, const OdGiProgressiveMeshObjectIdConverter* pConverter = NULL,
OdGiProgressiveMesh::ProgressiveMeshStreamVersion version = OdGiProgressiveMesh::kVersionActual ) = 0;
这些方法类似于原始的 createProgressiveMeshFrom 和 readProgressiveMeshExFrom 方法,但它们使用 OdGiDataExtractor 实例而不是将 LOD 信息保存在内存中。OdGiProgressiveMesh 还具有以下几种方法:
-
定义渐进网格是否处于部分模式。virtual bool isInPartialMode() const = 0; -
强制将 LOD 信息加载到内存中并结束部分模式。当重新写入用于在部分模式下加载渐进网格的文件时,这可能会有所帮助;在这种情况下,无法保证提取器和计算的偏移量有效,因为流可能会被更改。virtual void endPartialMode() = 0;
使用 OdGiDataExtractor 进行部分加载
OdGiDataExtractor 类定义了数据提取接口。每个对象可能以不同的方式使用提取器,因此提取器实现无法知道它当前正在处理的确切数据。相反,对象在提取器中注册不同的数据类型,并在需要提取注册数据时通知它。
数据注册使用两个 OdGiDataExtractor 方法,它们注册 dataId 的开始和结束:
virtual bool registerDataBegin( OdUInt8 dataId, OdUInt64 localOffset ) = 0;
virtual bool registerDataEnd( OdUInt8 dataId, OdUInt64 localOffset ) = 0;
在对象可以提取数据之前,它需要使用以下方法开始提取:
virtual bool beginExtraction( OdUInt8 dataId ) = 0;
通常在此方法中,提取器应查看注册的 dataId 的开头,但这在不同的实现中可能有所不同。当一个对象提取了所有必要的数据后,它必须使用以下方法结束提取:
virtual bool endExtraction( OdUInt8 dataId ) = 0;
通常此方法会重置提取器。在 beginExtraction() 和 endExtraction() 期间,对象可以使用以下方法提取数据:
virtual void extractBytes( void* buffer, OdUInt32 numBytes ) = 0;
OdGiDataExtractor 还具有一些基于 extractBytes() 的默认实现的辅助方法。
此外,对象还可以使用:
virtual bool seekFromLocalOffset( OdUInt64 offset ) = 0;
请注意,在这种情况下,偏移值是本地 dataId 偏移量,它是使用从 0 开始的 dataId 计算的。
使用 OdTvProgressiveMesh 进行部分加载
从 VSFX 文件加载的每个 OdTvProgressiveMesh 都支持两种部分渐进网格加载版本。OdTvFactoryId 类的 readVSFX 方法有一个 OdTvVSFXReadOptions 选项参数。这些选项具有 progressiveMeshMode 字段,可以是以下之一:
- OdTvVSFXReadOptions::kNormalMode — 以常规模式读取渐进网格。
- OdTvVSFXReadOptions::kPartialMode — 以纯部分模式读取渐进网格。
- OdTvVSFXReadOptions::kFastPartialMode — 以快速混合部分模式读取渐进网格。请注意,来自 VSF 文件的 OdTvProgressiveMesh 不支持部分加载。
OdTvVSFXReadOptions::kPartialMode
这是纯部分模式。渐进网格不在内存中存储 LOD 信息,它逐个单独提取每个 LOD 细节。因此,内存使用量始终保持最小。另一方面,LOD 切换非常慢,因为每个 LOD 细节的提取都需要文件流访问。然而,在内存使用量至关重要的情况下,它可能是一个很好的解决方案。
OdTvVSFXReadOptions::kFastPartialMode
这是一种快速混合的部分模式。渐进网格不在内存中存储 LOD 信息。但是,当需要切换 LOD 时,它会从文件流中加载整个 LOD 信息列表。LOD 切换完成后,它会卸载 LOD 信息列表。因此,在执行 LOD 切换时,内存使用量会增加,但完成后,内存使用量又会恢复到最小。这种方法将性能损失降低到几乎察觉不到的程度。