Search code examples
iosscenekit

How to adjust node as per pivot


In Scenekit

let's say I have 2 BOX , box1 with PIVOT , box2 without PIVOT

My Goal is to match both of boxes with transformation

      let plane = SCNBox(width: 12, height: 2, length: 12, chamferRadius: 0)
      plane.firstMaterial?.diffuse.contents = UIColor.red
      let planeNode = SCNNode(geometry: plane)
      planeNode.name = "Plane1"
      planeNode.pivot  = SCNMatrix4MakeTranslation(0, -0.5, 0)

Box 2

      let plane2 = SCNBox(width: 12, height: 2, length: 12, chamferRadius: 0)
      plane2.firstMaterial?.diffuse.contents = UIColor.red
      let planeNode2 = SCNNode(geometry: plane2)
      planeNode2.name = "Plane2"

Now I scale BOX1 and box2

planeNode.scale.y = 4 planeNode2.scale.y = 4

as planeNode has pivot so it will be scale from bottom , but Plane2 will be scale from center

How can I calculate position of plane2 that it will match the plane1


Solution

  • Both of your boxes have pivots. By default, for SCNBox, it's in the objects center (the center of the Bounding Box). What you do is shifting the Pivot of your first Box. The Scene Object will always be placed relative to its current pivot position. So when you move up the pivot of the Y axis, the object will be in a lower position.

    You can match both object positions when you set the second object to the same position as the first object, then you add the inverted offset of the pivot from the first object to the position of the second object.

    make something like this:

    func alignPosition() {
        
        // Calculate offset position
        let offset = SCNVector3(planeNode.pivot.m41, planeNode.pivot.m42, planeNode.pivot.m43)
        
        // Set the seconds node to the position as the first node
        // without changing it's pivot, then subtract the offset
        planeNode2.position = planeNode.position - offset
        
    }
    

    you will also need this math extensions:

    extension CGPoint {
        
        init(_ size: CGSize) {
            self.init()
            self.x = size.width
            self.y = size.height
        }
        
        init(_ vector: SCNVector3) {
            self.init()
            self.x = CGFloat(vector.x)
            self.y = CGFloat(vector.y)
        }
        
        func distanceTo(_ point: CGPoint) -> CGFloat {
            return (self - point).length()
        }
        
        func length() -> CGFloat {
            return sqrt(self.x * self.x + self.y * self.y)
        }
        
        func midpoint(_ point: CGPoint) -> CGPoint {
            return (self + point) / 2
        }
        static func + (left: CGPoint, right: CGPoint) -> CGPoint {
            return CGPoint(x: left.x + right.x, y: left.y + right.y)
        }
        
        static func - (left: CGPoint, right: CGPoint) -> CGPoint {
            return CGPoint(x: left.x - right.x, y: left.y - right.y)
        }
        
        static func += (left: inout CGPoint, right: CGPoint) {
            left = left + right
        }
        
        static func -= (left: inout CGPoint, right: CGPoint) {
            left = left - right
        }
        
        static func / (left: CGPoint, right: CGFloat) -> CGPoint {
            return CGPoint(x: left.x / right, y: left.y / right)
        }
        
        static func * (left: CGPoint, right: CGFloat) -> CGPoint {
            return CGPoint(x: left.x * right, y: left.y * right)
        }
        
        static func /= (left: inout CGPoint, right: CGFloat) {
            left = left / right
        }
        
        static func *= (left: inout CGPoint, right: CGFloat) {
            left = left * right
        }
    }
    
    extension SCNVector3
    {
        static func + (left: SCNVector3, right: SCNVector3) -> SCNVector3 {
            return SCNVector3Make(left.x + right.x, left.y + right.y, left.z + right.z)
        }
        
        static func - (left: SCNVector3, right: SCNVector3) -> SCNVector3 {
            return SCNVector3Make(left.x - right.x, left.y - right.y, left.z - right.z)
        }
        
        static func * (vector: SCNVector3, scalar: Float) -> SCNVector3 {
            return SCNVector3Make(vector.x * scalar, vector.y * scalar, vector.z * scalar)
        }
        
        static func / (vector: SCNVector3, scalar: Float) -> SCNVector3 {
            if scalar == 0.0 { return SCNVector3() }
            return SCNVector3Make(vector.x / scalar, vector.y / scalar, vector.z / scalar)
        }
        
        func lengthSquared() -> Float {
            return x*x + y*y + z*z
        }
    
        func length() -> Float {
            return sqrtf(lengthSquared())
        }
    
        func normalize() -> SCNVector3 {
            let len:Float = 1.0 / sqrt(lengthSquared())
            return self * len
        }
        
        func distanceFrom(_ v: SCNVector3) -> Float {
            let dx = x - v.x
            let dy = y - v.y
            let dz = z - v.z
            return sqrt(dx*dx + dy*dy + dz*dz)
        }
        
        func minus(_ other:SCNVector3) -> SCNVector3 { return SCNVector3(x - other.x, y - other.y, z - other.z) }
        
        func normalized() -> SCNVector3 {
            let len = length()
            var ans = SCNVector3()
            ans.x = self.x / len
            ans.y = self.y / len
            ans.z = self.z / len
            return ans
        }
    }