为3D网格创建自定义二进制格式

我曾经看到有人说,根据您的需要,使用自定义的二进制格式,而不是使用交换格式,会更好,更快。 但是,我想知道如何创建一个只包含顶点和索引数据的基本格式,如何将这些数据写入二进制文件并读取它。 多谢。

最终在运行时最终使用的是无论是在离线还是在运行时都将处理交换格式的版本。 主要区别是:

  1. 如果你在运行时这样做,那么你将最终反复支付处理成本
  2. 您可能希望花费尽可能less的时间进行处理和优化,以便您的加载时间合理

我不知道你的用例是什么,但我想你会把数据放入一个D3D或OpenGL的索引/顶点缓冲区集。 这听起来像你已经熟悉索引/顶点缓冲区是什么,所以我认为你可能缺less的部分是D3D调用顶点声明 。

OpenGL做同样的事情,但我觉得它在概念上没有很好的定义。 你会想看看Vertex Specification的OpenGL wiki,特别注意glVertexAttribPointer。

无论如何,顶点声明指定了每个组件的types以及它出现在顶点的位置。 例如,一个顶点声明可能如下所示:

  • [偏移量0] – 位置 – 3个32位浮点数(xyz)
  • [偏移量12] – 纹理坐标 – 2 32位浮点数(uv)
  • [偏移量20] – 颜色-1归一化压缩的ARGB值(或RGBA,或BGRA或…取决于系统)

给定这个顶点声明,然后用这个描述继续写出你的顶点缓冲区。 我通常倾向于用一个直的C结构匹配它:

struct MyVertex { Vector3F Position; Vector2F UV; int32_t mColour; }; 

为所有顶点创建一个数组,然后根据需要填充它们,并将顶点描述转储到文件中。

在运行时,你会把你的数据加载到内存中,然后对D3D / OpenGL进行适当的调用,说“我的顶点格式是这个”,并通过传递一个指向你的数据数组的指针构造你的顶点缓冲区。

索引缓冲区基本相同,只是指定每个索引的大小(8位,16位等)。

如果你想让不同的顶点缓冲区提供不同的数据stream,它会变得稍微复杂一点,但是我希望这能够帮助你理解一般的想法。

我在一个月前为我的引擎实现了这种离线格式。 基本的algorithm是:

  1. 在文字处理器中写出输出二进制文件的正式规范。 头+数据块。 数据types,偏移量,每个块表的每个元素的描述。
  2. 使用embedded式脚本语言,从3D编辑器将离线导出器写入C ++代码文本标题。 然后编码尝试导出所有内容。 对于每个关键帧,骨骼权重,骨骼列表,animation元数据(fps,fps),所有UVw纹理通道,标记,面部,边缘,面部法线,顶点法线,双正交,切线,材料,对象名称,四元数和matrix,帧数)等

  3. 使用预生成脚本将包含数据的标题包含到C ++离线转换器项目中。 运行项目并将头文本数据文件编译为二进制文件。 使用步骤1中的规范来正确编码转换器。 在这里你应该关心属性数据types。 即可以将顶点XYZ存储为float,short或者char。 在这里和第5步添加对每个合理数据types的支持是很重要的。

  4. 编写你的文件的在线加载器。 简单地读取fileheader到预定义的结构中,并把每个数据块char *

  5. 编写在线着色器生成器,渲染代码生成器和VBO初始化器,使用有关文件头和网格属性中的导出属性的信息。
  6. 给予

不要忘记添加对顶点数据压缩,三角形条带,多个文件导出的支持。

只是简单的顶点坐标和索引数据导出不足以呈现。 你需要更多的数据。 尽可能多地从3D编辑器中提取。 而且这个数据应该占用尽可能小的GPU内存空间。

这种scheme的主要缺点是步骤3很难转移到其他计算机上,要得到最终的二进制包,你应该总是使用自定义脚本重建转换项目。 但是,它提供了更多的可能性,使用许多现有的C ++库来处理数据,而不是一个发展不良的编辑器脚本语言。