In my previous blog post I discussed how to animate a node in a scene. Specifically, I animated a cube by rotating it continuously through 360 degrees on the Y axis. However, I originally wanted to animate a sphere, with a view to creating a rotating earth. In this blog post I’ll do just that.
The sample this code comes from can be found on GitHub.
Rotating earth
In order to add a sphere to the scene, I created a SphereNode
type that derives from SCNNode
:
using SceneKit;
using UIKit;
namespace ARKitFun.Nodes
{
public class SphereNode : SCNNode
{
public SphereNode(float size, string filename)
{
SCNNode node = new SCNNode
{
Geometry = CreateGeometry(size, filename),
Opacity = 0.975f
};
AddChildNode(node);
}
SCNGeometry CreateGeometry(float size, string filename)
{
SCNMaterial material = new SCNMaterial();
material.Diffuse.Contents = UIImage.FromFile(filename);
material.DoubleSided = true;
SCNSphere geometry = SCNSphere.Create(size);
geometry.Materials = new[] { material };
return geometry;
}
}
}
The SphereNode
constructor takes float
and string
arguments. The float
argument represents the size of the sphere, and the string
argument represents the filename of an image to overlay on the sphere. The constructor creates the material and geometry for the sphere, and adds the node as a child node to the SCNNode
. The power of ARKit is demonstrated by the CreateGeometry
method, which loads the supplied image and maps it onto the geometry as a material. The result is that a regular 2D rectangular image (in this case a map of the world) is automatically mapped onto the sphere geometry.
The ViewDidAppear
method in the ViewController
class can then be modified to add a SphereNode
to the scene:
using System;
using System.Linq;
using ARKit;
using ARKitFun.Extensions;
using ARKitFun.Nodes;
using CoreGraphics;
using SceneKit;
using UIKit;
namespace ARKitFun
{
public partial class ViewController : UIViewController
{
readonly ARSCNView sceneView;
const float size = 0.1f;
const float zPosition = -0.5f;
bool isAnimating;
float zAngle;
...
public override void ViewDidAppear(bool animated)
{
base.ViewDidAppear(animated);
sceneView.Session.Run(new ARWorldTrackingConfiguration
{
AutoFocusEnabled = true,
LightEstimationEnabled = true,
PlaneDetection = ARPlaneDetection.Horizontal,
WorldAlignment = ARWorldAlignment.Gravity
}, ARSessionRunOptions.ResetTracking | ARSessionRunOptions.RemoveExistingAnchors);
SphereNode sphereNode = new SphereNode(size, "world-map.jpg");
sphereNode.Position = new SCNVector3(0, 0, zPosition);
sceneView.Scene.RootNode.AddChildNode(sphereNode);
UIRotationGestureRecognizer rotationGestureRecognizer = new UIRotationGestureRecognizer(HandleRotateGesture);
sceneView.AddGestureRecognizer(rotationGestureRecognizer);
...
}
...
}
}
In this example, a SphereNode
is added to the scene and positioned at (0,0,-0.5). The SphereNode
constructor specifies a world map image that will be mapped to the geometry of the SCNNode
. In addition, a UIRotationGestureRecognizer
is added to the scene.
The following code example shows the HandleRotateGesture
method:
void HandleRotateGesture(UIRotationGestureRecognizer sender)
{
SCNView areaPanned = sender.View as SCNView;
CGPoint point = sender.LocationInView(areaPanned);
SCNHitTestResult[] hitResults = areaPanned.HitTest(point, new SCNHitTestOptions());
SCNHitTestResult hit = hitResults.FirstOrDefault();
if (hit != null)
{
SCNNode node = hit.Node;
zAngle += (float)(-sender.Rotation);
node.EulerAngles = new SCNVector3(node.EulerAngles.X, node.EulerAngles.Y, zAngle);
}
}
In this example, the node on which the rotate gesture was detected is determined. Then the node is rotated on the Z-axis by the rotation angle requested by the gesture.
The overall effect is that when the app runs, a SphereNode
that resembles the earth appears:
Tapping on the SphereNode
starts it rotating, and while rotating, tapping it a second time stops it rotating. In addition, the pinch gesture will resize the SphereNode
, and the rotate gesture enables the Z-axis of the SphereNode
to be manipulated.
In my next blog post I’ll discuss displaying a 3D model in a scene.
No comments:
Post a Comment