private void Open() { if (IsOpen || IsAnimating) { return; } // Open animation SCNTransaction.Begin(); SCNTransaction.AnimationTimingFunction = CAMediaTimingFunction.FromName(CAMediaTimingFunction.EaseOut); SCNTransaction.AnimationDuration = AnimationDuration / 4f; FocusSquareNode().Opacity = 1.0f; foreach (var segment in Segments) { segment.Open(); } SCNTransaction.SetCompletionBlock(() => { FocusSquareNode().RunAction(PulseAction(), "pulse"); }); SCNTransaction.Commit(); // Scale/bounce animation SCNTransaction.Begin(); SCNTransaction.AnimationTimingFunction = CAMediaTimingFunction.FromName(CAMediaTimingFunction.EaseOut); SCNTransaction.AnimationDuration = AnimationDuration / 4f; FocusSquareNode().SetUniformScale(FocusSquareSize); SCNTransaction.Commit(); IsOpen = true; }
private void PerformOpenAnimation() { if (!this.isBorderOpen && !this.isAnimating) { this.isBorderOpen = true; this.isAnimating = true; // Open animation SCNTransaction.Begin(); SCNTransaction.AnimationDuration = GameBoard.AnimationDuration / 4f; SCNTransaction.AnimationTimingFunction = CAMediaTimingFunction.FromName(CAMediaTimingFunction.EaseOut); this.borderNode.Opacity = 1f; foreach (var segment in this.borderSegments) { segment.Open(); } this.Scale = new SCNVector3(GameBoard.MinimumScale, GameBoard.MinimumScale, GameBoard.MinimumScale); // completion is run on main-thread SCNTransaction.SetCompletionBlock(() => { SCNTransaction.Begin(); this.borderNode.RunAction(this.PulseAction(), "pulse"); this.isAnimating = false; SCNTransaction.Commit(); }); SCNTransaction.Commit(); } }
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 }; }
private void Close(bool flash = false) { if (!IsOpen || IsAnimating) { return; } IsAnimating = true; StopPulsing(FocusSquareNode()); // Close animation SCNTransaction.Begin(); SCNTransaction.AnimationTimingFunction = CAMediaTimingFunction.FromName(CAMediaTimingFunction.EaseOut); SCNTransaction.AnimationDuration = AnimationDuration / 2f; FocusSquareNode().Opacity = 0.99f; SCNTransaction.SetCompletionBlock(() => { SCNTransaction.Begin(); SCNTransaction.AnimationTimingFunction = CAMediaTimingFunction.FromName(CAMediaTimingFunction.EaseOut); SCNTransaction.AnimationDuration = AnimationDuration / 4f; foreach (var segment in segments) { segment.Close(); } SCNTransaction.SetCompletionBlock(() => { IsAnimating = false; }); SCNTransaction.Commit(); }); SCNTransaction.Commit(); // Scale/bounce animation FocusSquareNode().AddAnimation(ScaleAnimation("transform.scale.x"), "transform.scale.y"); FocusSquareNode().AddAnimation(ScaleAnimation("transform.scale.y"), "transform.scale.y"); FocusSquareNode().AddAnimation(ScaleAnimation("transform.scale.z"), "transform.scale.z"); // Flash? if (flash) { var waitAction = SCNAction.Wait(AnimationDuration * 0.75f); var fadeInAction = SCNAction.FadeOpacityTo(0.25f, AnimationDuration * 0.125f); var fadeOutAction = SCNAction.FadeOpacityTo(0.0f, AnimationDuration * 0.125f); FillPlane.RunAction(SCNAction.Sequence(new SCNAction[] { waitAction, fadeInAction, fadeOutAction })); var flashSquareAction = FlashAnimation(AnimationDuration * 0.25f); foreach (var segment in Segments) { segment.RunAction(SCNAction.Sequence(new[] { waitAction, flashSquareAction })); } } IsOpen = false; }
void RemoveNumberNodes() { // Move, fade and remove on completion foreach (var node in GroundNode.ChildNodes) { if (node.Name == "number") { SCNTransaction.Begin(); SCNTransaction.AnimationDuration = 1; SCNTransaction.SetCompletionBlock(node.RemoveFromParentNode); node.Opacity = 0.0f; node.Position = new SCNVector3(node.Position.X, node.Position.Y, node.Position.Z - 20); SCNTransaction.Commit(); } } }
// Animate (fade out) to remove the text of specified type public void FadeOutText(TextType type) { var node = SubGroups [(int)type]; SubGroups [(int)type] = null; if (node != null) { SCNTransaction.Begin(); SCNTransaction.AnimationDuration = FLIP_DURATION; SCNTransaction.SetCompletionBlock(node.RemoveFromParentNode); node.Opacity = 0; SCNTransaction.Commit(); // Reset the baseline to what it was before adding this text CurrentBaseline = Math.Max(CurrentBaseline, BaselinePerType [(int)type]); } }
private void PerformCloseAnimation(bool flash = false) { if (this.isBorderOpen && !this.isAnimating) { this.isBorderOpen = false; this.isAnimating = true; this.borderNode.RemoveAction("pulse"); this.borderNode.Opacity = 1f; // Close animation SCNTransaction.Begin(); SCNTransaction.AnimationDuration = GameBoard.AnimationDuration / 2f; SCNTransaction.AnimationTimingFunction = CAMediaTimingFunction.FromName(CAMediaTimingFunction.EaseOut); this.borderNode.Opacity = 0.99f; SCNTransaction.SetCompletionBlock(() => { SCNTransaction.Begin(); SCNTransaction.AnimationDuration = GameBoard.AnimationDuration / 2f; SCNTransaction.AnimationTimingFunction = CAMediaTimingFunction.FromName(CAMediaTimingFunction.EaseOut); foreach (var segment in this.borderSegments) { segment.Close(); } SCNTransaction.SetCompletionBlock(() => { this.isAnimating = false; }); SCNTransaction.Commit(); }); SCNTransaction.Commit(); if (flash) { var waitAction = SCNAction.Wait(GameBoard.AnimationDuration * 0.75f); var fadeInAction = SCNAction.FadeOpacityTo(0.6f, GameBoard.AnimationDuration * 0.125f); var fadeOutAction = SCNAction.FadeOpacityTo(0f, GameBoard.AnimationDuration * 0.125f); this.FillPlane.RunAction(SCNAction.Sequence(new SCNAction[] { waitAction, fadeOutAction, fadeInAction })); } } }
protected void PerformEnemyDieWithExplosion(SCNNode enemy, SCNVector3 direction) { var explositionScene = SCNScene.FromFile("art.scnassets/enemy/enemy_explosion.scn"); if (explositionScene != null) { SCNTransaction.Begin(); SCNTransaction.AnimationDuration = 0.4f; SCNTransaction.AnimationTimingFunction = CAMediaTimingFunction.FromName(CAMediaTimingFunction.EaseOut); SCNTransaction.SetCompletionBlock(() => { explositionScene.RootNode.EnumerateHierarchy((SCNNode node, out bool stop) => { stop = false; if (node.ParticleSystems != null) { foreach (var particle in node.ParticleSystems) { enemy.AddParticleSystem(particle); } } }); // Hide if (enemy.ChildNodes.Length > 0) { enemy.ChildNodes[0].Opacity = 0f; } }); direction.Y = 0; enemy.RemoveAllAnimations(); enemy.EulerAngles = new SCNVector3(enemy.EulerAngles.X, enemy.EulerAngles.X + (float)Math.PI * 4.0f, enemy.EulerAngles.Z); enemy.WorldPosition += SCNVector3.Normalize(direction) * 1.5f; this.PositionAgentFromNode(); SCNTransaction.Commit(); } else { Console.WriteLine("Missing enemy_explosion.scn"); } }
private void WillOrderOutSlide(int slideIndex) { var slide = GetSlide(slideIndex, false); if (slide != null) { var node = slide.ContentNode; // Fade out and remove on completion SCNTransaction.Begin(); SCNTransaction.AnimationDuration = 0.75f; SCNTransaction.SetCompletionBlock(() => node.RemoveFromParentNode()); node.Opacity = 0.0f; SCNTransaction.Commit(); slide.WillOrderOut(this); SlideCache.Remove(slideIndex.ToString()); } }
public void AnimateBallGrowAndDrop() { // the block is the total time of the transcation, so sub-blocks are limited by that too SCNTransaction.Begin(); SCNTransaction.AnimationDuration = this.properties.GrowAnimationTime; // correct the rope sim by animating back to reset pose no matter what var fixupLaunchAnimationTime = 0.1f; this.rope.InterpolateToRestPoseAnimation(fixupLaunchAnimationTime); // first scale the ball from small to original size if (this.Projectile != null) { this.Projectile.Scale = this.projectileScale; } SCNTransaction.SetCompletionBlock(() => { // after back to scale, then run the ball drop SCNTransaction.Begin(); SCNTransaction.AnimationDuration = this.properties.DropAnimationTime; // next drop from ballOriginInactiveAbove to ballOriginInactive if (this.Projectile != null) { this.Projectile.WorldPosition = this.ballOriginInactiveBelow.WorldPosition; } SCNTransaction.SetCompletionBlock(() => { // only allow the ball to be grabbed after animation completes this.ballCanBeGrabbed = true; }); SCNTransaction.Commit(); }); SCNTransaction.Commit(); }
// forward click event to the game view controller public override void MouseDown(NSEvent theEvent) { // Called when a mouse click occurs // check what nodes are clicked var p = ConvertPointFromView(theEvent.LocationInWindow, null); var hitResults = HitTest(p, (NSDictionary)null); // check that we clicked on at least one object if (hitResults.Length > 0) { // retrieved the first clicked object var result = hitResults[0]; // get its material var material = result.Node.Geometry.FirstMaterial; // highlight it SCNTransaction.Begin(); SCNTransaction.AnimationDuration = 0.5f; // on completion - unhighlight SCNTransaction.SetCompletionBlock(() => { SCNTransaction.Begin(); SCNTransaction.AnimationDuration = 0.5f; material.Emission.Contents = NSColor.Black; SCNTransaction.Commit(); }); material.Emission.Contents = NSColor.Red; SCNTransaction.Commit(); } base.MouseDown(theEvent); }
void HandleTap(UIGestureRecognizer gestureRecognize) { // retrieve the SCNView var scnView = (SCNView)View; // check what nodes are tapped CGPoint p = gestureRecognize.LocationInView(scnView); SCNHitTestResult[] hitResults = scnView.HitTest(p, (SCNHitTestOptions)null); // check that we clicked on at least one object if (hitResults.Length > 0) { // retrieved the first clicked object SCNHitTestResult result = hitResults [0]; // get its material SCNMaterial material = result.Node.Geometry.FirstMaterial; // highlight it SCNTransaction.Begin(); SCNTransaction.AnimationDuration = 0.5f; // on completion - unhighlight SCNTransaction.SetCompletionBlock(() => { SCNTransaction.Begin(); SCNTransaction.AnimationDuration = 0.5f; material.Emission.Contents = UIColor.Black; SCNTransaction.Commit(); }); material.Emission.Contents = UIColor.Red; SCNTransaction.Commit(); } }
// End the game by showing the congratulation screen after fading the object to white. void EndGame() { var gNodes = gameNodes.Value; textUpdateTimer?.Invalidate(); SCNTransaction.Begin(); SCNTransaction.AnimationDuration = 0.5; SCNTransaction.SetCompletionBlock(() => { SCNTransaction.Begin(); SCNTransaction.AnimationDuration = 0.3; SCNTransaction.SetCompletionBlock(() => { ShowCongratulation(); gNodes.ObjectMaterial.Emission.Contents = UIColor.Black; gameStarted = false; }); SCNTransaction.Commit(); }); gNodes.Object.Transform = SCNMatrix4.Identity; gNodes.ObjectMaterial.Emission.Contents = UIColor.White; gNodes.ObjectMaterial.Transparency = 0; SCNTransaction.Commit(); }
// Animate (flip) to remove the text of specified type public void FlipOutText(TextType type) { var node = SubGroups [(int)type]; SubGroups [(int)type] = null; if (node != null) { SCNTransaction.Begin(); SCNTransaction.AnimationDuration = 0; node.Position = new SCNVector3(-PIVOT_X, 0, 0); node.Pivot = SCNMatrix4.CreateTranslation(-PIVOT_X, 0, 0); SCNTransaction.Commit(); SCNTransaction.Begin(); SCNTransaction.AnimationDuration = FLIP_DURATION; SCNTransaction.SetCompletionBlock(node.RemoveFromParentNode); node.Rotation = new SCNVector4(0, 1, 0, FLIP_ANGLE); node.Opacity = 0; SCNTransaction.Commit(); } // Reset the baseline to what it was before adding this text CurrentBaseline = Math.Max(CurrentBaseline, BaselinePerType [(int)type]); }
public void ShowsNewInSceneKitBadge(bool showsBadge) { if (NewBadgeNode != null && showsBadge) { return; // already visible } if (NewBadgeNode == null && !showsBadge) { return; // already invisible } // Load the model and the animation if (NewBadgeNode == null) { NewBadgeNode = SCNNode.Create(); var badgeNode = Utils.SCAddChildNode(NewBadgeNode, "newBadge", "Scenes.scnassets/newBadge", 1); NewBadgeNode.Scale = new SCNVector3(0.03f, 0.03f, 0.03f); NewBadgeNode.Opacity = 0; NewBadgeNode.Position = new SCNVector3(50, 20, -10); NewBadgeNode.Rotation = new SCNVector4(1, 0, 0, -(float)(Math.PI / 2)); var imageNode = NewBadgeNode.FindChildNode("badgeImage", true); imageNode.Geometry.FirstMaterial.Emission.Intensity = 0.0f; CameraPitch.AddChildNode(NewBadgeNode); NewBadgeAnimation = badgeNode.GetAnimation(badgeNode.GetAnimationKeys() [0]); badgeNode.RemoveAllAnimations(); NewBadgeAnimation.Speed = 1.5f; NewBadgeAnimation.FillMode = CAFillMode.Both; NewBadgeAnimation.UsesSceneTimeBase = false; NewBadgeAnimation.RemovedOnCompletion = false; NewBadgeAnimation.RepeatCount = 0; } // Play if (showsBadge) { NewBadgeNode.AddAnimation(NewBadgeAnimation, new NSString("badgeAnimation")); SCNTransaction.Begin(); SCNTransaction.AnimationDuration = 2; NewBadgeNode.Position = new SCNVector3(14, 8, -20); SCNTransaction.SetCompletionBlock(() => { SCNTransaction.Begin(); SCNTransaction.AnimationDuration = 3; if (NewBadgeNode != null) { SCNNode ropeNode = NewBadgeNode.FindChildNode("rope02", true); ropeNode.Opacity = 0.0f; } SCNTransaction.Commit(); }); NewBadgeNode.Opacity = 1.0f; SCNNode imageNode = NewBadgeNode.FindChildNode("badgeImage", true); imageNode.Geometry.FirstMaterial.Emission.Intensity = 0.4f; SCNTransaction.Commit(); } // Or hide else { SCNTransaction.Begin(); SCNTransaction.AnimationDuration = 1.5f; SCNTransaction.SetCompletionBlock(() => { if (NewBadgeNode != null) { NewBadgeNode.RemoveFromParentNode(); NewBadgeNode = null; } }); NewBadgeNode.Position = new SCNVector3(14, 50, -20); NewBadgeNode.Opacity = 0.0f; SCNTransaction.Commit(); } }
void StartGame() { if (!gameNodes.HasValue) { throw new InvalidProgramException("Nodes not set"); } var startSequence = SCNAction.Sequence(new SCNAction [] { // Wait for 1 second. SCNAction.Wait(1), SCNAction.Group(new SCNAction[] { SCNAction.FadeIn(0.3), // Start the game. SCNAction.Run(node => { if (!gameNodes.HasValue) { return; } var gNodes = gameNodes.Value; var rnd = new Random(); // Compute a random orientation for the object3D. var theta = (float)(Math.PI * rnd.NextDouble()); var phi = (float)(Math.Acos(2 * rnd.NextDouble() - 1) / NMath.PI); var axis = new Vector3 { X = (float)(Math.Cos(theta) * Math.Sin(phi)), Y = (float)(Math.Sin(theta) * Math.Sin(phi)), Z = (float)Math.Cos(theta) }; var angle = (float)(2 * Math.PI * rnd.NextDouble()); SCNTransaction.Begin(); SCNTransaction.AnimationDuration = 0.3; SCNTransaction.SetCompletionBlock(() => gameStarted = true); gNodes.ObjectMaterial.Transparency = 1; gNodes.Object.Transform = SCNMatrix4.CreateFromAxisAngle(axis, angle); SCNTransaction.Commit(); }) }) }); gameNodes.Value.Object.RunAction(startSequence); // Load and set the background image. var backgroundImage = UIImage.FromBundle("art.scnassets/background.png"); sceneInterface.Scene.Background.Contents = backgroundImage; // Hide particles, set camera projection to orthographic. particleRemovalTimer?.Invalidate(); gameNodes.Value.CongratulationsLabel.RemoveFromParent(); gameNodes.Value.Confetti.Hidden = true; gameNodes.Value.Camera.UsesOrthographicProjection = true; // Reset the countdown. countdown = 30; gameNodes.Value.CountdownLabel.Text = countdown.ToString(); gameNodes.Value.CountdownLabel.FontColor = GameColors.DefaultFont; gameNodes.Value.CountdownLabel.Position = new CGPoint(ContentFrame.Width / 2, ContentFrame.Height - 30); textUpdateTimer?.Invalidate(); textUpdateTimer = NSTimer.CreateRepeatingScheduledTimer(1, UpdateText); }
public void GoToSlide(int slideIndex) { int oldIndex = CurrentSlideIndex; // Load the slide at the specified index var slide = GetSlide(slideIndex, true); if (slide == null) { return; } // Compute the playback direction (did the user select next or previous?) var direction = slideIndex >= CurrentSlideIndex ? 1 : -1; // Update badge ShowsNewInSceneKitBadge(slide.IsNewIn10_10); // If we are playing backward, we need to use the slide we come from to play the correct transition (backward) int transitionSlideIndex = direction == 1 ? slideIndex : CurrentSlideIndex; var transitionSlide = GetSlide(transitionSlideIndex, true); // Make sure that the next operations are synchronized by using a transaction SCNTransaction.Begin(); SCNTransaction.AnimationDuration = 0; var rootNode = slide.ContentNode; var textContainer = slide.TextManager.TextNode; var offset = new SCNVector3(transitionSlide.TransitionOffsetX, 0.0f, transitionSlide.TransitionOffsetZ); offset.X *= direction; offset.Z *= direction; // Rotate offset based on current yaw var cosa = Math.Cos(-CameraHandle.Rotation.W); var sina = Math.Sin(-CameraHandle.Rotation.W); var tmpX = offset.X * cosa - offset.Z * sina; offset.Z = (float)(offset.X * sina + offset.Z * cosa); offset.X = (float)tmpX; // If we don't move, fade in if (offset.X == 0 && offset.Y == 0 && offset.Z == 0 && transitionSlide.TransitionRotation == 0) { rootNode.Opacity = 0; } // Don't animate the first slide bool shouldAnimate = !(slideIndex == 0 && CurrentSlideIndex == 0); // Update current slide index CurrentSlideIndex = slideIndex; // Go to step 0 GoToSlideStep(0); // Add the slide to the scene graph ((SCNView)View).Scene.RootNode.AddChildNode(rootNode); // Fade in, update paramters and notify on completion SCNTransaction.Begin(); SCNTransaction.AnimationDuration = (shouldAnimate ? slide.TransitionDuration : 0); SCNTransaction.SetCompletionBlock(() => DidOrderInSlide(slideIndex)); rootNode.Opacity = 1; CameraHandle.Position = new SCNVector3(CameraHandle.Position.X + offset.X, slide.Altitude, CameraHandle.Position.Z + offset.Z); CameraHandle.Rotation = new SCNVector4(0, 1, 0, (float)(CameraHandle.Rotation.W + transitionSlide.TransitionRotation * (Math.PI / 180.0f) * direction)); CameraPitch.Rotation = new SCNVector4(1, 0, 0, (float)(slide.Pitch * (Math.PI / 180.0f))); UpdateLightingForSlide(slideIndex); Floor.Reflectivity = slide.FloorReflectivity; Floor.ReflectionFalloffEnd = slide.FloorFalloff; SCNTransaction.Commit(); // Compute the position of the text (in world space, relative to the camera) var textWorldTransform = SCNMatrix4.Mult(SCNMatrix4.CreateTranslation(0, -3.3f, -28), CameraNode.WorldTransform); // Place the rest of the slide rootNode.Transform = textWorldTransform; rootNode.Position = new SCNVector3(rootNode.Position.X, 0, rootNode.Position.Z); // clear altitude rootNode.Rotation = new SCNVector4(0, 1, 0, CameraHandle.Rotation.W); // use same rotation as the camera to simplify the placement of the elements in slides // Place the text textContainer.Transform = textContainer.ParentNode.ConvertTransformFromNode(textWorldTransform, null); // Place the ground node var localPosition = new SCNVector3(0, 0, 0); var worldPosition = slide.GroundNode.ParentNode.ConvertPositionToNode(localPosition, null); worldPosition.Y = 0; // make it touch the ground localPosition = slide.GroundNode.ParentNode.ConvertPositionFromNode(worldPosition, null); slide.GroundNode.Position = localPosition; // Update the floor image if needed string floorImagePath = null; NSImage floorImage = null; if (slide.FloorImageName != null) { floorImagePath = NSBundle.MainBundle.PathForResource("SharedTextures/" + slide.FloorImageName, slide.FloorImageExtension); floorImage = new NSImage(floorImagePath); } UpdateFloorImage(floorImage, slide); SCNTransaction.Commit(); // Preload the next slide after some delay var delayInSeconds = 1.5; var popTime = new DispatchTime(DispatchTime.Now, (long)(delayInSeconds * Utils.NSEC_PER_SEC)); DispatchQueue.MainQueue.DispatchAfter(popTime, () => { PrepareSlide(slideIndex + 1); }); // Order out previous slide if any if (oldIndex != CurrentSlideIndex) { WillOrderOutSlide(oldIndex); } }
public override void PresentStep(int index, PresentationViewController presentationViewController) { //animate by default SCNTransaction.Begin(); SCNTransaction.AnimationDuration = 1; switch (index) { case 0: SCNTransaction.AnimationDuration = 0; // Set the slide's title and subtitle and add some text TextManager.SetTitle("Morphing"); TextManager.AddBulletAtLevel("Linear morph between multiple targets", 0); // Initial state, no ambient occlusion // This also shows how uniforms from shader modifiers can be set using KVC MapNode.Geometry.SetValueForKey(new NSNumber(0), new NSString("ambientOcclusionYFactor")); break; case 1: TextManager.FlipOutText(SlideTextManager.TextType.Bullet); // Reveal the map and show the gauges MapNode.Opacity = 1.0f; GaugeAProgressNode = SCNNode.Create(); GaugeBProgressNode = SCNNode.Create(); SCNTransaction.Begin(); SCNTransaction.AnimationDuration = 0; GaugeANode = Utils.SCGaugeNode("Target A", ref GaugeAProgressNode); GaugeANode.Position = new SCNVector3(-10.5f, 15, -5); ContentNode.AddChildNode(GaugeANode); GaugeBNode = Utils.SCGaugeNode("Target B", ref GaugeBProgressNode); GaugeBNode.Position = new SCNVector3(-10.5f, 13, -5); ContentNode.AddChildNode(GaugeBNode); SCNTransaction.Commit(); break; case 2: // Morph and update the gauges GaugeAProgressNode.Scale = new SCNVector3(1, 1, 1); MapNode.Morpher.SetWeight(0.65f, 0); SCNTransaction.Begin(); SCNTransaction.AnimationDuration = 1; GaugeAProgressNode.Opacity = 1.0f; SCNTransaction.Commit(); var shadowPlane = MapNode.ChildNodes [0]; shadowPlane.Scale = new SCNVector3(0.35f, 1, 1); MapNode.ParentNode.Rotation = new SCNVector4(1, 0, 0, -(float)(Math.PI / 4) * 0.75f); break; case 3: // Morph and update the gauges GaugeAProgressNode.Scale = new SCNVector3(1, 0.01f, 1); MapNode.Morpher.SetWeight(0, 0); shadowPlane = MapNode.ChildNodes [0]; shadowPlane.Scale = new SCNVector3(1, 1, 1); MapNode.ParentNode.Rotation = new SCNVector4(1, 0, 0, 0); SCNTransaction.SetCompletionBlock(() => { SCNTransaction.Begin(); SCNTransaction.AnimationDuration = 0.5f; GaugeAProgressNode.Opacity = 0.0f; SCNTransaction.Commit(); }); break; case 4: // Morph and update the gauges GaugeBProgressNode.Scale = new SCNVector3(1, 1, 1); MapNode.Morpher.SetWeight(0.4f, 1); SCNTransaction.Begin(); SCNTransaction.AnimationDuration = 0.1f; GaugeBProgressNode.Opacity = 1.0f; SCNTransaction.Commit(); shadowPlane = MapNode.ChildNodes [0]; shadowPlane.Scale = new SCNVector3(1, 0.6f, 1); MapNode.ParentNode.Rotation = new SCNVector4(0, 1, 0, -(float)(Math.PI / 4) * 0.5f); break; case 5: // Morph and update the gauges GaugeBProgressNode.Scale = new SCNVector3(1, 0.01f, 1); MapNode.Morpher.SetWeight(0, 1); shadowPlane = MapNode.ChildNodes [0]; shadowPlane.Scale = new SCNVector3(1, 1, 1); MapNode.ParentNode.Rotation = new SCNVector4(0, 1, 0, 0); SCNTransaction.SetCompletionBlock(() => { SCNTransaction.Begin(); SCNTransaction.AnimationDuration = 0.5f; GaugeBProgressNode.Opacity = 0.0f; SCNTransaction.Commit(); }); break; case 6: // Morph and update the gauges GaugeAProgressNode.Scale = new SCNVector3(1, 1, 1); GaugeBProgressNode.Scale = new SCNVector3(1, 1, 1); MapNode.Morpher.SetWeight(0.65f, 0); MapNode.Morpher.SetWeight(0.30f, 1); SCNTransaction.Begin(); SCNTransaction.AnimationDuration = 0.1f; GaugeAProgressNode.Opacity = 1.0f; GaugeBProgressNode.Opacity = 1.0f; SCNTransaction.Commit(); shadowPlane = MapNode.ChildNodes [0]; shadowPlane.Scale = new SCNVector3(0.4f, 0.7f, 1); shadowPlane.Opacity = 0.2f; MapNode.Geometry.SetValueForKey(new NSNumber(0.35f), new NSString("ambientOcclusionYFactor")); MapNode.Position = new SCNVector3(0, 0, 5); MapNode.ParentNode.Rotation = new SCNVector4(0, 1, 0, -(float)(Math.PI / 4) * 0.5f); MapNode.Rotation = new SCNVector4(1, 0, 0, -(float)(Math.PI / 4) * 0.75f); break; case 7: SCNTransaction.AnimationDuration = 0.5f; // Hide everything and update the text MapNode.Opacity = 0; GaugeANode.Opacity = 0.0f; GaugeBNode.Opacity = 0.0f; TextManager.SetSubtitle("SCNMorpher"); TextManager.AddBulletAtLevel("Topology must match", 0); TextManager.AddBulletAtLevel("Can be loaded from DAEs", 0); TextManager.AddBulletAtLevel("Can be created programmatically", 0); break; } SCNTransaction.Commit(); }
public override void PresentStep(int index, PresentationViewController presentationViewController) { switch (index) { case 0: TextManager.SetSubtitle("Built-in parametric primitives"); break; case 1: PresentPrimitives(); break; case 2: // Hide the carousel and illustrate SCNText TextManager.FlipOutText(SlideTextManager.TextType.Subtitle); SCNTransaction.Begin(); SCNTransaction.AnimationDuration = 1.0f; SCNTransaction.SetCompletionBlock(() => { if (CarouselNode != null) { CarouselNode.RemoveFromParentNode(); } }); PresentTextNode(); TextNode.Opacity = 1.0f; if (CarouselNode != null) { CarouselNode.Position = new SCNVector3(0, CarouselNode.Position.Y, -50); CarouselNode.Opacity = 0.0f; } SCNTransaction.Commit(); TextManager.SetSubtitle("Built-in 3D text"); TextManager.AddBulletAtLevel("SCNText", 0); TextManager.FlipInText(SlideTextManager.TextType.Subtitle); TextManager.FlipInText(SlideTextManager.TextType.Bullet); break; case 3: //Show bezier path var star = StarPath(3, 6); var shape = SCNShape.Create(star, 1); shape.ChamferRadius = 0.2f; shape.ChamferProfile = OutlineChamferProfilePath(); shape.ChamferMode = SCNChamferMode.Front; // that way only the outline of the model will be visible var outlineMaterial = SCNMaterial.Create(); outlineMaterial.Ambient.Contents = outlineMaterial.Diffuse.Contents = outlineMaterial.Specular.Contents = NSColor.Black; outlineMaterial.Emission.Contents = NSColor.White; outlineMaterial.DoubleSided = true; var tranparentMaterial = SCNMaterial.Create(); tranparentMaterial.Transparency = 0.0f; shape.Materials = new SCNMaterial[] { tranparentMaterial, tranparentMaterial, tranparentMaterial, outlineMaterial, outlineMaterial }; StarOutline = SCNNode.Create(); StarOutline.Geometry = shape; StarOutline.Position = new SCNVector3(0, 5, 30); StarOutline.RunAction(SCNAction.RepeatActionForever(SCNAction.RotateBy(0, (float)Math.PI * 2, 0, 10.0))); GroundNode.AddChildNode(StarOutline); // Hide the 3D text and introduce SCNShape SCNTransaction.Begin(); SCNTransaction.AnimationDuration = 1; SCNTransaction.SetCompletionBlock(() => { TextNode.RemoveFromParentNode(); }); TextManager.FlipOutText(SlideTextManager.TextType.Subtitle); TextManager.FlipOutText(SlideTextManager.TextType.Bullet); TextManager.SetSubtitle("3D Shapes"); TextManager.AddBulletAtLevel("SCNShape", 0); TextManager.FlipInText(SlideTextManager.TextType.Subtitle); TextManager.FlipInText(SlideTextManager.TextType.Bullet); TextManager.FlipInText(SlideTextManager.TextType.Code); StarOutline.Position = new SCNVector3(0, 5, 0); TextNode.Position = new SCNVector3(TextNode.Position.X, TextNode.Position.Y, -30); SCNTransaction.Commit(); break; case 4: star = StarPath(3, 6); shape = SCNShape.Create(star, 0); shape.ChamferRadius = 0.1f; StarNode = SCNNode.Create(); StarNode.Geometry = shape; var material = SCNMaterial.Create(); material.Reflective.Contents = new NSImage(NSBundle.MainBundle.PathForResource("SharedTextures/color_envmap", "png")); material.Diffuse.Contents = NSColor.Black; StarNode.Geometry.Materials = new SCNMaterial[] { material }; StarNode.Position = new SCNVector3(0, 5, 0); StarNode.Pivot = SCNMatrix4.CreateTranslation(0, 0, -0.5f); StarOutline.ParentNode.AddChildNode(StarNode); StarNode.EulerAngles = StarOutline.EulerAngles; StarNode.RunAction(SCNAction.RepeatActionForever(SCNAction.RotateBy(0, (float)Math.PI * 2, 0, 10.0))); SCNTransaction.Begin(); SCNTransaction.AnimationDuration = 1.0f; SCNTransaction.SetCompletionBlock(() => { StarOutline.RemoveFromParentNode(); }); shape.ExtrusionDepth = 1; StarOutline.Opacity = 0.0f; SCNTransaction.Commit(); break; case 5: //OpenSubdiv TextManager.FlipOutText(SlideTextManager.TextType.Subtitle); TextManager.FlipOutText(SlideTextManager.TextType.Bullet); TextManager.SetSubtitle("Subdivisions"); TextManager.AddBulletAtLevel("OpenSubdiv", 0); TextManager.AddCode("#aGeometry.#SubdivisionLevel# = anInteger;#"); TextManager.FlipInText(SlideTextManager.TextType.Subtitle); TextManager.FlipInText(SlideTextManager.TextType.Bullet); TextManager.FlipInText(SlideTextManager.TextType.Code); //add boxes var boxesNode = SCNNode.Create(); var level0 = Utils.SCAddChildNode(boxesNode, "rccarBody_LP", "Scenes.scnassets/car/car_lowpoly", 10); level0.Position = new SCNVector3(-6, level0.Position.Y, 0); var label = Utils.SCBoxNode("0", new CGRect(0, 0, 40, 40), NSColor.Orange, 20.0f, true); label.Position = new SCNVector3(0, -35, 10); label.Scale = new SCNVector3(0.3f, 0.3f, 0.001f); level0.AddChildNode(label); boxesNode.Position = new SCNVector3(0, 0, 30); var level1 = level0.Clone(); /*foreach (var child in level1.ChildNodes) { * if (child.Name != "engine_LP") { * child.Geometry = (SCNGeometry)child.Geometry.Copy (); * child.Geometry.SubdivisionLevel = 3; * } * }*/ level1.Position = new SCNVector3(6, level1.Position.Y, 0); boxesNode.AddChildNode(level1); label = Utils.SCBoxNode("2", new CGRect(0, 0, 40, 40), NSColor.Orange, 20.0f, true); label.Position = new SCNVector3(0, -35, 10); label.Scale = new SCNVector3(0.3f, 0.3f, 0.001f); level1.AddChildNode(label); level0.RunAction(SCNAction.RepeatActionForever(SCNAction.RotateBy((float)Math.PI * 2, new SCNVector3(0, 1, 0), 45.0))); level1.RunAction(SCNAction.RepeatActionForever(SCNAction.RotateBy((float)Math.PI * 2, new SCNVector3(0, 1, 0), 45.0))); SCNTransaction.Begin(); SCNTransaction.AnimationDuration = 1; SCNTransaction.SetCompletionBlock(() => { StarNode.RemoveFromParentNode(); }); // move the camera back to its previous position presentationViewController.CameraNode.Position = new SCNVector3(0, 0, 0); presentationViewController.CameraPitch.Rotation = new SCNVector4(1, 0, 0, Pitch * (float)Math.PI / 180.0f); StarNode.Position = new SCNVector3(StarNode.Position.X, StarNode.Position.Y, StarNode.Position.Z - 30); StarOutline.Position = new SCNVector3(StarOutline.Position.X, StarOutline.Position.Y, StarOutline.Position.Z - 30); GroundNode.AddChildNode(boxesNode); //move boxes in boxesNode.Position = new SCNVector3(0, 0, 3.5f); SCNTransaction.Commit(); break; } }
public override void PresentStep(int index, PresentationViewController presentationViewController) { switch (index) { case 1: // Load the scene var intermediateNode = SCNNode.Create(); intermediateNode.Position = new SCNVector3(0.0f, 0.1f, -24.5f); intermediateNode.Scale = new SCNVector3(2.3f, 1.0f, 1.0f); intermediateNode.Opacity = 0.0f; RoomNode = Utils.SCAddChildNode(intermediateNode, "Mesh", "Scenes/cornell-box/cornell-box", 15); ContentNode.AddChildNode(intermediateNode); // Hide the light maps for now foreach (var material in RoomNode.Geometry.Materials) { material.Multiply.Intensity = 0.0f; material.LightingModelName = SCNLightingModel.Blinn; } // Animate the point of view with an implicit animation. // On completion add to move the camera from right to left and back and forth. SCNTransaction.Begin(); SCNTransaction.AnimationDuration = 0.75f; SCNTransaction.SetCompletionBlock(() => { SCNTransaction.Begin(); SCNTransaction.AnimationDuration = 2; SCNTransaction.SetCompletionBlock(() => { var animation = CABasicAnimation.FromKeyPath("position"); animation.Duration = 10.0f; animation.Additive = true; animation.To = NSValue.FromVector(new SCNVector3(-5, 0, 0)); animation.From = NSValue.FromVector(new SCNVector3(5, 0, 0)); animation.TimeOffset = -animation.Duration / 2; animation.AutoReverses = true; animation.TimingFunction = CAMediaTimingFunction.FromName(CAMediaTimingFunction.EaseInEaseOut); animation.RepeatCount = float.MaxValue; presentationViewController.CameraNode.AddAnimation(animation, new NSString("myAnim")); }); presentationViewController.CameraHandle.Position = presentationViewController.CameraHandle.ConvertPositionToNode(new SCNVector3(0, +5, -30), presentationViewController.CameraHandle.ParentNode); presentationViewController.CameraPitch.Rotation = new SCNVector4(1, 0, 0, -(float)(Math.PI / 4) * 0.2f); SCNTransaction.Commit(); }); intermediateNode.Opacity = 1.0f; SCNTransaction.Commit(); break; case 2: // Remove the lighting by using a constant lighing model (no lighting) foreach (var material in RoomNode.Geometry.Materials) { material.LightingModelName = SCNLightingModel.Constant; } break; case 3: // Activate the light maps smoothly SCNTransaction.Begin(); SCNTransaction.AnimationDuration = 1; foreach (var material in RoomNode.Geometry.Materials) { material.Multiply.Intensity = 1.0f; } SCNTransaction.Commit(); break; } }
public override void PresentStep(int switchIndex, PresentationViewController presentationViewController) { switch (switchIndex) { case 0: // Set the slide's title and subtitle and add some text TextManager.SetTitle("Core Image"); TextManager.SetSubtitle("CI Filters"); TextManager.AddBulletAtLevel("Screen-space effects", 0); TextManager.AddBulletAtLevel("Applies to a node hierarchy", 0); TextManager.AddBulletAtLevel("Filter parameters are animatable", 0); TextManager.AddCode("#aNode.#Filters# = new CIFilter[] { filter1, filter2 };#"); break; case 1: SCNTransaction.Begin(); SCNTransaction.AnimationDuration = 1.0f; // Dim the text and move back a little TextManager.TextNode.Opacity = 0.0f; presentationViewController.CameraHandle.Position = presentationViewController.CameraNode.ConvertPositionToNode(new SCNVector3(0, 0, 5.0f), presentationViewController.CameraHandle.ParentNode); SCNTransaction.Commit(); // Reveal the grid GroupNode.Opacity = 1; break; case 2: SCNTransaction.Begin(); SCNTransaction.AnimationDuration = 1; // Highlight an item HighlightContact(13, presentationViewController); SCNTransaction.Commit(); break; case 3: var index = 13; var subStep = 0; // Successively select items for (var i = 0; i < 5; ++i) { var popTime = new DispatchTime(DispatchTime.Now, (long)(i * 0.2 * Utils.NSEC_PER_SEC)); DispatchQueue.MainQueue.DispatchAfter(popTime, () => { SCNTransaction.Begin(); SCNTransaction.AnimationDuration = 0.2f; UnhighlightContact(index); if (subStep++ == 3) { index += ColumnCount; } else { index++; } HighlightContact(index, presentationViewController); SCNTransaction.Commit(); }); } break; case 4: // BLUR+DESATURATE in the background, GLOW in the foreground // Here we will change the node hierarchy in order to group all the nodes in the background under a single node. // This way we can use a single Core Image filter and apply it on the whole grid, and have another CI filter for the node in the foreground. var selectionParent = HeroNode.ParentNode; SCNTransaction.Begin(); SCNTransaction.AnimationDuration = 0; // Stop the animations of the selected node HeroNode.Transform = HeroNode.PresentationNode.Transform; // set the current rotation to the current presentation value HeroNode.RemoveAllAnimations(); // Re-parent the node by preserving its world tranform var wantedWorldTransform = selectionParent.WorldTransform; GroupNode.ParentNode.AddChildNode(selectionParent); selectionParent.Transform = selectionParent.ParentNode.ConvertTransformFromNode(wantedWorldTransform, null); SCNTransaction.Commit(); // Add CIFilters SCNTransaction.Begin(); SCNTransaction.AnimationDuration = 1; // A negative 'centerX' value means no scaling. //TODO HeroNode.Filters [0].SetValueForKey (new NSNumber (-1), new NSString ("centerX")); // Move the selection to the foreground selectionParent.Rotation = new SCNVector4(0, 1, 0, 0); HeroNode.Transform = ContentNode.ConvertTransformToNode(SCNMatrix4.CreateTranslation(0, Altitude, 29), selectionParent); HeroNode.Scale = new SCNVector3(1, 1, 1); HeroNode.Rotation = new SCNVector4(1, 0, 0, -(float)(Math.PI / 4) * 0.25f); // Upon completion, rotate the selection forever SCNTransaction.SetCompletionBlock(() => { var animation = CABasicAnimation.FromKeyPath("rotation"); animation.Duration = 4.0f; animation.From = NSValue.FromVector(new SCNVector4(0, 1, 0, 0)); animation.To = NSValue.FromVector(new SCNVector4(0, 1, 0, NMath.PI * 2)); animation.TimingFunction = CAMediaTimingFunction.FromName(CAMediaTimingFunction.EaseInEaseOut); animation.RepeatCount = float.MaxValue; HeroNode.ChildNodes [0].AddAnimation(animation, new NSString("heroNodeAnimation")); }); // Add the filters var blurFilter = CIFilter.FromName("CIGaussianBlur"); blurFilter.SetDefaults(); blurFilter.Name = "blur"; blurFilter.SetValueForKey(new NSNumber(0), CIFilterInputKey.Radius); var desaturateFilter = CIFilter.FromName("CIColorControls"); desaturateFilter.SetDefaults(); desaturateFilter.Name = "desaturate"; GroupNode.Filters = new CIFilter[] { blurFilter, desaturateFilter }; SCNTransaction.Commit(); // Increate the blur radius and desaturate progressively SCNTransaction.Begin(); SCNTransaction.AnimationDuration = 2; GroupNode.SetValueForKey(new NSNumber(10), new NSString("filters.blur.inputRadius")); GroupNode.SetValueForKey(new NSNumber(0.1), new NSString("filters.desaturate.inputSaturation")); 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: break; case 1: // Set the slide's subtitle and display the primitves TextManager.SetSubtitle("Built-in parametric primitives"); PresentPrimitives(); break; case 2: // Hide the carousel and illustrate SCNText TextManager.FlipOutText(SlideTextManager.TextType.Subtitle); SCNTransaction.Begin(); SCNTransaction.AnimationDuration = 0.5f; SCNTransaction.SetCompletionBlock(() => { CarouselNode.RemoveFromParentNode(); SCNTransaction.Begin(); SCNTransaction.AnimationDuration = 1; PresentTextNode(); TextNode.Opacity = 1.0f; SCNTransaction.Commit(); }); CarouselNode.Opacity = 0.0f; SCNTransaction.Commit(); TextManager.SetSubtitle("Built-in 3D text"); TextManager.AddBulletAtLevel("SCNText", 0); TextManager.FlipInText(SlideTextManager.TextType.Subtitle); TextManager.FlipInText(SlideTextManager.TextType.Bullet); break; case 3: // Hide the 3D text and introduce SCNShape SCNTransaction.Begin(); SCNTransaction.AnimationDuration = 0.5f; SCNTransaction.SetCompletionBlock(() => { if (TextNode != null) { TextNode.RemoveFromParentNode(); } presentationViewController.ShowsNewInSceneKitBadge(true); TextManager.FlipOutText(SlideTextManager.TextType.Subtitle); TextManager.FlipOutText(SlideTextManager.TextType.Bullet); TextManager.SetSubtitle("3D Shapes"); TextManager.AddBulletAtLevel("SCNShape", 0); TextManager.AddBulletAtLevel("Initializes with a NSBezierPath", 0); TextManager.AddBulletAtLevel("Extrusion and chamfer", 0); TextManager.AddCode("#aNode.Geometry = SCNShape.#Create# (aBezierPath, 10);#"); TextManager.FlipInText(SlideTextManager.TextType.Subtitle); TextManager.FlipInText(SlideTextManager.TextType.Bullet); TextManager.FlipInText(SlideTextManager.TextType.Code); }); if (TextNode != null) { TextNode.Opacity = 0.0f; } SCNTransaction.Commit(); break; case 4: TextManager.FadeOutText(SlideTextManager.TextType.Bullet); TextManager.FadeOutText(SlideTextManager.TextType.Code); // Illustrate SCNShape, show the floor ouline Level2Node = Level2(); Level2OutlineNode = Level2Outline(); Level2Node.Position = Level2OutlineNode.Position = new SCNVector3(-11, 0, -5); Level2Node.Rotation = Level2OutlineNode.Rotation = new SCNVector4(1, 0, 0, -(float)(Math.PI / 2)); Level2Node.Opacity = Level2OutlineNode.Opacity = 0.0f; Level2Node.Scale = new SCNVector3(0.03f, 0.03f, 0); Level2OutlineNode.Scale = new SCNVector3(0.03f, 0.03f, 0.05f); GroundNode.AddChildNode(Level2OutlineNode); GroundNode.AddChildNode(Level2Node); SCNTransaction.Begin(); SCNTransaction.AnimationDuration = 1; Level2OutlineNode.Opacity = 1.0f; SCNTransaction.Commit(); break; case 5: presentationViewController.ShowsNewInSceneKitBadge(false); // Show the extruded floor SCNTransaction.Begin(); SCNTransaction.AnimationDuration = 1; Level2Node.Opacity = 1.0f; Level2Node.Scale = new SCNVector3(0.03f, 0.03f, 0.05f); SCNTransaction.SetCompletionBlock(() => { SCNTransaction.Begin(); SCNTransaction.AnimationDuration = 1.5f; // move the camera a little higher presentationViewController.CameraNode.Position = new SCNVector3(0, 7, -3); presentationViewController.CameraPitch.Rotation = new SCNVector4(1, 0, 0, -(float)(Math.PI / 4) * 0.7f); SCNTransaction.Commit(); }); SCNTransaction.Commit(); break; case 6: TextManager.FadeOutText(SlideTextManager.TextType.Subtitle); TextManager.FlipOutText(SlideTextManager.TextType.Bullet); // Example of a custom geometry (Möbius strip) TextManager.SetSubtitle("Custom geometry"); TextManager.AddBulletAtLevel("Custom vertices, normals and texture coordinates", 0); TextManager.AddBulletAtLevel("SCNGeometry", 0); TextManager.FlipInText(SlideTextManager.TextType.Subtitle); TextManager.FlipInText(SlideTextManager.TextType.Bullet); SCNTransaction.Begin(); SCNTransaction.AnimationDuration = 1; // move the camera back to its previous position presentationViewController.CameraNode.Position = new SCNVector3(0, 0, 0); presentationViewController.CameraPitch.Rotation = new SCNVector4(1, 0, 0, Pitch * (float)(Math.PI / 180.0)); Level2Node.Opacity = 0.0f; Level2OutlineNode.Opacity = 0.0f; SCNTransaction.Commit(); break; } }
public override void PresentStep(int index, PresentationViewController presentationViewController) { switch (index) { case 0: // Adjust the near clipping plane of the spotlight to maximize the precision of the dynamic drop shadows presentationViewController.SpotLight.Light.SetAttribute(new NSNumber(30), SCNLightAttribute.ShadowNearClippingKey); // Show what needs to be shown, hide what needs to be hidden PositionsVisualizationNode.Opacity = 1.0f; NormalsVisualizationNode.Opacity = 1.0f; TeapotNodeForUVs.Opacity = 0.0f; TeapotNodeForMaterials.Opacity = 1.0f; TeapotNodeForPositionsAndNormals.Opacity = 0.0f; // Don't highlight bullets (this is useful when we go back from the next slide) TextManager.HighlightBullet(-1); break; case 1: TextManager.HighlightBullet(0); // Animate the "explodeValue" parameter (uniform) of the shader modifier var explodeAnimation = CABasicAnimation.FromKeyPath("explodeValue"); explodeAnimation.Duration = 2.0f; explodeAnimation.RepeatCount = float.MaxValue; explodeAnimation.AutoReverses = true; explodeAnimation.To = new NSNumber(20); explodeAnimation.TimingFunction = CAMediaTimingFunction.FromName(CAMediaTimingFunction.EaseInEaseOut); TeapotNodeForPositionsAndNormals.Geometry.AddAnimation(explodeAnimation, new NSString("expode")); break; case 2: TextManager.HighlightBullet(1); // Remove the "explode" animation and freeze the "explodeValue" parameter to the current value SCNTransaction.Begin(); SCNTransaction.AnimationDuration = 0; var explodeValue = TeapotNodeForPositionsAndNormals.PresentationNode.Geometry.ValueForKey(new NSString("explodeValue")); TeapotNodeForPositionsAndNormals.Geometry.SetValueForKey(explodeValue, new NSString("explodeValue")); TeapotNodeForPositionsAndNormals.Geometry.RemoveAllAnimations(); SCNTransaction.Commit(); SCNTransaction.Begin(); SCNTransaction.AnimationDuration = 1.0f; SCNTransaction.SetCompletionBlock(() => { // Animate to a "no explosion" state and show the positions on completion SCNTransaction.Begin(); SCNTransaction.AnimationDuration = 1.0f; PositionsVisualizationNode.Opacity = 1.0f; SCNTransaction.Commit(); }); TeapotNodeForPositionsAndNormals.Geometry.SetValueForKey(new NSNumber(0.0f), new NSString("explodeValue")); SCNTransaction.Commit(); break; case 3: TextManager.HighlightBullet(2); SCNTransaction.Begin(); SCNTransaction.AnimationDuration = 1.0f; PositionsVisualizationNode.Opacity = 0.0f; NormalsVisualizationNode.Opacity = 1.0f; SCNTransaction.Commit(); break; case 4: TextManager.HighlightBullet(3); SCNTransaction.Begin(); SCNTransaction.AnimationDuration = 0; NormalsVisualizationNode.Hidden = true; TeapotNodeForUVs.Opacity = 1.0f; TeapotNodeForPositionsAndNormals.Opacity = 0.0f; SCNTransaction.Commit(); break; case 5: TextManager.HighlightBullet(4); SCNTransaction.Begin(); SCNTransaction.AnimationDuration = 0; TeapotNodeForUVs.Hidden = true; TeapotNodeForMaterials.Opacity = 1.0f; SCNTransaction.Commit(); break; } }