渐进网格部分加载

简介

渐进网格是一种特殊对象,可用于提高渲染性能。例如,一个具有大量面的大型壳体在屏幕上可能非常小,通常所有面都会独立渲染,无论它们(以及整个壳体)在屏幕上有多小。

渐进网格允许您更改细节级别 (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;
    定义渐进网格是否处于部分模式。
  • virtual void endPartialMode() = 0;
    强制将 LOD 信息加载到内存中并结束部分模式。当重新写入用于在部分模式下加载渐进网格的文件时,这可能会有所帮助;在这种情况下,无法保证提取器和计算的偏移量有效,因为流可能会被更改。
使用 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 字段,可以是以下之一:

  1. OdTvVSFXReadOptions::kNormalMode — 以常规模式读取渐进网格。
  2. OdTvVSFXReadOptions::kPartialMode — 以纯部分模式读取渐进网格。
  3. OdTvVSFXReadOptions::kFastPartialMode — 以快速混合部分模式读取渐进网格。请注意,来自 VSF 文件的 OdTvProgressiveMesh 不支持部分加载。
OdTvVSFXReadOptions::kPartialMode

这是纯部分模式。渐进网格不在内存中存储 LOD 信息,它逐个单独提取每个 LOD 细节。因此,内存使用量始终保持最小。另一方面,LOD 切换非常慢,因为每个 LOD 细节的提取都需要文件流访问。然而,在内存使用量至关重要的情况下,它可能是一个很好的解决方案。

OdTvVSFXReadOptions::kFastPartialMode

这是一种快速混合的部分模式。渐进网格不在内存中存储 LOD 信息。但是,当需要切换 LOD 时,它会从文件流中加载整个 LOD 信息列表。LOD 切换完成后,它会卸载 LOD 信息列表。因此,在执行 LOD 切换时,内存使用量会增加,但完成后,内存使用量又会恢复到最小。这种方法将性能损失降低到几乎察觉不到的程度。

今天就开始行动

免费试用 ODA 软件 60 天。
无风险,无需信用卡。

免费试用