如何将 .dae 文件加载到 iOS SceneKit 中的 SCNNode 中?

Posted

技术标签:

【中文标题】如何将 .dae 文件加载到 iOS SceneKit 中的 SCNNode 中?【英文标题】:How do you load a .dae file into an SCNNode in iOS SceneKit? 【发布时间】:2014-10-10 22:52:23 【问题描述】:

我无法理解如何将 .dae 文件中的几何图形加载到 ios SceneKit 场景图中。

我知道您可以将.dae 文件直接加载到 SCNScene 中:

// create a new scene
let scene = SCNScene("test.scnassets/test.dae")

我也知道你可以创建一个空的 SCNScene 并将内置的 3D 对象作为子节点添加到其中:

let scene = SCNScene()
var sphereNode = SCNNode()
sphereNode.geometry = SCNSphere(radius: 1.0)
scene.rootNode.addChildNode(sphereNode)

在第二种情况下,您可以将.dae 文件加载到 SCNNode 中而不是使用内置对象吗?还是预计所有.dae 文件都需要先加载到SCNScene 中?

如果后者是真的,那么如何将 SCNNode 对象放置在 SCNScene 下的场景图层次结构中的正确位置?

编辑#1:

这对我有用,这是 @FlippinFun 建议的修改版本。

let url = NSBundle.mainBundle().URLForResource("test.scnassets/test", withExtension: "dae")
let source = SCNSceneSource(URL: url, options: nil)
let block = source.entryWithIdentifier("ID10", withClass: SCNGeometry.self) as SCNGeometry
scene.rootNode.addChildNode(SCNNode(geometry: block))

但也许有更好的方法?以上涉及从 .dae 树中手动加载每个标识符。在我的文件中,有一个带有子标识符“ID2”和“ID10”的节点“SketchUp”。此方法不会让您加载根“SketchUp”。 (我得到一个运行时错误。)

【问题讨论】:

我已经发布了这个。这是一个链接。 ***.com/questions/25031774/… 谢谢。所以你的建议是使用SCNSceneSource。不幸的是,这对我来说现在崩溃了。 您的代码中似乎有一个错误可以检索几何。该类应该是 SCNGeometry 而不是 SCNNode。例如:let block = source.entryWithIdentifier("ID10", withClass: SCNGeometry.self) as SCNGeometry。有了这个修复,它对我有用。 是的,有一个错误。我将进行编辑。谢谢! 【参考方案1】:

通常的模式是加载您的场景并使用其名称检索您感兴趣的节点

[scene.rootNode childNodeWithName:aName recursively:YES];

然后您可以将此节点重新设置为您的主场景。

【讨论】:

但是在那种情况下,节点已经是根节点的直接子节点,对吗?因此,如果我需要它位于场景图中的某个其他节点下,我需要使用这种方法重新定位它。这就是为什么我要询问加载独立于 SCNScene 的 SCNNode 几何体。 无论如何,这是一个有用的方法。谢谢。 您通常会使用您的“其他”dae 文件创建一个新场景,检索您感兴趣的节点,并在您的主场景中重新设置它 您通常如何重新定义节点? 你可以看看WWDC 2014示例代码中的-[SCNNode asc_addChildNodeNamed:fromSceneNamed:withScale:]扩展方法。构建场景,使用-childNodeWithName:recursively: 获取节点,然后将-addChildNode: 简单地添加到主场景中的节点。【参考方案2】:

我有一个类似的问题,我有一个 .dae 文件,我想将该文件中的多个节点加载到一个节点中。这对我有用:

var node = SCNNode()
let scene = SCNScene(named: "helloScene.dae")
var nodeArray = scene.rootNode.childNodes

for childNode in nodeArray 
  node.addChildNode(childNode as SCNNode)

首先,我设置了一个节点,它将所有内容保存在一起,使其看起来像在原始文件中一样。接下来我们导入我们想要的 .dae 文件并复制其中的所有节点。最后,对于数组中的每个节点,我将其添加到节点中。

【讨论】:

我用 var nodeArray = scene!.rootNode.childNodes 替换了 var nodeArray = scene.rootNode.childNodes【参考方案3】:

感谢您的帮助!

这是一个简单的 collada2Node 类。

//collada2SCNNode
class func collada2SCNNode(filepath:String) -> SCNNode 
    var node = SCNNode()
    let scene = SCNScene(named: filepath)
    var nodeArray = scene!.rootNode.childNodes

    for childNode in nodeArray 
        node.addChildNode(childNode as SCNNode)
    
    return node

【讨论】:

【参考方案4】:
func nodeWithFile(path: String) -> SCNNode 

    if let scene = SCNScene(named: path) 

        let node = scene.rootNode.childNodes[0] as SCNNode
        return node

     else 
        println("Invalid path supplied")
        return SCNNode()
    


【讨论】:

【参考方案5】:

以下答案对我不起作用。

这是在 Xcode 7.0 beta 5、iOS 9.0 beta / Swift 2.0 中对我有用的:

3D 模型类型:科拉达 3D 模型名称:“model.dae”

    加载场景:

    let lampScene = SCNScene(named: "art.scnassets/model.dae")
    

    访问SCNScene中的子SCNode:

    let lampRootNode = lampScene?.rootNode.childNodes[0]
    

    将加载场景中的灯节点添加到当前加载并查看的场景中:

    self.scene.rootNode.addChildNode(lampRootNode!)
    

注意:self.scene 存在的原因是:

private var scene:SCNScene!

在将对象添加到场景之前,我已经根据场景套件示例进行了一些场景设置。如果您需要代码,请在 cmets 中提及。

希望对你有帮助。

【讨论】:

你为什么不使用 SCNReferenceNode?这种方法有优势吗?【参考方案6】:
guard let shipScene = SCNScene(named: "ship.dae") else  return 
let shipNode = SCNNode()
let shipSceneChildNodes = shipScene.rootNode.childNodes
for childNode in shipSceneChildNodes 
    shipNode.addChildNode(childNode)

【讨论】:

以上是关于如何将 .dae 文件加载到 iOS SceneKit 中的 SCNNode 中?的主要内容,如果未能解决你的问题,请参考以下文章

将 collada (dae) 文件加载到 SCNNode (Swift - SceneKit)

将 Collada dae 文件加载到 SceneKit 以进行联合操作

Android 将 FBX 或 Collada(.dae) 加载到 Android Studio Activity 中

如何在 SceneKit 中使用 OBJ 文件或 CTM 文件而不是 DAE 文件?

是我需要导出到 .dae 的包 org.papervision3d.core.io 吗?

如何导出 DAE 文件以在 Scene Kit 中使用而不会看到“无标题动画”?