void SetupCamera() { SCNNode pov = GameView.PointOfView; const float altitude = 1f; const float distance = 10f; cameraYHandle = SCNNode.Create(); cameraXHandle = SCNNode.Create(); cameraYHandle.Position = new SCNVector3(0f, altitude, 0f); cameraYHandle.AddChildNode(cameraXHandle); GameView.Scene.RootNode.AddChildNode(cameraYHandle); pov.EulerAngles = new SCNVector3(0f, 0f, 0f); pov.Position = new SCNVector3(0f, 0f, distance); cameraYHandle.Rotation = new SCNVector4(0f, 1f, 0f, (float)Math.PI / 2f + (float)Math.PI / 4f * 3f); cameraXHandle.Rotation = new SCNVector4(1f, 0f, 0f, -(float)Math.PI / 4f * 0.125f); cameraXHandle.AddChildNode(pov); // Animate camera on launch and prevent the user from manipulating the camera until the end of the animation lockCamera = true; SCNTransaction.Begin(); SCNTransaction.SetCompletionBlock(() => { lockCamera = false; }); var cameraYAnimation = CABasicAnimation.FromKeyPath("rotation.w"); cameraYAnimation.From = NSNumber.FromDouble(Math.PI * 2 - cameraYHandle.Rotation.W); cameraYAnimation.To = NSNumber.FromDouble(0.0); cameraYAnimation.Additive = true; cameraYAnimation.BeginTime = CAAnimation.CurrentMediaTime() + 3; cameraYAnimation.FillMode = CAFillMode.Both; cameraYAnimation.Duration = 5.0; cameraYAnimation.TimingFunction = CAMediaTimingFunction.FromName(CAMediaTimingFunction.EaseInEaseOut); cameraYHandle.AddAnimation(cameraYAnimation, null); var cameraXAnimation = CABasicAnimation.FromKeyPath("rotation.w"); cameraXAnimation.From = NSNumber.FromDouble(-Math.PI / 2 + cameraXHandle.Rotation.W); cameraXAnimation.To = NSNumber.FromDouble(0.0); cameraXAnimation.Additive = true; cameraXAnimation.FillMode = CAFillMode.Both; cameraXAnimation.Duration = 5.0; cameraXAnimation.BeginTime = CAAnimation.CurrentMediaTime() + 3; cameraXAnimation.TimingFunction = CAMediaTimingFunction.FromName(CAMediaTimingFunction.EaseInEaseOut); cameraXHandle.AddAnimation(cameraXAnimation, null); SCNTransaction.Commit(); var lookAtConstraint = SCNLookAtConstraint.Create(Character.Node.FindChildNode("Bip001_Head", true)); lookAtConstraint.InfluenceFactor = 0; pov.Constraints = new SCNConstraint[] { lookAtConstraint }; }
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 SetupSlide(PresentationViewController presentationViewController) { TextManager.SetTitle("Constraints"); TextManager.SetSubtitle("SCNIKConstraint"); TextManager.AddBulletAtLevel("Inverse Kinematics", 0); TextManager.AddBulletAtLevel("Node chain", 0); TextManager.AddBulletAtLevel("Target", 0); //load the hero Hero = Utils.SCAddChildNode(GroundNode, "heroGroup", "Scenes.scnassets/hero/hero", 12); Hero.Position = new SCNVector3(0, 0, 5); Hero.Rotation = new SCNVector4(1, 0, 0, -(nfloat)Math.PI / 2); //hide the sword var sword = Hero.FindChildNode("sword", true); sword.Hidden = true; //load attack animation var path = NSBundle.MainBundle.PathForResource("Scenes.scnassets/hero/attack", "dae"); var source = SCNSceneSource.FromUrl(NSUrl.FromFilename(path), (NSDictionary)null); Attack = (CAAnimation)source.GetEntryWithIdentifier("attackID", new Class("CAAnimation")); Attack.RepeatCount = 0; Attack.FadeInDuration = 0.1f; Attack.FadeOutDuration = 0.3f; Attack.Speed = 0.75f; Attack.AnimationEvents = new SCNAnimationEvent[] { SCNAnimationEvent.Create(0.55f, (CAAnimation animation, NSObject animatedObject, bool playingBackward) => { if (IkActive) { DestroyTarget(); } }) }; AnimationDuration = Attack.Duration; //setup IK var hand = Hero.FindChildNode("Bip01_R_Hand", true); var clavicle = Hero.FindChildNode("Bip01_R_Clavicle", true); var head = Hero.FindChildNode("Bip01_Head", true); Ik = SCNIKConstraint.Create(clavicle); hand.Constraints = new SCNConstraint[] { Ik }; Ik.InfluenceFactor = 0.0f; //add target Target = SCNNode.Create(); Target.Position = new SCNVector3(-4, 7, 10); Target.Opacity = 0; Target.Geometry = SCNPlane.Create(2, 2); Target.Geometry.FirstMaterial.Diffuse.Contents = new NSImage(NSBundle.MainBundle.PathForResource("Images/target", "png")); GroundNode.AddChildNode(Target); //look at LookAt = SCNLookAtConstraint.Create(Target); LookAt.InfluenceFactor = 0; head.Constraints = new SCNConstraint[] { LookAt }; ((SCNView)presentationViewController.View).WeakSceneRendererDelegate = this; }
public override void ViewDidLoad() { base.ViewDidLoad(); // Perform any additional setup after loading the view, typically from a nib. var scene = new SCNScene(); var rnd = new Random(); Func <int, int, bool, float> random = (min, max, clamp) => { float num = (float)((double)rnd.Next(min, max) * rnd.NextDouble()); if (!clamp) { return(num); } else if (num < 1.0f) { return(1.0f); } else { return(num); } }; Enumerable.Range(0, 200).Select <int, int> ((i) => Building( random(2, 5, true), random(2, 5, true), random(2, 10, true), random(-20, 20, false), random(-20, 20, false), scene, rnd )).ToArray(); //Lights! var lightNode = new SCNNode() { Light = new SCNLight(), Position = new SCNVector3(30.0F, 20.0F, 60.0F) }; lightNode.Light.LightType = SCNLightType.Omni; scene.RootNode.AddChildNode(lightNode); var ambientLightNode = new SCNNode() { Light = new SCNLight() }; ambientLightNode.Light.LightType = SCNLightType.Ambient; ambientLightNode.Light.Color = UIColor.DarkGray; scene.RootNode.AddChildNode(ambientLightNode); //Camera! var cameraNode = new SCNNode() { Camera = new SCNCamera() }; scene.RootNode.AddChildNode(cameraNode); cameraNode.Position = new SCNVector3(0.0F, 10.0F, 20.0F); var targetNode = new SCNNode() { Position = new SCNVector3(00.0F, 1.5F, 0.0F) }; scene.RootNode.AddChildNode(targetNode); var lc = SCNLookAtConstraint.Create(targetNode); cameraNode.Constraints = new[] { lc }; var scnView = new SCNView(UIScreen.MainScreen.Bounds) { Scene = scene, AllowsCameraControl = true, ShowsStatistics = true, BackgroundColor = UIColor.FromRGB(52, 152, 219) }; var floorNode = new SCNNode { Geometry = new SCNPlane { Height = 40.0F, Width = 40.0F }, Position = SCNVector3.Zero }; var pi2 = Math.PI / 2.0; floorNode.Orientation = SCNQuaternion.FromAxisAngle(SCNVector3.UnitX, (float)(0.0 - pi2)); scene.RootNode.AddChildNode(floorNode); var material = new SCNMaterial(); material.Diffuse.Contents = UIImage.FromFile("Content/road.jpg"); material.Diffuse.ContentsTransform = SCNMatrix4.Scale(new SCNVector3(10.0f, 10.0f, 1.0f)); material.Diffuse.MinificationFilter = SCNFilterMode.Linear; material.Diffuse.MagnificationFilter = SCNFilterMode.Linear; material.Diffuse.MipFilter = SCNFilterMode.Linear; material.Diffuse.WrapS = SCNWrapMode.Repeat; material.Diffuse.WrapT = SCNWrapMode.Repeat; material.Specular.Contents = UIColor.Gray; floorNode.Geometry.FirstMaterial = material; this.View = scnView; }
public override void PresentStep(int index, PresentationViewController presentationViewController) { switch (index) { case 0: break; case 1: TextManager.HighlightBullet(0); StaticShadowNode.Opacity = 1; var node = TextManager.AddCode("#aMaterial.#multiply#.contents = aShadowMap;#"); node.Position = new SCNVector3(node.Position.X, node.Position.Y - 4, node.Position.Z); foreach (var child in node.ChildNodes) { child.RenderingOrder = 1; foreach (var m in child.Geometry.Materials) { m.ReadsFromDepthBuffer = false; } } break; case 2: //move the tree PalmTree.RunAction(SCNAction.RotateBy(0, NMath.PI * 4, 0, 8)); break; case 3: TextManager.FadesIn = true; TextManager.FadeOutText(SlideTextManager.TextType.Code); TextManager.AddEmptyLine(); node = TextManager.AddCode("#aLight.#castsShadow# = YES;#"); foreach (SCNNode child in node.ChildNodes) { child.RenderingOrder = 1; foreach (SCNMaterial m in child.Geometry.Materials) { m.ReadsFromDepthBuffer = false; m.WritesToDepthBuffer = false; } } node.Position = new SCNVector3(node.Position.X, node.Position.Y - 6, node.Position.Z); SCNTransaction.Begin(); SCNTransaction.AnimationDuration = 0.75f; var spot = presentationViewController.SpotLight; OldSpotShadowColor = spot.Light.ShadowColor; spot.Light.ShadowColor = NSColor.Black; spot.Light.ShadowRadius = 3; var tp = TextManager.TextNode.Position; var superNode = presentationViewController.CameraNode.ParentNode.ParentNode; var p0 = GroundNode.ConvertPositionToNode(SCNVector3.Zero, null); var p1 = GroundNode.ConvertPositionToNode(new SCNVector3(20, 0, 0), null); var tr = new SCNVector3(p1.X - p0.X, p1.Y - p0.Y, p1.Z - p0.Z); var p = superNode.Position; p.X += tr.X; p.Y += tr.Y; p.Z += tr.Z; tp.X += 20; tp.Y += 0; tp.Z += 0; superNode.Position = p; TextManager.TextNode.Position = tp; SCNTransaction.Commit(); TextManager.HighlightBullet(1); break; case 4: //move the light var lightPivot = SCNNode.Create(); lightPivot.Position = Character.Position; GroundNode.AddChildNode(lightPivot); spot = presentationViewController.SpotLight; OldSpotPosition = spot.Position; OldSpotParent = spot.ParentNode; OldSpotZNear = spot.Light.ZNear; spot.Light.ZNear = 20; spot.Position = lightPivot.ConvertPositionFromNode(spot.Position, spot.ParentNode); lightPivot.AddChildNode(spot); //add an object to represent the light var lightModel = SCNNode.Create(); var lightHandle = SCNNode.Create(); var cone = SCNCone.Create(0, 0.5f, 1); cone.RadialSegmentCount = 10; cone.HeightSegmentCount = 5; lightModel.Geometry = cone; lightModel.Geometry.FirstMaterial.Emission.Contents = NSColor.Yellow; lightHandle.Position = new SCNVector3(spot.Position.X * DIST, spot.Position.Y * DIST, spot.Position.Z * DIST); lightModel.CastsShadow = false; lightModel.EulerAngles = new SCNVector3(NMath.PI / 2, 0, 0); lightHandle.AddChildNode(lightModel); lightHandle.Constraints = new SCNConstraint[] { SCNLookAtConstraint.Create(Character) }; lightPivot.AddChildNode(lightHandle); LightHandle = lightHandle; var animation = CABasicAnimation.FromKeyPath("eulerAngles.z"); animation.From = new NSNumber((nfloat)(Math.PI / 4) * 1.7f); animation.To = new NSNumber((nfloat)(-Math.PI / 4) * 0.3f); animation.Duration = 4; animation.AutoReverses = true; animation.RepeatCount = float.MaxValue; animation.TimingFunction = CAMediaTimingFunction.FromName(CAMediaTimingFunction.EaseInEaseOut); animation.TimeOffset = animation.Duration / 2; lightPivot.AddAnimation(animation, new NSString("lightAnim")); break; case 5: TextManager.FadeOutText(SlideTextManager.TextType.Code); var text = TextManager.AddCode("#aLight.#shadowMode# =\n#SCNShadowModeModulated#;\naLight.#gobo# = anImage;#"); text.Position = new SCNVector3(text.Position.X, text.Position.Y - 6, text.Position.Z); text.EnumerateChildNodes((SCNNode child, out bool stop) => { stop = false; child.RenderingOrder = 1; foreach (var m in child.Geometry.Materials) { m.ReadsFromDepthBuffer = false; m.WritesToDepthBuffer = false; } return(stop); }); LightHandle.RemoveFromParentNode(); RestoreSpotPosition(presentationViewController); TextManager.HighlightBullet(2); spot = presentationViewController.SpotLight; spot.Light.CastsShadow = false; var head = Character.FindChildNode("Bip001_Pelvis", true); node = SCNNode.Create(); node.Light = SCNLight.Create(); node.Light.LightType = SCNLightType.Spot; node.Light.SpotOuterAngle = 30; node.Constraints = new SCNConstraint[] { SCNLookAtConstraint.Create(head) }; node.Position = new SCNVector3(0, 220, 0); node.Light.ZNear = 10; node.Light.ZFar = 1000; node.Light.Gobo.Contents = new NSImage(NSBundle.MainBundle.PathForResource("SharedTextures/blobShadow", "jpg")); node.Light.Gobo.Intensity = 0.65f; node.Light.ShadowMode = SCNShadowMode.Modulated; //exclude character from shadow node.Light.CategoryBitMask = 0x1; Character.FindNodes((SCNNode child, out bool stop) => { stop = false; child.CategoryBitMask = 0x2; return(stop); }); Projector = node; Character.AddChildNode(node); break; } }