7

I have downloaded two different 3D models from Sketchfab. i imported both model in ARKit 3D object placing. While placing the 3D models the node is not properly aligning with the manipulator for one of the models.. i have attached screenshot. enter image description here

Left side is where the selected node(viewport) and manipulator are properly aligned. But Right side the selected node(viewport) and manipulator are not properly aligned. How do i make the node and manipulator align to the center like left side 3D model. please guide me. Thank you

@Josh Robbins

i have tried your code but still i am getting same issue.

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

updated code

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
Raj
  • 485
  • 9
  • 18
  • Why do you want to place it in the center? In the app you need only the tree not the hole scene.. so when you add the tree you it will not matter if it was on the center.. the positions will be the same with the positions if it was on the center. For any reasion if you want to move it to the center you will have to change from the right menu the position x to - some number.. – Vasilis D. Mar 06 '18 at 13:19
  • @ Βασίλης Δ when i try to place the object in planes(touch location). the object is getting placed in summer other location. at the same time when i try to rotate the object, the object along with the manipulator is turning instead off the object alone.. if i try to change node position of x the node object and manipulator both moving. how to fix it.. thanks – Raj Mar 06 '18 at 13:43
  • So if i understand your problem well you have activate the plane detection and you want to add SCNNodes to the detected planes in the position of the touch that you make in the detected plane and it should be upon the detected plane. I will write you the code in answer because it is big – Vasilis D. Mar 06 '18 at 14:02
  • @ Βασίλης Δ i have updated my issues screenshot. please check it. thanks – Raj Mar 06 '18 at 14:05
  • can you please write the code that initialize the variables box and node? – Vasilis D. Mar 06 '18 at 14:07
  • i have updated my full code please check it. thanks – Raj Mar 06 '18 at 14:11
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/166325/discussion-between-raj-and--). – Raj Mar 06 '18 at 14:13

3 Answers3

2

This seems to be a popular question. I just answered a similar question a few minutes ago. See if this function below helps centering your node's pivot without moving its position.

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
}

to use the function above do this:

 centerPivotWithOutMoving(for: treenode)

Edit: I’ve realised my approach above wasn’t the most efficient way to go about solving centerPivotWithOutMoving for all cases, because in some cases the local axis of the childnode you are trying to center the pivot for may not coplanar (local axis & parent axis sharing the same planes) with the ParentNode axis. A better way to go is to put a wrapperNode around each node you want to centre the pivot for.

something like this will wrap each node fixing that potential issue when the axis are not coplanar.

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

I did this for the time being to call CenerPivotWithOutMoving on all the childNodes at time of tapping into the scene.

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

    }

here is the modified centerPivotWithOutMoving, with some added code for testing the local axis against the parent just to show they are all now 1,1,1 for all wrapper nodes. Without the wrapper nodes these numbers were in most cases never 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
}
Clay
  • 1,721
  • 2
  • 10
  • 18
1

Looking at your model, it seems like the pivot is set to the left hand side for you tree.

You can change the pivot of your programatically by using the pivot property of the `SCNNode, which is an SCNMatrix4MakeTranslation.

Assuming your model is called tree you could change it like so:

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

Or you can try this:

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

Update: In Scenekit Editor, you could also create an `EMPTY NODE'. Thenposition the tree centrally within that. This is probably your best bet if the aforementioned doesn't work.

BlackMirrorz
  • 7,217
  • 2
  • 20
  • 31
0

I solved this problem with node.position = SCNVector3(0, 0, 0)

In my code looks like this:

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

I hope it helps to you.