I want to get the corner coordinates of a plane that ARKit has identified into the ARSCNView screen coordinates.
I've started by adapting Apple's example for creating the planes, so I have a Plane class:
class Plane : SCNNode {
var anchor : ARPlaneAnchor
init(anchor : ARPlaneAnchor) {
self.anchor = anchor
super.init()
self.geometry = SCNPlane(width: CGFloat(Float(anchor.extent.x)), height: CGFloat(anchor.extent.z))
self.rotation = SCNVector4Make(1.0, 0.0, 0.0, -Float.pi/2.0)
let material = SCNMaterial()
material.diffuse.contents = UIColor.yellow
material.specular.contents = UIColor.white
self.geometry?.firstMaterial = material
}
required init?(coder aDecoder: NSCoder) {
fatalError("Error")
}
func update(anchor: ARPlaneAnchor) {
self.anchor = anchor
if let plane = self.geometry as? SCNPlane {
plane.width = CGFloat(anchor.extent.x)
plane.height = CGFloat(anchor.extent.z)
}
}
}And the ARSCNViewDelegate methods in the view controller to identify and update it:
func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {
if let planeAnchor = anchor as? ARPlaneAnchor {
let plane = Plane(anchor: planeAnchor)
node.addChildNode(plane)
planes[planeAnchor] = plane
print("plane = \(plane)")
}
}
func renderer(_ renderer: SCNSceneRenderer, didUpdate node: SCNNode, for anchor: ARAnchor) {
if let planeAnchor = anchor as? ARPlaneAnchor {
planes[planeAnchor]?.update(anchor: planeAnchor)
}
}
func renderer(_ renderer: SCNSceneRenderer, didRemove node: SCNNode, for anchor: ARAnchor) {
if let planeAnchor = anchor as? ARPlaneAnchor {
planes.removeValue(forKey: planeAnchor)
}
}As I understand it, the plane has it's own local coordinate space in scene kit, so I want to to just create 4 SCNVector3 values, and convert them from the Plane's local space to the scene's world coordinate space, and from them, project them to the screen's space.
This is how I'm doing it:
func renderer(_ renderer: SCNSceneRenderer, updateAtTime time: TimeInterval) {
for (_, aPlane) in planes {
// Vectors representing the corners of the plane
let maxX = aPlane.anchor.extent.x/2.0
let minX = -maxX
let minY = aPlane.anchor.extent.z/2.0
let maxY = -minY
var point1 = SCNVector3Make(minX, 0.0, minY)
var point2 = SCNVector3Make(maxX, 0.0, minY)
var point3 = SCNVector3Make(maxX, 0.0, maxY)
var point4 = SCNVector3Make(minX, 0.0, maxY)
// var point1 = SCNVector3Make(minX, minY, 0.0)
// var point2 = SCNVector3Make(maxX, minY, 0.0)
// var point3 = SCNVector3Make(maxX, maxY, 0.0)
// var point4 = SCNVector3Make(minX, maxY, 0.0)
print("initial nodes ------------------")
print("point1 = \(point1)")
print("point2 = \(point2)")
print("point3 = \(point3)")
print("point4 = \(point4)")
// Get the root node and convert the coords from the plane's coord system
let rootNode = sceneView.scene.rootNode
point1 = rootNode.convertVector(point1, from: aPlane)
point2 = rootNode.convertVector(point2, from: aPlane)
point3 = rootNode.convertVector(point3, from: aPlane)
point4 = rootNode.convertVector(point4, from: aPlane)
print("first conversion nodes ------------------")
print("point1 = \(point1)")
print("point2 = \(point2)")
print("point3 = \(point3)")
print("point4 = \(point4)")
// Finally, project them to the screen view
point1 = sceneView.projectPoint(point1)
point2 = sceneView.projectPoint(point2)
point3 = sceneView.projectPoint(point3)
point4 = sceneView.projectPoint(point4)
print("final conversion nodes ------------------")
print("point1 = \(point1)")
print("point2 = \(point2)")
print("point3 = \(point3)")
print("point4 = \(point4)")
}
}However, whatever I do, when I have a plane in full view, I still get coordinates outside the bounds of the view. I'm pretty sure it's something simple, but I've tried many combinations now