// Load movies and display movie layers private AVPlayerLayer ConfigurePlayer(string movieName, string hostingNodeName) { var player = AVPlayer.FromUrl(NSUrl.FromFilename(movieName)); player.ActionAtItemEnd = AVPlayerActionAtItemEnd.None; // loop NSNotificationCenter.DefaultCenter.AddObserver(this, new Selector("PlayerItemDidReachEnd"), AVPlayerItem.DidPlayToEndTimeNotification, player.CurrentItem); player.Play(); // Set an arbitrary frame. This frame will be the size of our movie texture so if it is too small it will appear scaled up and blurry, and if it is too big it will be slow var playerLayer = new AVPlayerLayer(); playerLayer.Player = player; playerLayer.ContentsGravity = AVPlayerLayer.GravityResizeAspectFill; playerLayer.Frame = new CGRect(0, 0, 600, 800); // Use a parent layer with a background color set to black // That way if the movie is stil loading and the frame is transparent, we won't see holes in the model var backgroundLayer = CALayer.Create(); backgroundLayer.BackgroundColor = NSColor.Black.CGColor; backgroundLayer.Frame = new CGRect(0, 0, 600, 800); backgroundLayer.AddSublayer(playerLayer); var frameNode = ContentNode.FindChildNode(hostingNodeName, true); var material = frameNode.Geometry.FirstMaterial; material.Diffuse.Contents = backgroundLayer; return(playerLayer); }
public override void PresentStep(int index, PresentationViewController presentationViewController) { SCNTransaction.Begin(); switch (index) { case 0: break; case 1: // Switch to camera1 SCNTransaction.AnimationDuration = 2.0f; ((SCNView)presentationViewController.View).PointOfView = ContentNode.FindChildNode("camera1", true); break; case 2: // Switch to camera2 SCNTransaction.AnimationDuration = 2.0f; ((SCNView)presentationViewController.View).PointOfView = ContentNode.FindChildNode("camera2", true); break; case 3: // Switch back to the default camera SCNTransaction.AnimationDuration = 1.0f; ((SCNView)presentationViewController.View).PointOfView = presentationViewController.CameraNode; break; } SCNTransaction.Commit(); }
public override void PresentStep(int index, PresentationViewController presentationViewController) { switch (index) { case 0: // Set the slide's title and subtitle and add some text TextManager.SetTitle("Materials"); TextManager.SetSubtitle("CALayer as texture"); TextManager.AddCode("#// Map a layer tree on a 3D object. \n" + "aNode.Geometry.FirstMaterial.Diffuse.#Contents# = #aLayerTree#;#"); // Add the model var intermediateNode = SCNNode.Create(); intermediateNode.Position = new SCNVector3(0, 3.9f, 8); intermediateNode.Rotation = new SCNVector4(1, 0, 0, -(float)(Math.PI / 2)); GroundNode.AddChildNode(intermediateNode); Utils.SCAddChildNode(intermediateNode, "frames", "Scenes/frames/frames", 8); presentationViewController.NarrowSpotlight(true); break; case 1: SCNTransaction.Begin(); SCNTransaction.AnimationDuration = 1; // Change the point of view to "frameCamera" (a camera defined in the "frames" scene) var frameCamera = ContentNode.FindChildNode("frameCamera", true); ((SCNView)presentationViewController.View).PointOfView = frameCamera; // The "frames" scene contains animations, update the end time of our main scene and start to play the animations ((SCNView)presentationViewController.View).Scene.SetAttribute(new NSNumber(7.33f), SCNScene.EndTimeAttributeKey); ((SCNView)presentationViewController.View).CurrentTime = 0; ((SCNView)presentationViewController.View).Playing = true; ((SCNView)presentationViewController.View).Loops = true; PlayerLayer1 = ConfigurePlayer(NSBundle.MainBundle.PathForResource("Movies/movie1", "mov"), "PhotoFrame-Vertical"); PlayerLayer2 = ConfigurePlayer(NSBundle.MainBundle.PathForResource("Movies/movie2", "mov"), "PhotoFrame-Horizontal"); SCNTransaction.Commit(); break; } }
public override void PresentStep(int index, PresentationViewController presentationViewController) { switch (index) { case 0: // Set the slide's title and subtitle and add some text TextManager.SetTitle("Constraints"); TextManager.SetSubtitle("SCNConstraint"); TextManager.AddBulletAtLevel("Applied sequentially at render time", 0); TextManager.AddBulletAtLevel("Only affect presentation values", 0); TextManager.AddCode("#aNode.#Constraints# = new SCNConstraint[] { aConstraint, anotherConstraint, ... };#"); // Tweak the near clipping plane of the spot light to get a precise shadow map presentationViewController.SpotLight.Light.SetAttribute(new NSNumber(10), SCNLightAttribute.ShadowNearClippingKey); break; case 1: // Remove previous text TextManager.FlipOutText(SlideTextManager.TextType.Subtitle); TextManager.FlipOutText(SlideTextManager.TextType.Bullet); TextManager.FlipOutText(SlideTextManager.TextType.Code); // Add new text TextManager.SetSubtitle("SCNLookAtConstraint"); TextManager.AddBulletAtLevel("Makes a node to look at another node", 0); TextManager.AddCode("#nodeA.Constraints = new SCNConstraint[] { #SCNLookAtConstraint.Create# (nodeB) };#"); TextManager.FlipInText(SlideTextManager.TextType.Subtitle); TextManager.FlipInText(SlideTextManager.TextType.Bullet); TextManager.FlipInText(SlideTextManager.TextType.Code); break; case 2: // Setup the scene SetupLookAtScene(); SCNTransaction.Begin(); SCNTransaction.AnimationDuration = 1; // Dim the text and move back a little bit TextManager.TextNode.Opacity = 0.5f; presentationViewController.CameraHandle.Position = presentationViewController.CameraNode.ConvertPositionToNode(new SCNVector3(0, 0, 5.0f), presentationViewController.CameraHandle.ParentNode); SCNTransaction.Commit(); break; case 3: // Add constraints to the arrows var container = ContentNode.FindChildNode("arrowContainer", true); // "Look at" constraint var constraint = SCNLookAtConstraint.Create(BallNode); var i = 0; foreach (var arrow in container.ChildNodes) { var delayInSeconds = 0.1 * i++; var popTime = new DispatchTime(DispatchTime.Now, (long)(delayInSeconds * Utils.NSEC_PER_SEC)); DispatchQueue.MainQueue.DispatchAfter(popTime, () => { SCNTransaction.Begin(); SCNTransaction.AnimationDuration = 1; // Animate to the result of applying the constraint ((SCNNode)arrow.ChildNodes [0]).Rotation = new SCNVector4(0, 1, 0, (float)(Math.PI / 2)); arrow.Constraints = new SCNConstraint[] { constraint }; SCNTransaction.Commit(); }); } break; case 4: // Create a keyframe animation to move the ball var animation = CAKeyFrameAnimation.FromKeyPath("position"); animation.KeyTimes = new NSNumber[] { 0.0f, (1.0f / 8.0f), (2.0f / 8.0f), (3.0f / 8.0f), (4.0f / 8.0f), (5.0f / 8.0f), (6.0f / 8.0f), (7.0f / 8.0f), 1.0f }; animation.Values = new NSObject[] { NSValue.FromVector(new SCNVector3(0, 0.0f, 0)), NSValue.FromVector(new SCNVector3(20.0f, 0.0f, 20.0f)), NSValue.FromVector(new SCNVector3(40.0f, 0.0f, 0)), NSValue.FromVector(new SCNVector3(20.0f, 0.0f, -20.0f)), NSValue.FromVector(new SCNVector3(0, 0.0f, 0)), NSValue.FromVector(new SCNVector3(-20.0f, 0.0f, 20.0f)), NSValue.FromVector(new SCNVector3(-40.0f, 0.0f, 0)), NSValue.FromVector(new SCNVector3(-20.0f, 0.0f, -20.0f)), NSValue.FromVector(new SCNVector3(0, 0.0f, 0)) }; animation.CalculationMode = CAAnimation.AnimationCubicPaced; // smooth the movement between keyframes animation.RepeatCount = float.MaxValue; animation.Duration = 10.0f; animation.TimingFunction = CAMediaTimingFunction.FromName(CAMediaTimingFunction.Linear); BallNode.AddAnimation(animation, new NSString("ballNodeAnimation")); // Rotate the ball to give the illusion of a rolling ball // We need two animations to do that: // - one rotation to orient the ball in the right direction // - one rotation to spin the ball animation = CAKeyFrameAnimation.FromKeyPath("rotation"); animation.KeyTimes = new NSNumber[] { 0.0f, (0.7f / 8.0f), (1.0f / 8.0f), (2.0f / 8.0f), (3.0f / 8.0f), (3.3f / 8.0f), (4.7f / 8.0f), (5.0f / 8.0f), (6.0f / 8.0f), (7.0f / 8.0f), (7.3f / 8.0f), 1.0f }; animation.Values = new NSObject[] { NSValue.FromVector(new SCNVector4(0, 1, 0, (float)(Math.PI / 4))), NSValue.FromVector(new SCNVector4(0, 1, 0, (float)(Math.PI / 4))), NSValue.FromVector(new SCNVector4(0, 1, 0, (float)(Math.PI / 2))), NSValue.FromVector(new SCNVector4(0, 1, 0, (float)(Math.PI))), NSValue.FromVector(new SCNVector4(0, 1, 0, (float)(Math.PI + Math.PI / 2))), NSValue.FromVector(new SCNVector4(0, 1, 0, (float)(Math.PI * 2 - Math.PI / 4))), NSValue.FromVector(new SCNVector4(0, 1, 0, (float)(Math.PI * 2 - Math.PI / 4))), NSValue.FromVector(new SCNVector4(0, 1, 0, (float)(Math.PI * 2 - Math.PI / 2))), NSValue.FromVector(new SCNVector4(0, 1, 0, (float)(Math.PI))), NSValue.FromVector(new SCNVector4(0, 1, 0, (float)(Math.PI - Math.PI / 2))), NSValue.FromVector(new SCNVector4(0, 1, 0, (float)(Math.PI / 4))), NSValue.FromVector(new SCNVector4(0, 1, 0, (float)(Math.PI / 4))) }; animation.RepeatCount = float.MaxValue; animation.Duration = 10.0f; animation.TimingFunction = CAMediaTimingFunction.FromName(CAMediaTimingFunction.Linear); BallNode.AddAnimation(animation, new NSString("ballNodeAnimation2")); var rotationAnimation = CABasicAnimation.FromKeyPath("rotation"); rotationAnimation.Duration = 1.0f; rotationAnimation.RepeatCount = float.MaxValue; rotationAnimation.To = NSValue.FromVector(new SCNVector4(1, 0, 0, (float)(Math.PI * 2))); BallNode.ChildNodes [1].AddAnimation(rotationAnimation, new NSString("ballNodeRotation")); break; case 5: // Add a constraint to the camera SCNTransaction.Begin(); SCNTransaction.AnimationDuration = 1; constraint = SCNLookAtConstraint.Create(BallNode); presentationViewController.CameraNode.Constraints = new SCNConstraint[] { constraint }; SCNTransaction.Commit(); break; case 6: // Add a constraint to the light SCNTransaction.Begin(); SCNTransaction.AnimationDuration = 1; var cameraTarget = ContentNode.FindChildNode("cameraTarget", true); constraint = SCNLookAtConstraint.Create(cameraTarget); presentationViewController.SpotLight.Constraints = new SCNConstraint[] { constraint }; SCNTransaction.Commit(); break; } }
public override void PresentStep(int index, PresentationViewController presentationViewController) { SCNTransaction.Begin(); switch (index) { case 0: // Set the slide's title and subtitle and add some text TextManager.SetTitle("Node Attributes"); TextManager.SetSubtitle("Camera"); TextManager.AddBulletAtLevel("Point of view for renderers", 0); // Start with the "sign" model hidden var group = ContentNode.FindChildNode("group", true); group.Scale = new SCNVector3(0, 0, 0); group.Hidden = true; break; case 1: // Reveal the model (unhide then scale) group = ContentNode.FindChildNode("group", true); SCNTransaction.Begin(); SCNTransaction.AnimationDuration = 0; group.Hidden = false; SCNTransaction.Commit(); SCNTransaction.AnimationDuration = 1.0f; group.Scale = new SCNVector3(1, 1, 1); break; case 2: TextManager.AddCode("#aNode.#Camera# = #SCNCamera#.Create (); \naView.#PointOfView# = aNode;#"); break; case 3: // Switch to camera1 SCNTransaction.AnimationDuration = 2.0f; ((SCNView)presentationViewController.View).PointOfView = ContentNode.FindChildNode("camera1", true); break; case 4: // Switch to camera2 SCNTransaction.AnimationDuration = 2.0f; ((SCNView)presentationViewController.View).PointOfView = ContentNode.FindChildNode("camera2", true); break; case 5: // On completion add some code SCNTransaction.SetCompletionBlock(() => { TextManager.FadesIn = true; TextManager.AddEmptyLine(); TextManager.AddCode("#aNode.#Camera#.XFov = angleInDegrees;#"); }); // Switch back to the default camera SCNTransaction.AnimationDuration = 1.0f; ((SCNView)presentationViewController.View).PointOfView = presentationViewController.CameraNode; break; case 6: // Switch to camera 3 SCNTransaction.AnimationDuration = 1.0f; var target = ContentNode.FindChildNode("camera3", true); // Don't let the default transition animate the FOV (we will animate the FOV separately) var wantedFOV = target.Camera.XFov; target.Camera.XFov = ((SCNView)presentationViewController.View).PointOfView.Camera.XFov; // Animate point of view with an ease-in/ease-out function SCNTransaction.Begin(); SCNTransaction.AnimationDuration = 1.0f; SCNTransaction.AnimationTimingFunction = CAMediaTimingFunction.FromName(CAMediaTimingFunction.EaseInEaseOut); ((SCNView)presentationViewController.View).PointOfView = target; SCNTransaction.Commit(); // Animate the FOV with the default timing function (for a better looking transition) SCNTransaction.Begin(); SCNTransaction.AnimationDuration = 1.0f; ((SCNView)presentationViewController.View).PointOfView.Camera.XFov = wantedFOV; SCNTransaction.Commit(); break; case 7: // Switch to camera 4 var cameraNode = ContentNode.FindChildNode("camera4", true); // Don't let the default transition animate the FOV (we will animate the FOV separately) wantedFOV = cameraNode.Camera.XFov; cameraNode.Camera.XFov = ((SCNView)presentationViewController.View).PointOfView.Camera.XFov; // Animate point of view with the default timing function SCNTransaction.Begin(); SCNTransaction.AnimationDuration = 1.0f; ((SCNView)presentationViewController.View).PointOfView = cameraNode; SCNTransaction.Commit(); // Animate the FOV with an ease-in/ease-out function SCNTransaction.Begin(); SCNTransaction.AnimationDuration = 1.0f; SCNTransaction.AnimationTimingFunction = CAMediaTimingFunction.FromName(CAMediaTimingFunction.EaseInEaseOut); ((SCNView)presentationViewController.View).PointOfView.Camera.XFov = wantedFOV; SCNTransaction.Commit(); break; case 8: // Quickly switch back to the default camera SCNTransaction.Begin(); SCNTransaction.AnimationDuration = 0.75f; ((SCNView)presentationViewController.View).PointOfView = presentationViewController.CameraNode; SCNTransaction.Commit(); break; } SCNTransaction.Commit(); }
public override void PresentStep(int index, PresentationViewController presentationViewController) { switch (index) { case 0: // Set the slide's title and subtitle and add some text TextManager.SetTitle("Performance"); TextManager.SetSubtitle("Copying"); TextManager.AddBulletAtLevel("Attributes are shared by default", 0); TextManager.AddBulletAtLevel("Unshare if needed", 0); TextManager.AddBulletAtLevel("Copying geometries is cheap", 0); break; case 1: // New "Node B" box var nodeB = Utils.SCBoxNode("Node B", new CGRect(-55, -36, 110, 50), GreenColor, 10, true); nodeB.Name = "nodeB"; nodeB.Position = new SCNVector3(140, 0, 0); nodeB.Opacity = 0; var nodeA = ContentNode.FindChildNode("nodeA", true); nodeA.AddChildNode(nodeB); // Arrow from "Root Node" to "Node B" var arrowNode = SCNNode.Create(); arrowNode.Geometry = SCNShape.Create(Utils.SCArrowBezierPath(new CGSize(140, 3), new CGSize(10, 14), 4, true), 0); arrowNode.Position = new SCNVector3(-130, 60, 0); arrowNode.Rotation = new SCNVector4(0, 0, 1, -(float)(Math.PI * 0.12f)); arrowNode.Geometry.FirstMaterial.Diffuse.Contents = GreenColor; nodeB.AddChildNode(arrowNode); // Arrow from "Node B" to the shared geometry arrowNode = SCNNode.Create(); arrowNode.Name = "arrow-shared-geometry"; arrowNode.Geometry = SCNShape.Create(Utils.SCArrowBezierPath(new CGSize(140, 3), new CGSize(10, 14), 4, false), 0); arrowNode.Position = new SCNVector3(0, -28, 0); arrowNode.Rotation = new SCNVector4(0, 0, 1, (float)(Math.PI * 1.12f)); arrowNode.Geometry.FirstMaterial.Diffuse.Contents = PurpleColor; nodeB.AddChildNode(arrowNode); // Reveal SCNTransaction.Begin(); SCNTransaction.AnimationDuration = 1; nodeB.Opacity = 1.0f; // Show the related code TextManager.AddCode("#// Copy a node \n" + "var nodeB = nodeA.#Copy# ();#"); SCNTransaction.Commit(); break; case 2: var geometryNodeA = ContentNode.FindChildNode("geometry", true); var oldArrowNode = ContentNode.FindChildNode("arrow-shared-geometry", true); // New "Geometry" box var geometryNodeB = Utils.SCBoxNode("Geometry", new CGRect(-55, -20, 110, 40), PurpleColor, 10, true); geometryNodeB.Position = new SCNVector3(140, 0, 0); geometryNodeB.Opacity = 0; geometryNodeA.AddChildNode(geometryNodeB); // Arrow from "Node B" to the new geometry arrowNode = SCNNode.Create(); arrowNode.Geometry = SCNShape.Create(Utils.SCArrowBezierPath(new CGSize(55, 3), new CGSize(10, 14), 4, false), 0); arrowNode.Position = new SCNVector3(0, 75, 0); arrowNode.Rotation = new SCNVector4(0, 0, 1, -(float)(Math.PI * 0.5f)); arrowNode.Geometry.FirstMaterial.Diffuse.Contents = PurpleColor; geometryNodeB.AddChildNode(arrowNode); // Arrow from the new geometry to "Material" arrowNode = SCNNode.Create(); arrowNode.Name = "arrow-shared-material"; arrowNode.Geometry = SCNShape.Create(Utils.SCArrowBezierPath(new CGSize(140, 3), new CGSize(10, 14), 4, true), 0); arrowNode.Position = new SCNVector3(-130, -80, 0); arrowNode.Rotation = new SCNVector4(0, 0, 1, (float)(Math.PI * 0.12f)); arrowNode.Geometry.FirstMaterial.Diffuse.Contents = RedColor; geometryNodeB.AddChildNode(arrowNode); // Reveal SCNTransaction.Begin(); SCNTransaction.AnimationDuration = 1; geometryNodeB.Opacity = 1.0f; oldArrowNode.Opacity = 0.0f; // Show the related code TextManager.AddEmptyLine(); TextManager.AddCode("#// Unshare geometry \n" + "nodeB.Geometry = nodeB.Geometry.#Copy# ();#"); SCNTransaction.Commit(); break; case 3: var materialANode = ContentNode.FindChildNode("material", true); oldArrowNode = ContentNode.FindChildNode("arrow-shared-material", true); // New "Material" box var materialBNode = Utils.SCBoxNode("Material", new CGRect(-55, -20, 110, 40), NSColor.Orange, 10, true); materialBNode.Position = new SCNVector3(140, 0, 0); materialBNode.Opacity = 0; materialANode.AddChildNode(materialBNode); // Arrow from the unshared geometry to the new material arrowNode = SCNNode.Create(); arrowNode.Geometry = SCNShape.Create(Utils.SCArrowBezierPath(new CGSize(55, 3), new CGSize(10, 14), 4, false), 0); arrowNode.Position = new SCNVector3(0, 75, 0); arrowNode.Rotation = new SCNVector4(0, 0, 1, -(float)(Math.PI * 0.5f)); arrowNode.Geometry.FirstMaterial.Diffuse.Contents = NSColor.Orange; materialBNode.AddChildNode(arrowNode); // Reveal SCNTransaction.Begin(); SCNTransaction.AnimationDuration = 1; materialBNode.Opacity = 1.0f; oldArrowNode.Opacity = 0.0f; SCNTransaction.Commit(); break; } }