Balder 3D开发系列之--创建基本动画
一、对于前一篇创建天空盒的一点补充
在之前那篇文章中,我们在天空盒中创建了一块木板,但是,你会发现,这块木板还不够真实,因为在天空中是有太阳的,我们从不同的视角去观察它,应该出现明暗变化,为了达到这样的效果,我们只需要对Box做如下修改:
2 <Geomentry:Box.Material>
3 <Material:Material Ambient="Black" Specular="White" Shade="Gouraud" DiffuseMap="/MaterialDemo;component/Assets/f.png" />
4 </Geomentry:Box.Material>
5 </Geomentry:Box>
仔细观察,就会发现,我们增加了Ambient(环境光),Specular(镜面反射),Shade(阴影)效果,就行了。具体关于它们的介绍,请参考3D设计光线相关资料,对此,由于笔者对此不熟悉,就不多做介绍了,以免误导他人。
二、本篇主题Balder中的动画
Balder中的动画,其实,在之前的文章中已经使用过了,具体请看Sprite初次相遇,这时,你会骂道:“楼主,这。。这。。已经讲过了,也用过了,还将个屁啊。”没错,其实,今天讲的动画和那个动画一样又有点不一样。在上次中,我们看到主要代码是这样的:
2 <EventTrigger RoutedEvent="Grid.Loaded">
3 <BeginStoryboard>
4 <Storyboard AutoReverse="true" RepeatBehavior="Forever">
5 <DoubleAnimation Storyboard.TargetName="Camera" Storyboard.TargetProperty="(Camera.Position).(X)" From="-100" To="100" Duration="00:00:05">
6 <DoubleAnimation.EasingFunction>
7 <ElasticEase/>
8 </DoubleAnimation.EasingFunction>
9 </DoubleAnimation>
10 </Storyboard>
11 </BeginStoryboard>
12 </EventTrigger>
13 </Grid.Triggers>
这里是使用了一个事件触发器,来触发动画,但是,你要知道,在Silverlight中,RoutedEvent只是支持Loaded事件的,如果你要更大的灵活性,那怎么办?例如你要点击某个按钮来触发动画,什么时候让动画停止,开始另一个动画,这不是说使用触发器是不行的,只是操作起来相对不是那么直接了,你需要这样做:
要对不属于控件的对象的属性进行动画处理,请将演示图板放在页面或应用程序的常规 Resources
中。然后在放置"Triggers"的元素上分配一个事件处理程序。响应相关事件时,该事件处理程序应从资源字典中检索演示图板。然后,您对检索到的 Storyboard 调用 Begin。
要对属于控件的对象的属性进行动画处理(派生自 Control),请使用 VisualStateManager
技术,并通过调用 GoToState
基于控件的状态或输入信息运行适当的动画。-
(以上摘自Silverlight官方文档)
,为此,还是选择对后台代码进行动画编程比较直接。而且,你会发现官方的例子,它的动画大多数都是在xaml中定义的,关于这方面,之前园子里Nowpaper已经介绍过一些了,请看这里http://www.cnblogs.com/nowpaper/archive/2010/11/16/1878242.html ,这里已经介绍了balder中的简单动画,而且讲得很好,其实,那篇文章中简单的动画总结起来就是通过计时器来定时的对模型和场景的观察角度和观察位置的变化,或者对模型直接的位置和角度变化。我们今天讲另一种动画实现方法:通过使用storyboard(故事板)来进行。
storyboard相信大家都很熟悉,就是通过时间线控制动画,并为其子动画提供对象和属性目标信息。子动画有DoubleAnimation,ColorAnimation等等,这里我们是对模型或者摄像机的坐标进行变化,所以应该是DoubleAnimation,主要进行的属性变化当然是Position了,其中,Position又有三个分量:X,Y,Z分别代表各个方向轴坐标的坐标点。所以设置模型的目标属性是(Node.Position).(X),摄像机的目标属性是:"(Camera.Position).(X)" ,但是你会发现,这里每个动画都都具体到每个X,Y,Z分量,如果我们要同时进行X,Y,Z三个方向的动画就得定义三次。为此,在balder中针对于这种情况,封装了两个类:
1.CoordinateAnimation
2.StoryboardExtensions
其中,CoordinateAnimation类的结构比较简单:
2 {
3 public string TargetName { get; set; }
4 public string TargetProperty { get; set; }
5 public DependencyObject Target { get; set; }
6 public Coordinate From { get; set; }
7 public Coordinate To { get; set; }
8 public IEasingFunction EasingFunction { get; set; }
9 public TimeSpan? BeginTime { get; set; }
10 public Duration Duration { get; set; }
11 }
12
而相对复杂的是StoryboardExtensions,要注意的是它是一个静态类,因此,在使用的时候不能对它进行实例化,而是通过使用其静态方法:static void SetCoordinateAnimation(DependencyObject obj, CoordinateAnimation coordinateAnimation)
来进行初始化,方法中的参数obj是一个依赖对象,这里只要传入一个Storyboard实例就行了,而后面的参数就是一个CoordinateAnimation类的对象,这个对象在之前就设置好里面的各个属性,例如TargetName,TargetProperty,Target等属性。特别需要注意的是Target属性,如果没有指定的话,会出现TargetName 无法解析的异常。那么使用这个类,为什么能实现三个坐标方向的动画呢?秘密就在StoryboardExtensions类中,在它内部,对Storyboard添加了三个分量的自对象:
1.storyboard.Children.Add(xAnimation);
2.storyboard.Children.Add(yAnimation);
3.storyboard.Children.Add(zAnimation);
这一切都归功于依赖属性的强大之处。说了那么多,我们还是来实战一下吧,还是在上次木板天空盒的例子上更改:我是对木板实现各个方向的旋转动画。
三、实战动画之旋转
因为是旋转,因此,这里的TargetProperty不是Position而是Rotation。
第一步:
打开上次的工程,在xaml中我们添加一个ComboBox,来提供不同方向的旋转:
<ComboBox Width="100" Height="40" SelectionChanged="ComboBox_SelectionChanged" Margin="30">
<ComboBoxItem Content="沿着X轴转动" IsSelected="True"/>
<ComboBoxItem Content="沿着Y轴转动"/>
<ComboBoxItem Content="沿着Z轴转动"/>
</ComboBox>
第二步:
在后台代码的SelectionChanged事件处理程序中添加如下关键代码:
2 ca.From =new Balder.Math.Coordinate(0,0,0);//沿着X轴旋转360度
3 ca.To = new Balder.Math.Coordinate(365,0,0);
4 ca.TargetProperty = "(Node.Rotation)"; //目标属性
5 ca.TargetName = "box";
6 ca.Target = box; //目标对象
7 ca.Duration = TimeSpan.FromMilliseconds(1000);
8 Storyboard sb = new Storyboard();
9 sb.RepeatBehavior = RepeatBehavior.Forever;
10 StoryboardExtensions.SetCoordinateAnimation(sb, ca);
11
12 sb.Begin();
|
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构