Make nodes always face camera
Description
This is a neat trick if your goal is to have certain nodes in your scene always face the camera. The alternative is to do the maths to work out the angle at which to to rotate the nodes..
Video
No video yet
Code
using ARKit;
using Foundation;
using SceneKit;
using System;
using UIKit;
namespace XamarinArkitSample
{
public partial class ViewController : UIViewController
{
private readonly ARSCNView sceneView;
public ViewController(IntPtr handle) : base(handle)
{
this.sceneView = new ARSCNView
{
AutoenablesDefaultLighting = true,
DebugOptions = ARSCNDebugOptions.ShowFeaturePoints
| ARSCNDebugOptions.ShowWorldOrigin
};
this.View.AddSubview(this.sceneView);
}
public override void ViewDidLoad()
{
base.ViewDidLoad();
this.sceneView.Frame = this.View.Frame;
}
public override void ViewDidAppear(bool animated)
{
base.ViewDidAppear(animated);
this.sceneView.Session.Run(new ARWorldTrackingConfiguration
{
AutoFocusEnabled = true,
PlaneDetection = ARPlaneDetection.Horizontal,
LightEstimationEnabled = true,
WorldAlignment = ARWorldAlignment.GravityAndHeading
}, ARSessionRunOptions.ResetTracking | ARSessionRunOptions.RemoveExistingAnchors);
var size = 0.6f;
var distanceAway = 1f;
// Front
var frontPlane = new PlaneNode(size, "https://images.unsplash.com/photo-1532264043222-be99c0b73c8e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1400&q=80")
{
Position = new SCNVector3(distanceAway, 0, 0)
};
this.sceneView.Scene.RootNode.AddChildNode(frontPlane);
// Back
var backPlane = new PlaneNode(size, "https://images.unsplash.com/photo-1567312588623-8cc94e2c31bc?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1400&q=80")
{
Position = new SCNVector3(-distanceAway, 0, 0)
};
this.sceneView.Scene.RootNode.AddChildNode(backPlane);
// Right
var rightPlane = new PlaneNode(size, "https://images.unsplash.com/photo-1552914953-938eef0ce926?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1400&q=80")
{
Position = new SCNVector3(0, 0, distanceAway)
};
this.sceneView.Scene.RootNode.AddChildNode(rightPlane);
// Left
var leftPlane = new PlaneNode(size, "https://images.unsplash.com/photo-1578294178279-bb0fac077249?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1422&q=80")
{
Position = new SCNVector3(0, 0, -distanceAway)
};
this.sceneView.Scene.RootNode.AddChildNode(leftPlane);
// Above
var abovePlane = new PlaneNode(size, "https://images.unsplash.com/photo-1571771894821-ce9b6c11b08e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1400&q=80")
{
Position = new SCNVector3(0, distanceAway, 0)
};
this.sceneView.Scene.RootNode.AddChildNode(abovePlane);
// Below
var belowPlane = new PlaneNode(size, "https://images.unsplash.com/photo-1554444510-592779e6e009?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1400&q=80")
{
Position = new SCNVector3(0, -distanceAway, 0)
};
this.sceneView.Scene.RootNode.AddChildNode(belowPlane);
}
public override void ViewDidDisappear(bool animated)
{
base.ViewDidDisappear(animated);
this.sceneView.Session.Pause();
}
public override void DidReceiveMemoryWarning()
{
base.DidReceiveMemoryWarning();
}
}
public class PlaneNode : SCNNode
{
public PlaneNode(float size, string url)
{
var rootNode = new SCNNode
{
Geometry = CreateGeometry(size, url),
// Lesson: Makes the node always face the camera
Constraints = new[] { new SCNBillboardConstraint() }
};
AddChildNode(rootNode);
}
private static SCNGeometry CreateGeometry(float size, string url)
{
var image = FromUrl(url);
var material = new SCNMaterial();
material.Diffuse.Contents = image;
material.DoubleSided = true;
var geometry = SCNPlane.Create(size, size);
geometry.Materials = new[] { material };
return geometry;
}
private static UIImage FromUrl(string uri)
{
using (var url = new NSUrl(uri))
using (var data = NSData.FromUrl(url))
return UIImage.LoadFromData(data);
}
}
}
Next Step : Touch detection
After you have mastered this you should try Touch detection