Lighting and shadows

Share on Twitter Share on Facebook Share on LinkedIn

Lighting and shadows

Description

In order to make objects in your Augmented Reality scene look real, you will have to think about lighting.

It is only because of light and shadows that we are able to understand where something is. Think about how many times you have reached for a glass of water in a poorly lit room and knocked it over. By accomodating for lighting and having our AR objects cast a shadow, they begin to look more real.

In this example we create an instance of SCNLight that emits a directional light.
We are using basic plane detection to detect the floor and place a plane using a special material with a LightingModel of SCNLightingModel.ShadowOnly to cast the shadows.

Credit

I had a hard time trying to find the relevant swift/xcode samples to show this effect in C#. After three evenings trying to get it working Romain finally showed me the swift code to achieve what I wanted. This example is just his code converted to C#, so I am very grateful to him.


Video


Code

using System;
using ARKit;
using Foundation;
using SceneKit;
using UIKit;

namespace XamarinArkitSample
{
    public partial class ViewController : UIViewController, IARSCNViewDelegate
    {
        private readonly ARSCNView sceneView;

        public ViewController(IntPtr handle) : base(handle)
        {
            this.sceneView = new ARSCNView
            {
                AutoenablesDefaultLighting = true,
                AutomaticallyUpdatesLighting = true,
                Delegate = this
            };

            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);

            var configuration = new ARWorldTrackingConfiguration
            {
                AutoFocusEnabled = true,
                PlaneDetection = ARPlaneDetection.Horizontal,
                LightEstimationEnabled = true,
                WorldAlignment = ARWorldAlignment.Gravity,
                EnvironmentTexturing = AREnvironmentTexturing.Automatic
            };

            this.sceneView.Session.Run(configuration);

            var light = SCNLight.Create();
            light.LightType = SCNLightType.Directional;
            light.Intensity = 2000f;
            light.ShadowColor = UIColor.Black.ColorWithAlpha(0.5f);
            light.ShadowRadius = 4;
            light.ShadowSampleCount = 4;
            light.CastsShadow = true;

            var lightNode = new SCNNode();
            lightNode.Light = light;
            lightNode.EulerAngles = new SCNVector3((float)-Math.PI / 2, 0, 0);

            var cube = SCNBox.Create(0.1f, 0.1f, 0.1f, 0.02f);
            var metal = SCNMaterial.Create();
            metal.LightingModelName = SCNLightingModel.PhysicallyBased;
            metal.Roughness.Contents = new NSNumber(0.1);
            metal.Metalness.Contents = new NSNumber(1);
            cube.FirstMaterial = metal;

            var cubeNode = new SCNNode();
            cubeNode.Geometry = cube;
            cubeNode.CastsShadow = true;

            this.sceneView.Scene.RootNode.AddChildNode(lightNode);
            this.sceneView.Scene.RootNode.AddChildNode(cubeNode);
        }

        [Export("renderer:didUpdateNode:forAnchor:")]
        public void DidUpdateNode(ISCNSceneRenderer renderer, SCNNode node, ARAnchor anchor)
        {
            if (anchor is ARPlaneAnchor planeAnchor)
            {
                var plane = ARSCNPlaneGeometry.Create(sceneView.Device);
                plane.Update(planeAnchor.Geometry);
                plane.FirstMaterial.LightingModelName = SCNLightingModel.ShadowOnly;
                node.Geometry = plane;
                node.CastsShadow = false;
            }
        }

        public override void ViewDidDisappear(bool animated)
        {
            base.ViewDidDisappear(animated);

            this.sceneView.Session.Pause();
        }   
    }
}

Next Step : Coaching overlay

After you have mastered this you should try Coaching overlay