我于 11 月 25 日在 Apple Bug Reporter 上报告了此错误,错误 ID:35687088
摘要:SCNSceneSourceLoadingOptionPreserveOriginalTopology 实际上并不保留原始拓扑。相反,它将几何体转换为所有四边形,严重扰乱了 3D 模型。根据其名称,它的行为应该与 Model IO 资产加载的preserveTopology 完全相同。
重现步骤:使用 SCNSceneSourceLoadingOptionPreserveOriginalTopology 加载同时具有三角形和多边形的 OBJ 文件,并使用 ModelIO 的preserveTopology 将同一文件加载到 MDLMesh 中。请注意它如何仅适用于后者。即使您基于 MDLMesh 创建新的 SCNGeometry,它也会再次“限定”网格以仅包含四边形(同时它应该支持 3 边形及以上)。
12 月 13 日,我收到了回复,要求提供示例代码和资源,我在 2 天后提供了这些内容。从那以后我还没有收到回复(希望是因为他们只是忙着赶假期......)。
正如我在错误报告摘要中提到的,使用模型 I/O 加载资源确实可以正常工作,但是当您基于该 MDLMesh 创建 SCNNode 时,它最终会再次弄乱几何图形。
就我而言,我加载的 OBJ 文件具有已知格式,因为它们始终是随我的应用程序导出的文件(没有法线、颜色、UV)。因此,我所做的是将 MDLMesh(缓冲区、面拓扑等)的信息手动加载到数组中,然后从中手动创建 SCNGeometry。我没有为您提供完整的独立代码段,因为它很多并且与我的应用程序特定的大量代码混合在一起,并且它是在 Objective C 中。但为了说明:
NSError *scnsrcError;
MDLAsset *asset = [[MDLAsset alloc] initWithURL:objURL vertexDescriptor:nil bufferAllocator:nil preserveTopology:YES error:&scnsrcError];
NSLog(@"%@", scnsrcError.localizedDescription);
MDLMesh * newMesh = (MDLMesh *)[asset objectAtIndex:0];
for (MDLSubmesh *faces in newMesh.submeshes) {
//MDLSubmesh *faces = newMesh.submeshes.firstObject;
MDLMeshBufferData *topo = faces.topology.faceTopology;
MDLMeshBufferData *vertIx = faces.indexBuffer;
MDLMeshBufferData *verts = newMesh.vertexBuffers.firstObject;
int faceCount = (int)faces.topology.faceCount;
int8_t *faceIndexValues = malloc(faceCount * sizeof(int8_t));
memcpy(faceIndexValues, topo.data.bytes, faceCount * sizeof(int8_t));
int32_t *vertIndexValues = malloc(faces.indexCount * sizeof(int32_t));
memcpy(vertIndexValues, vertIx.data.bytes, faces.indexCount * sizeof(int32_t));
SCNVector3 *vertValues = malloc(newMesh.vertexCount * sizeof(SCNVector3));
memcpy(vertValues, verts.data.bytes, newMesh.vertexCount * sizeof(SCNVector3));
....
....
}
简而言之,SceneKit 中的preserveTopology 选项无法正常工作。为了从 Model I/O 中的工作版本转换为 SceneKit,我基本上必须编写自己的转换器。