【问题标题】:ARKit - How to set manipulator position with center of the node in SceneKit editorARKit - 如何在 SceneKit 编辑器中使用节点中心设置操纵器位置
【发布时间】:2018-08-14 05:19:25
【问题描述】:

我从 Sketchfab 下载了两个不同的 3D 模型。我在 ARKit 3D 对象放置中导入了两个模型。放置 3D 模型时,节点未与其中一个模型的操纵器正确对齐。 我附上了截图。

左侧是所选节点(视口)和操纵器正确对齐的位置。 但右侧所选节点(视口)和操纵器未正确对齐。 如何使节点和操纵器像左侧 3D 模型一样与中心对齐。请指导我。谢谢

@乔什·罗宾斯

我已经尝试过你的代码,但我仍然遇到同样的问题。

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)

更新代码

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 更改为 - 某个数字..
  • @ Βασίλης Δ 当我尝试将对象放置在平面中(触摸位置)时。对象被放置在夏天的其他位置。同时,当我尝试旋转对象时,对象和操纵器正在单独关闭对象。如果我尝试更改 x 的节点位置,则节点对象和操纵器都在移动。如何解决它.. 谢谢
  • 因此,如果我很好地理解了您的问题,您已经激活了平面检测,并且您希望将 SCNNodes 添加到您在检测到的平面中进行的触摸位置的检测到的平面中,它应该在检测到的平面。我会写给你答案的代码,因为它很大
  • @ Βασίλης Δ 我更新了我的问题截图。请检查一下。谢谢
  • 你能写出初始化变量框和节点的代码吗?

标签: ios swift scenekit arkit 3d-model


【解决方案1】:

这似乎是一个热门问题。几分钟前我刚刚回答了一个类似的问题。看看下面的这个函数是否有助于在不移动节点位置的情况下使节点的枢轴居中。

set pivot of SCNNode to bounding volume center without changing the node's position

 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)
            }

我这样做是为了在进入场景时在所有 childNode 上调用 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
}

【讨论】:

    【解决方案2】:

    查看您的模型,似乎枢轴设置为您的树的左侧。

    您可以通过使用 `SCNNode 的 pivot 属性以编程方式更改您的枢轴,这是一个 SCNMatrix4MakeTranslation。

    假设您的模型称为树,您可以像这样更改它:

    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 编辑器中,您还可以创建一个“空节点”。然后将树放在其中的中心位置。如果上述方法不起作用,这可能是您最好的选择。

    【讨论】:

    • 还尝试在设置节点位置之前设置枢轴:) 只是一个想法:)
    【解决方案3】:

    我用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)
        }
    

    希望对你有帮助。

    【讨论】:

      猜你喜欢
      • 2018-02-28
      • 2017-12-08
      • 1970-01-01
      • 2016-01-28
      • 2019-06-30
      • 1970-01-01
      • 2020-04-01
      • 1970-01-01
      • 2011-10-26
      相关资源
      最近更新 更多