[返回博客](/cn/blog) # 渐进网格部分加载

Egor Slupko 十一月 12, 2021 [\#Visualize](/cn/blog/tag/visualize) [\#meshes](/cn/blog/tag/meshes)

<a class="a2a_button_facebook"></a><a class="a2a_button_twitter"></a><a class="a2a_button_linkedin"></a>

#### 简介

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

渐进网格允许您更改细节级别 (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 天。  
无风险，无需信用卡。**

[免费试用](https://www.opendesign.com/cn/free-trial)
