Make nodes always face camera

Share on Twitter Share on Facebook Share on LinkedIn

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