3

我目前正在使用 Apple 的 SceneKit/Model I/O 中的大型 .obj 文件,其中包含多个对象,每个对象都有单独的纹理和材质。这意味着我不能像许多其他表单帖子所建议的那样将单个纹理应用于文件。有没有很好的方法来导入材质和纹理?

我的 obj mtl 和 jpg 都在一个目录中,我也将 scn 场景放在该目录中。

代码当前遵循此设计,我从其各自的位置访问它,将其加载到 MDLAsset 中,然后将其放置到 SCNScene 中,然后将其保存回文件中,以便稍后在代码中加载。

//...  

// Get the mesh from the obj object  
let asset = MDLAsset(url:url)  
//asset.loadTextures()  
guard let object = asset.object(at: 0) as? MDLMesh else {  
    fatalError("Failed to get mesh from obj asset.")  
}  

// Wrap the ModelIO object in a SceneKit object  
let scene = SCNScene()  
let node = SCNNode(mdlObject: object)  
scene.rootNode.addChildNode(node)  

// Get the document directory name the write a url for the object replacing its extention with scn  
let dirPaths = FileManager().urls(for: .documentDirectory, in: .userDomainMask)  
let fileUrl = dirPaths[0].appendingPathComponent(url.lastPathComponent.replacingOccurrences(of: ".obj", with: ".scn"))  

// Write the scene to the new url  
if !scene.write(to: fileUrl, delegate: nil) {  
    print("Failed to write scn scene to file!")  
    return nil  
}  

// ... 

MDLAsset.loadTextures 函数没有文档,只会导致内存泄漏,因此在本文发布时,它不是一个选项。手动打开模型并点击转换为 SCNScene 也不起作用,因为我仍然丢失了材料。此外,我希望这在代码中实现自动化,以允许在运行时下载和转换模型。

似乎没有内置的方法可以做到这一点,除了在代码中手工制作每个纹理和材料,当它只有一个完整的纹理时这很容易,但这个模型可能有 100 种不同的材料。看起来它需要我手动解析 obj/mtl,然后手动创建和分配材料。这似乎完全不合理,我认为一定有更好的方法,我不知道。

4

1 回答 1

2

当您通过模型 I/O 将 OBJ 文件作为 MDLAsset 导入时,它将作为一个或多个 MDLMeshes 的集合到达。网格将具有与之关联的 MDLMaterial,并且 MDLMaterial 将具有属性。这些属性将是数字、文件路径或图像。您需要迭代属性,并检查是否有路径。

https://developer.apple.com/documentation/modelio/mdlmaterialproperty

如果有,它很可能是一个与 OBJ 文件的关联 MTL 文件具有相同内容的文件 URL。

MDLScatteringFunction 中描述的属性对应于典型 MTL 文件中的各种属性。

https://developer.apple.com/documentation/modelio/mdlscatteringfunction

如果模型 IO 确实可以找到 MTL 文件中引用的纹理,MDLAsset.loadTextures 将向属性添加一个 MDLTextureSampler 值。

于 2018-09-10T23:04:09.360 回答