So let’s talk plane detection with ARKit and SpriteKit . You might be tempted to set the ARWorldTrackingConfiguration to detect planes in the Scene.swift file. If you did, it would look like this
1 2 3 4 5 6 7 8 9 10 11 |
override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) // Create a session configuration let configuration = ARWorldTrackingConfiguration() configuration.planeDetection = .horizontal //(added this line) which configures AUTOMATIC plane detection // Run the view's session sceneView.session.run(configuration) } |
But if you’re using SpriteKit commenting out that configuration.planeDetection line is probably a good idea to start. It doesn’t mean that you can’t ever detect planes, it just means it won’t detect them automatically. In SpriteKit you’ll never be able to lay a sprite flat on a table and look at it like a piece of paper changing it’s perspective in space. To do that you’d need to work with SceneKit which would support adding a 3d plane to the world, lying that on an AR-detected horizontal plane (or upright), and then texturing the plane with your image. Planes can even be textured with SpriteKit scenes, which is how this was put together in the WWDC demo…
Granted that’s a vertical plane laying on the table, but hopefully you get the point.
Let’s Talk Billboarding Real Quick…
SpriteKit instead “billboards” the sprites you see in the augmented reality space, which means the image is always facing directly at the viewer. So if your art was a perfect square with 4 equal sides, you’ll always see it as a perfect 4 sided square, with no perspective shift.
Hopefully that didn’t blow your mind too hard and make you rethink using SpriteKit and ARKit altogether. Embrace billboarding, because at times, that’s exactly what you want. Certainly so with 2D art and animations. For my first ARKit app, it would have looked weirder to see 2D cartoons changing perspective. Here’s an example…
Notice how the birds aren’t awkwardly tilting perspective as if they were stuck to a piece of paper. You don’t even really notice it, but they are always facing directly at you.
Checking for Horizontal Planes As Needed
So in my Tooniverse app (seen above) every time the user tosses a ball, at a certain point, the game checks to see if the ball should appear to just let gravity take over and fall down OR if it should appear to ricochet off a flat surface (both cases assume the ball didn’t hit a bird). Here’s the code for that…
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
guard let sceneView = self.view as? ARSKView else { return } //create an array of planes at a CGPoint represented by x:0.5, y:0.5, //In other words, dead center in the middle of the screen //you could exclude estimatedHorizontalPlane, existingPlane, or existingPlaneUsingExtent. //Just include at least one type. let hitTestArray = sceneView.hitTest(CGPoint(x: 0.5, y:0.5), types: [.estimatedHorizontalPlane, .existingPlane, .existingPlaneUsingExtent]) if(hitTestArray.count > 0) { //If the hitTestArray count is more than 0, than we've hit at least one type of plane. //Here is where I would do something to react to hitting a plane } |
You’ll notice once I have the hitTestArray above, I don’t do much with it. I just check to see if it’s greater than 0, meaning it hit at least one plane. But we could iterate through the results in the hitTestArray, like so…
1 2 3 4 5 6 7 |
for result in hitTestArray { //find out the distance of the plane from the viewer... print(result.distance) //find out the type... print(result.type) } |
And obviously you can just start typing “result.” and see for yourself all the possible properties of the result. For example…
1 |
result.anchor |
…That would be the anchor representing the detected surface, if any.