Cristiano Coelho
Cristiano Coelho

Reputation: 1735

ARKit get ARPlaneAnchor vertices world coordinates

I'm trying to get each one of the 4 ARPlaneAnchor vertices/edges world coordinates. The reason to use world coordinates, is that I already have functions/code to place nodes from hit tests, and I want to place nodes using the same logic.

Basically, ARPlaneAnchor only has 2D relative positions (relative to its SCNNode), and I'm trying to convert the position of each of the plane's vertices to world coordinates, and then use those coordinates (x,y,z) to place a new SCNNode/sphere there.

I do NOT want to add children to the anchor's node and use the anchor's center to place it, as this node will change over time.

Upvotes: 0

Views: 665

Answers (1)

Cristiano Coelho
Cristiano Coelho

Reputation: 1735

Figured out after some work. One would expect all this math to be done by ARKit... If someone finds a better implementation, please let me know!

// helper to create a translation matrix
func translateTransform(_ x: Float, _ y: Float, _ z: Float) -> float4x4 {
    var tf = float4x4(diagonal: SIMD4<Float>(repeating: 1))
    tf.columns.3 = SIMD4<Float>(x: x, y: y, z: z, w: 1)
    return tf
}

@available(iOS 13.0, *)
extension ARPlaneAnchor {
    
    // returns all 4 world coordinates of the given plane
    // (topLeft, topRight, bottomLeft, bottomRight)
    func worldPoints() -> (SCNVector3, SCNVector3, SCNVector3, SCNVector3) {
        
        // Get world's updated center
        let worldTransform = transform * translateTransform(center.x, 0, center.z)
        
        let width = extent.x
        let height = extent.z

        let topLeft = worldTransform * translateTransform(-width / 2.0, 0, -height / 2.0)
        let topRight = worldTransform * translateTransform(width / 2.0, 0, -height / 2.0)
        let bottomLeft = worldTransform * translateTransform(-width / 2.0, 0, height / 2.0)
        let bottomRight = worldTransform * translateTransform(width / 2.0, 0, height / 2.0)

       
        let pointTopLeft = SCNVector3(
            x: topLeft.columns.3.x,
            y: topLeft.columns.3.y,
            z: topLeft.columns.3.z
        )

        let pointTopRight = SCNVector3(
            x: topRight.columns.3.x,
            y: topRight.columns.3.y,
            z: topRight.columns.3.z
        )

        let pointBottomLeft = SCNVector3(
            x: bottomLeft.columns.3.x,
            y: bottomLeft.columns.3.y,
            z: bottomLeft.columns.3.z
        )

        let pointBottomRight = SCNVector3(
            x: bottomRight.columns.3.x,
            y: bottomRight.columns.3.y,
            z: bottomRight.columns.3.z
        )
        
        return (
            pointTopLeft,
            pointTopRight,
            pointBottomLeft,
            pointBottomRight
        )
    }
}

Upvotes: 3

Related Questions