ARKit - 如何在SceneKit编辑器中使用节点中心设置操纵杆位置

7

我从Sketchfab下载了两个不同的3D模型。我将这两个模型导入到ARKit 3D对象放置中。在放置3D模型时,其中一个模型的节点与操作器没有正确对齐。 我已经附上了截图。 enter image description here

左侧是选定节点(视口)和操作器正确对齐的位置。 但右侧选定节点(视口)和操作器未正确对齐。 请问如何使节点和操作器像左侧3D模型一样居中对齐。谢谢。

@Josh Robbins

我尝试了您的代码,但仍然遇到相同的问题。

box.firstMaterial?.emission.contents = UIColor.green

                    box.firstMaterial?.shaderModifiers = [SCNShaderModifierEntryPoint.surface: sm]

                    box.firstMaterial?.isDoubleSided = true
                    let boxNode = SCNNode(geometry: box)
                    boxNode.position = SCNVector3(node.position.x,(node.position.y + Float((proheights * 0.0234)/2)),node.position.z)

                    let minimum = float3(treenode.boundingBox.min)
                    let maximum = float3(treenode.boundingBox.max)

                    let translation = (maximum - minimum) * 0.5

                    //3. Set The Pivot
                    treenode.pivot = SCNMatrix4MakeTranslation(translation.x, translation.y, translation.z)
                    boxNode.pivot = SCNMatrix4MakeTranslation(translation.x, translation.y, translation.z)

                    self.addChildNode(boxNode)

enter image description here

更新的代码

let treenode = SCNNode()
                    let box = SCNBox(width: (prowidths * 0.0234), height: (proheights * 0.0234), length: (prolenght * 0.0234), chamferRadius: 0)

                    box.firstMaterial?.emission.contents = UIColor.green

                    box.firstMaterial?.shaderModifiers = [SCNShaderModifierEntryPoint.surface: sm]

                    box.firstMaterial?.isDoubleSided = true
                    let boxNode = SCNNode(geometry: box)
                    boxNode.position = SCNVector3(treenode.position.x,(treenode.position.y + Float((proheights * 0.0234)/2)),treenode.position.z)

                    let minimum = float3(treenode.boundingBox.min)
                    let maximum = float3(treenode.boundingBox.max)

                    let translation = (maximum - minimum) * 0.5

                    //3. Set The Pivot
                    treenode.pivot = SCNMatrix4MakeTranslation(translation.x, translation.y, translation.z)
                    boxNode.pivot = SCNMatrix4MakeTranslation(translation.x, translation.y, translation.z)

                    self.addChildNode(boxNode)

                self.addChildNode(treenode)
                return treenode

你为什么想把它放在中心位置?在应用程序中,你只需要树而不是整个场景..所以当你添加树时,它是否在中心位置并不重要..位置将与如果它在中心位置相同。如果出于任何原因你想把它移动到中心位置,你将不得不从右侧菜单更改位置x为-某个数字.. - Vasilis D.
所以如果我理解你的问题正确,你已经启用了平面检测,并且想要在检测到的平面上根据触摸位置添加SCN节点,并且它应该在检测到的平面之上。因为代码很长,我会在答复中写下它。 - Vasilis D.
请问能否编写初始化变量box和node的代码? - Vasilis D.
我已经更新了我的全部代码,请检查一下。谢谢。 - Raj
让我们在聊天中继续这个讨论. - Raj
显示剩余2条评论
3个回答

2

这似乎是一个普遍的问题。我几分钟前刚回答了一个类似的问题。看看下面的函数是否有助于将节点的中心轴居中而不移动其位置。

将SCNNode的枢轴设置为边界体积中心,而不更改节点的位置

 func centerPivotWithOutMoving(for node: SCNNode) -> SCNNode {

 let initialPos = treenode.presentation.position

 var min = SCNVector3Zero
 var max = SCNVector3Zero
 node.__getBoundingBoxMin(&min, max: &max)

 node.pivot = SCNMatrix4MakeTranslation(
     min.x + (max.x - min.x)/2,
     min.y + (max.y - min.y)/2,
     min.z + (max.z - min.z)/2
 )
 let correctX = Float(min.x + (max.x - min.x)/2)
 let correctY = Float(min.y + (max.y - min.y)/2)
 let correctZ = Float(min.z + (max.z - min.z)/2)

 if node.convertVector(SCNVector3(0,0,1), from: parentNode).z < 0 {
     // if blue local z-axis is pointing downwards
      node.position = SCNVector3(initialPos.x - correctX, initialPos.y - correctY, initialPos.z - correctZ)
 } else {
     // if blue local z-axis is pointing upwards
     node.position = SCNVector3(initialPos.x + correctX, initialPos.y + correctY, initialPos.z + correctZ)
 }

 return node
}

要使用上述功能,请执行以下操作:

 centerPivotWithOutMoving(for: treenode)
编辑:我意识到上述方法不是解决所有情况下centerPivotWithOutMoving的最有效方法,因为在某些情况下,您尝试为其居中轴心的子节点的局部轴可能与ParentNode轴不共面(局部轴和父轴共享相同平面)。更好的方法是在要为其居中轴心的每个节点周围放置一个wrapperNode。

像这样的东西将包装每个节点,修复轴不共面的潜在问题。

    for child in (self.parentNode?.childNodes)! {
                let wrapperNode = SCNNode()
                child.geometry?.firstMaterial?.lightingModel = .physicallyBased
                wrapperNode.addChildNode(child)
                wrapperNode.name = child.name! + "_wrapper"
                self.parentNode.addChildNode(wrapperNode)
            }

目前我这样做是为了在点击场景时调用CenerPivotWithOutMoving方法来处理所有子节点。

 for child in parentNode.childNodes {
           let delayInSeconds = Double(0.1)
          DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + delayInSeconds) {
            self.centerPivotWithOutMoving(for: child)
         }

    }

这是修改后的centerPivotWithOutMoving代码,添加了一些用于测试本地轴与父级节点之间关系的代码,以展示它们现在对所有包装节点都是1,1,1。如果没有包装节点,这些数字在大多数情况下从未为1,1,1。

  func centerPivot(for node: SCNNode) -> SCNNode {
    var min = SCNVector3Zero
    var max = SCNVector3Zero
    node.__getBoundingBoxMin(&min, max: &max)
    node.pivot = SCNMatrix4MakeTranslation(
        min.x + (max.x - min.x)/2,
        min.y + (max.y - min.y)/2,
        min.z + (max.z - min.z)/2
    )
    return node
}



func centerPivotWithOutMoving(for node: SCNNode) -> SCNNode {

    let initialPos = node.presentation.position

    var min = SCNVector3Zero
    var max = SCNVector3Zero
    node.__getBoundingBoxMin(&min, max: &max)

    // corrective factor for each axis
    let correctX = Float(min.x + (max.x - min.x)/2)
    let correctY = Float(min.y + (max.y - min.y)/2)
    let correctZ = Float(min.z + (max.z - min.z)/2)

    var xAxis = node.convertVector(SCNVector3(1,0,0), from: parentNode).x 
    var yAxis = node.convertVector(SCNVector3(0,1,0), from: parentNode).y
    var zAxis = node.convertVector(SCNVector3(0,0,1), from: parentNode).z

    // check the local axis is coplanar with parentNode axis
    if (xAxis == 1) && (yAxis == 1) && (zAxis == 1) {
        print(node.name)
        centerPivot(for: node)
        node.position = SCNVector3(initialPos.x + correctX, initialPos.y + correctY, initialPos.z + correctZ)
    } else {
        print("node axis is not coplanar with parent")
    }

    return node
}

1

从您的模型来看,似乎您的树的枢轴设置在左侧。

您可以通过使用“SCNNode”的枢轴属性(即“SCNMatrix4MakeTranslation”)在程序中更改其枢轴。

假设您的模型名为“tree”,您可以这样更改:

tree.pivot = SCNMatrix4MakeTranslation(0,0,0)

或者你可以尝试这个:

//1. Get The Bounding Box Of The Tree
let minimum = float3(tree.boundingBox.min)
let maximum = float3(tree.boundingBox.max)

//2. Set The Translation To Be Half Way Between The Vector
let translation = (maximum - minimum) * 0.5

//3. Set The Pivot
tree.pivot = SCNMatrix4MakeTranslation(translation.x, translation.y, translation.z)

更新:在Scenekit编辑器中,您还可以创建一个“空节点”。然后将树置于其中央。如果前面提到的方法不起作用,则这很可能是您最好的选择。


在设置节点位置之前,也可以尝试设置枢轴点 :) 只是一个想法 :) - BlackMirrorz

0
我使用 node.position = SCNVector3(0, 0, 0) 解决了这个问题。
在我的代码中是这样的:
func placeObject(with objectPath: String) {
        // Create a new scene
        guard let virtualObjectScene = SCNScene(named: objectPath)
            else {
                print("Unable to Generate " + objectPath)
                return
        }
        let wrapperNode = SCNNode()
        for child in virtualObjectScene.rootNode.childNodes {
            child.geometry?.firstMaterial?.lightingModel = .constant
            wrapperNode.addChildNode(child)
        }
        // Rotate the node
        let rotationAction = SCNAction.rotateBy(x: 0, y: 0.5, z: 0, duration: 1)
        let inifiniteAction = SCNAction.repeatForever(rotationAction)
        wrapperNode.runAction(inifiniteAction)

        // 0.08 from placed plane
        wrapperNode.position =  SCNVector3(0, 0.08, 0)

        node.addChildNode(wrapperNode)
    }

希望对你有所帮助。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接