iOS 将 .obj 文件导入模型 I/O 而不复制顶点

Posted

技术标签:

【中文标题】iOS 将 .obj 文件导入模型 I/O 而不复制顶点【英文标题】:iOS Import .obj file to Model I/O without duplicating vertices 【发布时间】:2016-07-30 06:32:13 【问题描述】:

我正在尝试使用 Model I/O 框架导入 .obj 文件以在 Scene Kit 中使用。我最初使用简单的 MDLAsset initWithURL: 函数,但是在将网格转移到 SCNGeometry 之后,我意识到这个函数正在对网格进行三角剖分,这样每个面都有 3 个唯一的顶点,并且在边界面的同一位置有单独的顶点。这导致我的其他函数出现一些重大问题,因此我尝试通过使用 MDLAsset initWithURL:vertexDescriptor:bufferAllocator:preserveTopology 函数来修复它,将 preserveTopology 设置为 YES,并将描述符/分配器设置为默认值,nil。这种保留拓扑解决了我复制顶点的问题,所以面/边都很好,但在这个过程中我丢失了法线数据。

失去法线,我不是指多重索引,我的意思是在将 preserveTopology 设置为 YES 后,缓冲区根本不包含任何法线值。而之前它是 v1/n1/v2/n2... 并且步幅是 24 字节(3 个维度 *4 字节/浮点 * 2 个属性),现在缓冲区的前半部分是 v1/v2/...步幅为 12,缓冲区的整个第二半只有 0.0 个浮点数。

这也有点奇怪,当您查看几何的 SCNGeometrySources 时,有 2 个源,1 个具有语义 kGeometrySourceSemanticVertex,1 个具有语义 kGeometrySourceSemanticNormal。您会认为语义顶点源将包含位置数据,而语义法线源将包含法线数据。然而事实并非如此。无论您设置什么 preserveTopology,它们都是大小缓冲区,以包含具有相同值的位置数据和正常数据。所以当我之前说没有正常数据时,我的意思是这两个缓冲区,语义顶点和语义正常从 v1/n1/v2/n2... 变为 v1/v2/.../(0.0, 0.0, 0.0)/(0.0, 0.0, 0.0)/... 我进入 mdlmesh 的缓冲区(在转移到场景套件之前)发现同样的问题,所以问题一定是 initWithURL,而不是模型 i/o到scenekit桥。

所以我认为默认的顶点描述符和缓冲区分配器肯定有问题(因为我使用的是 nil)并开始尝试创建我自己的匹配这两种可能的数据格式。唉,经过多次尝试,我无法得到有效的东西。

关于我应该如何做到这一点的任何想法?如何为 MDLAsset 提供正确的 vertexDescriptor 和 bufferAllocator(我觉得这里 nil 应该没问题)以导入 .obj 文件?谢谢

【问题讨论】:

【参考方案1】:

具有顶点和法线的 obj 文件有顶点,用 v 线表示,法线用 vn 线表示,面用 f 线表示。

v 和 vn 行将是您期望的浮点值,而 f 行将是 -

f v0//n0 v1//n1 等

由于 OpenGL 和 Metal 不允许多重索引,您将看到顶点被复制的第一个效果。例如,

f 0//0 1//2 2//0

不能用作顶点缓冲区,因为它需要每个顶点不同的索引。所以典型的 OBJ 解析器必须创建新的顶点来允许人脸变成

f 0//0 1//1 2//2

保留拓扑选项对您没有帮助。它保留了网格的连通性和形状(不发生三角剖分,共享边保持共享),但它仍然对每个顶点组件强制执行单个索引。

一种解决方案是确保输出 OBJ 文件的工具在导出期间使用单一索引(如果可以的话)。

另一种选择,这不会立即解决问题,是提出在模型 I/O 级别支持多索引的请求。 SceneKit 仍然需要唯一索引,因为它必须能够渲染。

另一种选择是使用像 PLY 这样没有多重索引的格式。

【讨论】:

这对 .obj 文件很有见地,但我认为我对问题所在还不够清楚。通过复制顶点我的意思是三角剖分,所以保留拓扑解决了那里的问题。我相信,问题不在于您所说的多重索引。问题是设置 preserveTopology:YES 导致法线数据根本不加载到缓冲区中。我编辑了问题以使其更清楚。 你是对的。当设置保留拓扑标志时,所有每个顶点的数据都会丢失,包括法线、颜色和纹理坐标。如果可能,请提交有关此问题的错误报告以修复它。 @NickPorcino 非常感谢您的这一富有启发性的评论。这是否意味着 Model I/O 无法准确导入所有有效的 OBJ 文件,因为它不会将面顶点参考编号正确导入其索引缓冲区结构?这让我困惑了一整天。

以上是关于iOS 将 .obj 文件导入模型 I/O 而不复制顶点的主要内容,如果未能解决你的问题,请参考以下文章

I/O模型介绍

IO操作与IO模型

IO 操作与 IO 模型

Nginx 之 I/O模型介绍

I/O模型剖析

操作系统IO模型