COLLADA2GLTF源码解析

此次解析针对其中的GLTF库一些函数,强化对GLTF结构的认知,包括对于Draco压缩的一些解读

前置知识: GLTF格式解析-CSDN博客

目录

1.GLTFAsset.cpp

1.1 GLTF::Asset::getAllPrimitiveAccessors


 

1.GLTFAsset.cpp

1.1 GLTF::Asset::getAllPrimitiveAccessors

std::vector GLTF::Asset::getAllPrimitiveAccessors(
    GLTF::Primitive* primitive) const {
  std::vector accessors;

  for (const auto& attribute : primitive->attributes) {
    accessors.emplace_back(attribute.second);
  }
  for (const auto* target : primitive->targets) {
    for (const auto& attribute : target->attributes) {
      accessors.emplace_back(attribute.second);
    }
  }

  return move(accessors);
}
这段代码是一个成员函数`getAllPrimitiveAccessors`,它是`GLTF::Asset`类的一部分,该函数的目的是从一个指定的`GLTF::Primitive`对象中提取所有相关的访问器(`GLTF::Accessor`)。

以下是对代码的详细解释:

1. **函数声明**:
   ```cpp
   std::vector GLTF::Asset::getAllPrimitiveAccessors(
       GLTF::Primitive* primitive) const {
   ```
   这一行定义了一个函数,名为`getAllPrimitiveAccessors`,该函数返回一个`std::vector`,其中包含指向`GLTF::Accessor`对象的指针。它接收一个指向`GLTF::Primitive`对象的指针作为参数,并且该函数是常量的,意味着它不能修改其所属的`GLTF::Asset`对象。

2. **初始化结果向量**:
   ```cpp
   std::vector accessors;
   ```
   这行代码创建了一个空的`std::vector`,用于存储`GLTF::Accessor`指针。

3. **遍历primitive的attributes**:
   ```cpp
   for (const auto& attribute : primitive->attributes) {
       accessors.emplace_back(attribute.second);
   }
   ```
   这段代码遍历`primitive`的`attributes`(可能是一个映射或类似的数据结构),然后将每个属性的`second`值(这里似乎是一个指向`GLTF::Accessor`的指针)添加到`accessors`向量中。

4. **遍历primitive的targets**:
   ```cpp
   for (const auto* target : primitive->targets) {
       for (const auto& attribute : target->attributes) {
           accessors.emplace_back(attribute.second);
       }
   }
   ```
   这部分代码遍历`primitive`的`targets`。对于每一个`target`,它又遍历该`target`的`attributes`,并且像之前那样,将每个属性的`second`值添加到`accessors`向量中。

5. **返回结果**:
   ```cpp
   return move(accessors);
   ```
   使用`std::move`来返回`accessors`,这样做的目的是为了优化性能,避免额外的复制操作。这会将向量的所有权从函数的局部变量`accessors`移动到返回的向量。

总的来说,该函数的目的是从给定的`GLTF::Primitive`对象中提取所有相关的`GLTF::Accessor`指针,并将它们作为一个向量返回。这可能是为了在后续的处理中方便地访问这些访问器。

主要就是遍历primitive中的attributes和targets,这两个属性需要搞明白

// Copyright 2020 The Khronos® Group Inc.
#pragma once

#include 
#include 
#include 

#include "GLTFAccessor.h"
#include "GLTFDracoExtension.h"
#include "GLTFMaterial.h"
#include "GLTFObject.h"

namespace GLTF {
class Primitive : public GLTF::Object {
 public:
  enum Mode {
    UNKNOWN = -1,
    POINTS = 0,
    LINES = 1,
    LINE_LOOP = 2,
    LINE_STRIP = 3,
    TRIANGLES = 4,
    TRIANGLE_STRIP = 5,
    TRIANGLE_FAN = 6,
  };

  class Target {
   public:
    std::map attributes;

    Target* clone(GLTF::Object* clone);
    void writeJSON(void* writer, GLTF::Options* options);
  };

  std::map attributes;
  GLTF::Accessor* indices = NULL;
  GLTF::Material* material = NULL;
  Mode mode = Mode::UNKNOWN;
  std::vector targets;

  ~Primitive();

  virtual GLTF::Object* clone(GLTF::Object* clone);
  virtual void writeJSON(void* writer, GLTF::Options* options);
};
}  // namespace GLTF

 其中Primitive中的定义是

 std::map attributes;
 std::vector targets;

以下是对这个类的详细解释

这段代码定义了名为`GLTF::Primitive`的类,这是在GLTF(GL Transmission Format)的上下文中使用的,GLTF是一种用于3D场景和模型的传输格式。此类表示一个几何图元,这是3D图形中渲染的基本单元,例如点、线和三角形。

以下是`GLTF::Primitive`类的详细解释:

### 类定义:

```cpp
class Primitive : public GLTF::Object {
```
这里,`Primitive`类是`GLTF::Object`类的一个子类。

### 枚举 Mode:
```cpp
enum Mode {
  UNKNOWN = -1,
  POINTS = 0,
  LINES = 1,
  LINE_LOOP = 2,
  LINE_STRIP = 3,
  TRIANGLES = 4,
  TRIANGLE_STRIP = 5,
  TRIANGLE_FAN = 6,
};
```
这个枚举定义了几种可能的图元类型。例如,`TRIANGLES`用于定义由单独三角形组成的图元。

### 内部类 Target:
```cpp
class Target {
 public:
  std::map attributes;
  // ...
};
```
这个`Target`类包含一个映射`attributes`,它将字符串映射到`GLTF::Accessor`对象的指针。这些属性可能代表顶点的不同属性,如位置、法线和纹理坐标。

### 类成员:
```cpp
std::map attributes;
GLTF::Accessor* indices = NULL;
GLTF::Material* material = NULL;
Mode mode = Mode::UNKNOWN;
std::vector targets;
```
- `attributes`:一个映射,包含了与这个图元相关的`GLTF::Accessor`对象的指针。
- `indices`:指向用于描述图元顶点索引的`GLTF::Accessor`对象的指针。
- `material`:指向与此图元关联的`GLTF::Material`对象的指针,定义了图元的材质。
- `mode`:定义了图元的类型,是上面定义的`Mode`枚举的一个实例。
- `targets`:一个`Target`对象的指针的向量。

### 析构函数:
```cpp
~Primitive();
```
这是类的析构函数,用于在对象生命周期结束时执行清理。

### 虚拟函数:
```cpp
virtual GLTF::Object* clone(GLTF::Object* clone);
virtual void writeJSON(void* writer, GLTF::Options* options);
```
这些都是虚拟函数,由子类来实现。`clone`函数用于克隆一个对象,而`writeJSON`函数用于将对象的状态写入JSON格式。

总之,`GLTF::Primitive`类似乎表示一个3D图形中的图元,包含了定义图元的各种属性和方法,如几何类型、关联材质、顶点属性等。这样的表示法是为了能够将3D模型以GLTF格式进行存储和传输。

里面涉及到了一个难懂的GLTF::Accessor*,接下来我将对这个结构进行解释

// Copyright 2020 The Khronos® Group Inc.
#pragma once

#include 

#include "GLTFBufferView.h"
#include "GLTFConstants.h"
#include "GLTFObject.h"

namespace GLTF {
class Accessor : public GLTF::Object {
 public:
  enum class Type { SCALAR, VEC2, VEC3, VEC4, MAT2, MAT3, MAT4, UNKNOWN };

  GLTF::BufferView* bufferView = NULL;
  int byteOffset = 0;
  GLTF::Constants::WebGL componentType;
  int count = 0;
  float* max = NULL;
  float* min = NULL;
  Type type = Type::UNKNOWN;

  Accessor(GLTF::Accessor::Type type, GLTF::Constants::WebGL componentType);

  Accessor(GLTF::Accessor::Type type, GLTF::Constants::WebGL componentType,
           unsigned char* data, int count, GLTF::Constants::WebGL target);

  Accessor(GLTF::Accessor::Type type, GLTF::Constants::WebGL componentType,
           unsigned char* data, int count, GLTF::BufferView* bufferView);

  Accessor(GLTF::Accessor::Type type, GLTF::Constants::WebGL componentType,
           int byteOffset, int count, GLTF::BufferView* bufferView);

  explicit Accessor(GLTF::Accessor* accessor);

  static int getComponentByteLength(GLTF::Constants::WebGL componentType);
  static int getNumberOfComponents(GLTF::Accessor::Type type);

  bool computeMinMax();
  int getByteStride();
  bool getComponentAtIndex(int index, float* component);
  bool writeComponentAtIndex(int index, float* component);
  int getComponentByteLength();
  int getNumberOfComponents();
  bool equals(GLTF::Accessor* accessor);
  const char* getTypeName();

  virtual std::string typeName();
  virtual void writeJSON(void* writer, GLTF::Options* options);
};
}  // namespace GLTF

这段代码是定义`GLTF::Accessor`类的。在GLTF格式中,`Accessor`用来解读存储在`BufferView`中的二进制数据,描述了如何从`BufferView`中抽取出属性数据,比如位置、法线、纹理坐标等。

下面详细解释这个类的每个部分:

### 类定义
```cpp
class Accessor : public GLTF::Object {
```
`GLTF::Accessor`类是`GLTF::Object`的子类。

### 枚举 Type
```cpp
enum class Type { SCALAR, VEC2, VEC3, VEC4, MAT2, MAT3, MAT4, UNKNOWN };
```
这个枚举定义了可能的数据类型,包括标量、2D向量、3D向量、4D向量以及2x2、3x3、4x4矩阵。

### 成员变量
```cpp
GLTF::BufferView* bufferView = NULL;
int byteOffset = 0;
GLTF::Constants::WebGL componentType;
int count = 0;
float* max = NULL;
float* min = NULL;
Type type = Type::UNKNOWN;
```
- `bufferView`: 指向`GLTF::BufferView`的指针,描述了数据在缓冲中的布局。
- `byteOffset`: 在`BufferView`中的字节偏移量。
- `componentType`: 数据的组件类型,例如`FLOAT`或`UNSIGNED_SHORT`。
- `count`: `Accessor`所指向的元素数量。
- `max`和`min`: 描述数值范围的指针。
- `type`: 代表数据类型的`Type`枚举值。

### 构造函数
这个类提供了几个构造函数,允许不同的初始化方式,可以通过不同的参数集合来创建`Accessor`对象。

### 静态函数
```cpp
static int getComponentByteLength(GLTF::Constants::WebGL componentType);
static int getNumberOfComponents(GLTF::Accessor::Type type);
```
这两个静态方法用来返回给定`componentType`的字节长度和给定`Type`的组件数量。

### 成员函数
```cpp
bool computeMinMax();
int getByteStride();
bool getComponentAtIndex(int index, float* component);
bool writeComponentAtIndex(int index, float* component);
int getComponentByteLength();
int getNumberOfComponents();
bool equals(GLTF::Accessor* accessor);
const char* getTypeName();
```
- `computeMinMax()`: 计算并设置`min`和`max`成员变量。
- `getByteStride()`: 获取`Accessor`的字节步长。
- `getComponentAtIndex()`: 获取指定索引处的组件值。
- `writeComponentAtIndex()`: 在指定索引处写入组件值。
- `getComponentByteLength()`: 获取组件的字节长度。
- `getNumberOfComponents()`: 获取类型中的组件数量。
- `equals()`: 比较两个`Accessor`对象是否相等。
- `getTypeName()`: 获取类型名的字符指针。

### 虚拟成员函数
```cpp
virtual std::string typeName();
virtual void writeJSON(void* writer, GLTF::Options* options);
```
- `typeName()`: 返回类型名称的字符串。
- `writeJSON()`: 将对象写入JSON格式。

### 总结
这个`GLTF::Accessor`类定义了如何访问和解释存储在`BufferView`中的数据,它包含了相关的数据类型、组件类型、数量等信息,并提供了一系列方法来操作和查询这些数据。

 Accessor 中有BufferViewer、字节偏移、元素个数

BufferViewer中又存在什么的,我们看下面的

// Copyright 2020 The Khronos® Group Inc.
#pragma once

#include 

#include "GLTFBuffer.h"
#include "GLTFConstants.h"
#include "GLTFObject.h"

namespace GLTF {
class BufferView : public GLTF::Object {
 public:
  GLTF::Buffer* buffer = NULL;
  int byteOffset = 0;
  int byteStride = 0;
  int byteLength = 0;
  GLTF::Constants::WebGL target = (GLTF::Constants::WebGL)-1;

  BufferView(int byteOffset, int byteLength, GLTF::Buffer* buffer);
  BufferView(unsigned char* data, int dataLength);
  BufferView(unsigned char* data, int dataLength,
             GLTF::Constants::WebGL target);

  virtual std::string typeName();
  virtual void writeJSON(void* writer, GLTF::Options* options);
};
}  // namespace GLTF
这段代码定义了`GLTF::BufferView`类,该类是GLTF(GL Transmission Format,一种用于3D场景和模型的文件格式)中的一个重要组成部分。`BufferView`表示了从`Buffer`(包含原始二进制数据的容器)中如何读取数据。

### 类定义
```cpp
class BufferView : public GLTF::Object {
```
这里,`GLTF::BufferView`类从`GLTF::Object`类继承。

### 成员变量
```cpp
GLTF::Buffer* buffer = NULL;
int byteOffset = 0;
int byteStride = 0;
int byteLength = 0;
GLTF::Constants::WebGL target = (GLTF::Constants::WebGL)-1;
```
- `buffer`:这是一个指向`GLTF::Buffer`的指针,代表了包含实际二进制数据的缓冲。
- `byteOffset`:这是一个整数,表示从`buffer`开始读取数据的偏移量(以字节为单位)。
- `byteStride`:这是一个整数,描述了连续的顶点属性之间的间隔(以字节为单位)。
- `byteLength`:这是一个整数,代表了`BufferView`包含的数据量(以字节为单位)。
- `target`:这是一个`GLTF::Constants::WebGL`枚举值,描述了缓冲区的用途,比如是用于顶点数据还是索引数据。

### 构造函数
```cpp
BufferView(int byteOffset, int byteLength, GLTF::Buffer* buffer);
BufferView(unsigned char* data, int dataLength);
BufferView(unsigned char* data, int dataLength, GLTF::Constants::WebGL target);
```
这里提供了三个构造函数,允许用不同的参数来初始化`BufferView`对象。

### 虚拟成员函数
```cpp
virtual std::string typeName();
virtual void writeJSON(void* writer, GLTF::Options* options);
```
- `typeName()`:返回对象的类型名称。
- `writeJSON()`:将该对象写入JSON格式,接受一个写入器对象和选项对象。

### 总结
`GLTF::BufferView`类定义了如何在相应的`Buffer`对象中定位和读取数据。它包含关于缓冲视图如何访问其底层缓冲区的数据的信息,并提供了几个构造函数来创建对象,以及一些虚拟成员函数来获取对象类型和将对象写入JSON。

不明白已经有了attributes 为啥还需要GLTF::Accessor* indices

在GLTF(GL Transmission Format)格式中,`attributes` 和 `indices` 所扮演的角色是不同的。

1. **Attributes(属性)**:
   - `attributes` 通常包含了顶点的位置、法线、纹理坐标和其他顶点相关的信息。
   - 在 `GLTF::Primitive` 类中,`attributes` 是一个映射,它将字符串(如 "POSITION","NORMAL","TEXCOORD" 等)映射到 `GLTF::Accessor` 对象。这些 `GLTF::Accessor` 对象提供了从 `BufferView` 读取具体属性数据的必要信息。

2. **Indices(索引)**:
   - `indices` 存储了组成三维模型面片的顶点索引。
   - 在 `GLTF::Primitive` 类中,`indices` 是一个指向 `GLTF::Accessor` 的指针,它描述了如何从 `BufferView` 读取索引数据。
   - 通过索引,我们可以重用顶点数据,这使得数据存储更加高效。例如,一个共享同一个位置的两个三角形只需存储一个顶点的位置数据。

### 为什么需要两者:
- `attributes` 定义了顶点的各种属性,例如位置和纹理坐标。
- `indices` 定义了如何将这些顶点连接起来以形成三维模型的面片。

举个例子,假设我们有四个顶点,我们可以通过 `attributes` 定义它们的位置。然后,我们可以使用 `indices` 来定义哪三个顶点组成一个三角形。如果我们有四个顶点 0, 1, 2, 和 3,我们可以有索引如 `[0, 1, 2]` 和 `[2, 3, 0]` 来定义两个共享一条边的三角形。这样我们就能够通过索引来重用顶点数据,并且构造复杂的三维模型。

因此,`attributes` 和 `indices` 在3D模型中都是必要的,其中 `attributes` 提供了顶点的具体数据,而 `indices` 定义了如何将这些顶点组合起来以形成模型的表面。

其实到这里,我工作那边的研究已经到位了。我的需求是b3dm中的glb中对mesh进行draco压缩,已经解决。后续可能会更新,主要看大家的需求。

你可能感兴趣的:(图像算法与c++,算法,c++)