KeySplineAnimations关键帧进度控制动画
实现效果:
- 创建三维立方体及贴图模型
- 通过KeySpline的两个进度控制点来设置3D模型的水平进度移动动画
具体实现:
一、三维立方体的创建
- 在Viewport3D中设置Camera及content实例。使用透视投影摄像机PerspectiveCanmera,设置投影摄像机属性ProjectionCanmera的五大属性,及水平视角属性PerspectiveCamera.FieldOfView值。
- 内容ModeVisual3D使用静态资源,此处同时设置3D模型的变换方式组合Transform3DGroup,包含绕轴X/Y旋转及平移动画。
- 设置好旋转实例名,作为动画触发参数。在Viewport3D的加载事件触发动画(只有x/y轴转动角度动画)
<StackPanel>
<Border >
<Viewbox Stretch="Uniform">
<!-- An animated cube. -->
<Viewport3D ClipToBounds="True" Width="700" Height="180">
<Viewport3D.Camera>
<PerspectiveCamera x:Name="myPerspectiveCamera"
FarPlaneDistance="15" LookDirection="0,0,-1" UpDirection="0,1,0" NearPlaneDistance="1" Position="0,0,6" FieldOfView="60" />
</Viewport3D.Camera>
<ModelVisual3D>
<ModelVisual3D.Children>
<StaticResource ResourceKey="PictureCubeModelVisual3DResource" />
</ModelVisual3D.Children>
<ModelVisual3D.Transform>
<Transform3DGroup >
<Transform3DGroup.Children>
<RotateTransform3D>
<RotateTransform3D.Rotation>
<AxisAngleRotation3D x:Name="myHorizontalRotation" Angle="0" Axis="0 1 0" />
</RotateTransform3D.Rotation>
</RotateTransform3D>
<RotateTransform3D>
<RotateTransform3D.Rotation>
<AxisAngleRotation3D x:Name="myVerticalRotation" Angle="0" Axis="1 0 0" />
</RotateTransform3D.Rotation>
</RotateTransform3D>
<TranslateTransform3D x:Name="myTranslateTransform3D"
OffsetX="-2.5" OffsetY="0" OffsetZ="0" />
</Transform3DGroup.Children>
</Transform3DGroup>
</ModelVisual3D.Transform>
</ModelVisual3D>
<Viewport3D.Triggers>
<EventTrigger RoutedEvent="Viewport3D.Loaded">
<BeginStoryboard>
<Storyboard>
<!-- Rotates the cube. -->
<DoubleAnimation
Storyboard.TargetName="myHorizontalRotation"
Storyboard.TargetProperty="Angle"
From="0" To="360"
Duration="0:0:10" RepeatBehavior="Forever"/>
<DoubleAnimation
Storyboard.TargetName="myVerticalRotation"
Storyboard.TargetProperty="Angle"
From="0" To="360"
Duration="0:0:10" RepeatBehavior="Forever"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Viewport3D.Triggers>
</Viewport3D>
</Viewbox>
</Border>
</StackPanel>
</DockPanel>
</StackPanel>
二、立方体3dModel模型创建
-
在3D中设置立方体的6个面模型
- 三角形基元的三角形索引集合TriangleIndices、法向量集合Normals、纹理坐标TextureCoordinates、顶点位置集合Positions(必需)
-
设置3D立方体6个面的材质
- 材质组合MaterialGroup中设置漫射材质类DiffuseMaterial,其属性Brush赋值为包含图像的ImageBrush。
- 同时设置高光材质SpecularMaterial,设置其反光角度SpecularPower值,在SpecularMaterial.Brush应用纯白色画刷上。
<!-- 3D Models -->
<MeshGeometry3D
presentationOptions:Freeze="True"
x:Key="CubeSide01"
TriangleIndices="0,1,2 3,4,5 "
Normals="-1,0,0 -1,0,0 -1,0,0 -1,0,0 -1,0,0 -1,0,0 "
TextureCoordinates="0,1 0,0 1,0 1,0 1,1 0,1 "
Positions="-0.5,0.5,-0.5 -0.5,-0.5,-0.5 -0.5,-0.5,0.5 -0.5,-0.5,0.5 -0.5,0.5,0.5 -0.5,0.5,-0.5 " />
<MeshGeometry3D
presentationOptions:Freeze="True"
x:Key="CubeSide02"
TriangleIndices="0,1,2 3,4,5 "
Normals="0,0,1 0,0,1 0,0,1 0,0,1 0,0,1 0,0,1 "
TextureCoordinates="0,0 1,0 1,1 1,1 0,1 0,0 "
Positions="-0.5,-0.5,0.5 0.5,-0.5,0.5 0.5,0.5,0.5 0.5,0.5,0.5 -0.5,0.5,0.5 -0.5,-0.5,0.5 " />
<MeshGeometry3D
presentationOptions:Freeze="True"
x:Key="CubeSide03"
TriangleIndices="0,1,2 3,4,5 "
Normals="0,0,1 0,0,1 0,0,1 0,0,1 0,0,1 0,0,1 "
TextureCoordinates="1,0 1,1 0,1 0,1 0,0 1,0 "
Positions="0.5,-0.5,-0.5 0.5,0.5,-0.5 0.5,0.5,0.5 0.5,0.5,0.5 0.5,-0.5,0.5 0.5,-0.5,-0.5 " />
<MeshGeometry3D
presentationOptions:Freeze="True"
x:Key="CubeSide04"
TriangleIndices="0,1,2 3,4,5 "
Normals="1,0,0 1,0,0 1,0,0 1,0,0 1,0,0 1,0,0 "
TextureCoordinates="1,0 1,1 0,1 0,1 0,0 1,0 "
Positions="-0.5,-0.5,-0.5 -0.5,0.5,-0.5 0.5,0.5,-0.5 0.5,0.5,-0.5 0.5,-0.5,-0.5 -0.5,-0.5,-0.5 " />
<MeshGeometry3D
presentationOptions:Freeze="True"
x:Key="CubeSide05"
TriangleIndices="0,1,2 3,4,5 6,7,8 9,10,11 "
Normals="0,-1,0 0,-1,0 0,-1,0 0,-1,0 0,-1,0 0,-1,0 0,1,0 0,1,0 0,1,0 0,1,0 0,1,0 0,1,0 "
TextureCoordinates="0,0 1,0 1,1 1,1 0,1 0,0 1,1 0,1 0,0 0,0 1,0 1,1 "
Positions="-0.5,-0.5,-0.5 -0.5,0.5,0.5 -0.5,-0.5,0.5 0.5,-0.5,0.5 -0.5,-0.5,-0.5 -0.5,0.5,-0.5
0.5,0.5,-0.5 -0.5,0.5,-0.5 -0.5,0.5,0.5 -0.5,0.5,0.5 0.5,0.5,0.5 0.5,0.5,-0.5 " />
<MeshGeometry3D
presentationOptions:Freeze="True"
x:Key="CubeSide06"
TriangleIndices="0,1,2 3,4,5 6,7,8 9,10,11 "
Normals="-1,0,0 -1,0,0 -1,0,0 -1,0,0 -1,0,0 -1,0,0 "
TextureCoordinates="1,0 1,1 0,1 0,1 0,0 1,0 "
Positions="-0.5,-0.5,0.5 -0.5,-0.5,-0.5 0.5,-0.5,-0.5 0.5,-0.5,-0.5 0.5,-0.5,0.5 -0.5,-0.5,0.5" />
<!-- 3D Materials -->
<MaterialGroup x:Key="LeavesMaterial1"
presentationOptions:Freeze="True">
<DiffuseMaterial>
<DiffuseMaterial.Brush>
<ImageBrush Stretch="UniformToFill" ImageSource="sample_images\leaves_closeup.png" TileMode="None" ViewportUnits="Absolute" Viewport="0 0 1 1" AlignmentX="Left" AlignmentY="Top" Opacity="1.000000" />
</DiffuseMaterial.Brush>
</DiffuseMaterial>
<SpecularMaterial SpecularPower="85.3333">
<SpecularMaterial.Brush>
<SolidColorBrush Color="#FFFFFF" Opacity="1.000000"/>
</SpecularMaterial.Brush>
</SpecularMaterial>
</MaterialGroup>
<MaterialGroup x:Key="RocksMaterial"
presentationOptions:Freeze="True">
<DiffuseMaterial>
<DiffuseMaterial.Brush>
<ImageBrush Stretch="UniformToFill" ImageSource="sample_images\rocks.png" TileMode="None" ViewportUnits="Absolute" Viewport="0 0 1 1" AlignmentX="Left" AlignmentY="Top" Opacity="1.000000" />
</DiffuseMaterial.Brush>
</DiffuseMaterial>
<SpecularMaterial SpecularPower="85.3333">
<SpecularMaterial.Brush>
<SolidColorBrush Color="#FFFFFF" Opacity="1.000000"/>
</SpecularMaterial.Brush>
</SpecularMaterial>
</MaterialGroup>
<MaterialGroup x:Key="BranchesMaterial"
presentationOptions:Freeze="True">
<DiffuseMaterial>
<DiffuseMaterial.Brush>
<ImageBrush Stretch="UniformToFill" ImageSource="sample_images\branches.png" TileMode="None" ViewportUnits="Absolute" Viewport="0 0 1 1" AlignmentX="Left" AlignmentY="Top" Opacity="1.000000" />
</DiffuseMaterial.Brush>
</DiffuseMaterial>
<SpecularMaterial SpecularPower="85.3333">
<SpecularMaterial.Brush>
<SolidColorBrush Color="#FFFFFF" Opacity="1.000000"/>
</SpecularMaterial.Brush>
</SpecularMaterial>
</MaterialGroup>
<MaterialGroup x:Key="BerriesMaterial"
presentationOptions:Freeze="True">
<DiffuseMaterial>
<DiffuseMaterial.Brush>
<ImageBrush Stretch="UniformToFill" ImageSource="sample_images\berries.jpg" TileMode="None" ViewportUnits="Absolute" Viewport="0 0 1 1" AlignmentX="Left" AlignmentY="Top" Opacity="1.000000" />
</DiffuseMaterial.Brush>
</DiffuseMaterial>
<SpecularMaterial SpecularPower="85.3333">
<SpecularMaterial.Brush>
<SolidColorBrush Color="#FFFFFF" Opacity="1.000000"/>
</SpecularMaterial.Brush>
</SpecularMaterial>
</MaterialGroup>
<MaterialGroup x:Key="FlowersMaterial"
presentationOptions:Freeze="True">
<DiffuseMaterial>
<DiffuseMaterial.Brush>
<ImageBrush Stretch="UniformToFill" ImageSource="sample_images\Waterlilies.png" ViewportUnits="Absolute"
Viewport="0 0 1 1" AlignmentX="Left" AlignmentY="Top" Opacity="1.000000" />
</DiffuseMaterial.Brush>
</DiffuseMaterial>
<SpecularMaterial SpecularPower="85.3333">
<SpecularMaterial.Brush>
<SolidColorBrush Color="#FFFFFF" Opacity="1.000000"/>
</SpecularMaterial.Brush>
</SpecularMaterial>
</MaterialGroup>
<MaterialGroup x:Key="SunsetMaterial"
presentationOptions:Freeze="True">
<DiffuseMaterial>
<DiffuseMaterial.Brush>
<ImageBrush Stretch="UniformToFill" ImageSource="sample_images\Sunset.jpg" ViewportUnits="Absolute"
Viewport="0 0 1 1" AlignmentX="Left" AlignmentY="Top" Opacity="1.000000" />
</DiffuseMaterial.Brush>
</DiffuseMaterial>
<SpecularMaterial SpecularPower="85.3333">
<SpecularMaterial.Brush>
<SolidColorBrush Color="#FFFFFF" Opacity="1.000000"/>
</SpecularMaterial.Brush>
</SpecularMaterial>
</MaterialGroup>
<MaterialGroup x:Key="SolidColorMaterial"
presentationOptions:Freeze="True">
<DiffuseMaterial>
<DiffuseMaterial.Brush>
<SolidColorBrush Color="Orange" Opacity="1.000000"/>
</DiffuseMaterial.Brush>
</DiffuseMaterial>
<SpecularMaterial SpecularPower="85.3333">
<SpecularMaterial.Brush>
<SolidColorBrush Color="#FFFFFF" Opacity="1.000000"/>
</SpecularMaterial.Brush>
</SpecularMaterial>
</MaterialGroup>
三、组合成呈现 Model3D 对象的 Visual3D:ModelVisual3D
- ModelVisual3D只设置其子项Children包含的以上各面几何模型Model3D,以及2个包含2种光源的Model3D组合成立方体
- 以上作为静态资源赋值到Viewport3D的children上
<!-- Model3DVisuals -->
<ModelVisual3D x:Key="PictureCubeModelVisual3DResource">
<ModelVisual3D.Children>
<ModelVisual3D>
<ModelVisual3D.Content>
<AmbientLight Color="#333333" />
</ModelVisual3D.Content>
</ModelVisual3D>
<ModelVisual3D>
<ModelVisual3D.Content>
<DirectionalLight Color="#FFFFFF" Direction="-0.612372,-0.5,-0.612372" />
</ModelVisual3D.Content>
</ModelVisual3D>
<ModelVisual3D>
<ModelVisual3D.Content>
<DirectionalLight Color="#FFFFFF" Direction="0.612372,-0.5,-0.612372" />
</ModelVisual3D.Content>
</ModelVisual3D>
<ModelVisual3D>
<ModelVisual3D.Content>
<GeometryModel3D Geometry="{StaticResource CubeSide01}" Material="{StaticResource BranchesMaterial}"/>
</ModelVisual3D.Content>
</ModelVisual3D>
<ModelVisual3D>
<ModelVisual3D.Content>
<GeometryModel3D Geometry="{StaticResource CubeSide02}" Material="{StaticResource FlowersMaterial}"/>
</ModelVisual3D.Content>
</ModelVisual3D>
<ModelVisual3D>
<ModelVisual3D.Content>
<GeometryModel3D Geometry="{StaticResource CubeSide03}" Material="{StaticResource BerriesMaterial}"/>
</ModelVisual3D.Content>
</ModelVisual3D>
<ModelVisual3D>
<ModelVisual3D.Content>
<GeometryModel3D Geometry="{StaticResource CubeSide04}" Material="{StaticResource LeavesMaterial1}"/>
</ModelVisual3D.Content>
</ModelVisual3D>
<ModelVisual3D>
<ModelVisual3D.Content>
<GeometryModel3D Geometry="{StaticResource CubeSide05}" Material="{StaticResource RocksMaterial}"/>
</ModelVisual3D.Content>
</ModelVisual3D>
<ModelVisual3D>
<ModelVisual3D.Content>
<GeometryModel3D Geometry="{StaticResource CubeSide06}" Material="{StaticResource SunsetMaterial}"/>
</ModelVisual3D.Content>
</ModelVisual3D>
</ModelVisual3D.Children>
</ModelVisual3D>
四、设置KeySpline参数控制图表
- 图表中线点元素是作为一个绘图集合DrawingGroup赋值到绘制图形DrawingImage.Drawing属性上。DrawingImage作为一个图像源来在Image元素上显示。
- 背景GeometryDrawing:方格背景,使用静态资源画刷,一个输出区域矩形。
- 曲线GeometryDrawing:设置贝塞尔曲线BezierSegment(需两个控制点)的路径Path的几何绘图GeometryDrawing,加上一个画笔属性。
- 设置GeometryDrawing:端点处2g黑色几个何圆点
- 2个X/Y轴上红、蓝色控制圆点
的GeometryDrawing。
- 2个X、Y轴红色线条的GeometryDrwing,设置TranslateTransform实例,后台进行移动控制。
<!-- Provides an animated illustration of the spline. -->
<Image Width="200" Height="200">
<Image.Source>
<DrawingImage>
<DrawingImage.Drawing>
<DrawingGroup>
<GeometryDrawing presentationOptions:Freeze="True"
Brush="{StaticResource MyPartiallyTransparentGridBrushResource}">
<GeometryDrawing.Geometry>
<RectangleGeometry Rect="0,0,101,101" />
</GeometryDrawing.Geometry>
</GeometryDrawing>
<GeometryDrawing>
<GeometryDrawing.Geometry>
<PathGeometry>
<PathFigure StartPoint="0,100">
<BezierSegment x:Name="SplineIllustrationSegment"
Point1="0,100" Point2="0,100" Point3="100,0" />
</PathFigure>
</PathGeometry>
</GeometryDrawing.Geometry>
<GeometryDrawing.Pen>
<Pen Thickness="1" Brush="Black" />
</GeometryDrawing.Pen>
</GeometryDrawing>
<GeometryDrawing Brush="Gray" presentationOptions:Freeze="True">
<GeometryDrawing.Geometry>
<GeometryGroup>
<EllipseGeometry
Center="0,100"
RadiusX="2" RadiusY="2" />
<EllipseGeometry
Center="100,0"
RadiusX="2" RadiusY="2" />
</GeometryGroup>
</GeometryDrawing.Geometry>
<GeometryDrawing.Pen>
<Pen Thickness="1" Brush="Black" />
</GeometryDrawing.Pen>
</GeometryDrawing>
<GeometryDrawing Brush="Red">
<GeometryDrawing.Geometry>
<EllipseGeometry
x:Name="SplineControlPoint1Marker"
Center="0,100"
RadiusX="2" RadiusY="2" />
</GeometryDrawing.Geometry>
</GeometryDrawing>
<GeometryDrawing Brush="RoyalBlue">
<GeometryDrawing.Geometry>
<EllipseGeometry
x:Name="SplineControlPoint2Marker"
Center="0,100"
RadiusX="2" RadiusY="2" />
</GeometryDrawing.Geometry>
</GeometryDrawing>
<GeometryDrawing Brush="Orange">
<GeometryDrawing.Pen>
<Pen Thickness="1" Brush="Red" />
</GeometryDrawing.Pen>
<GeometryDrawing.Geometry>
<GeometryGroup>
<GeometryGroup>
<EllipseGeometry
Center="0,0" RadiusX="2" RadiusY="2" />
<LineGeometry StartPoint="2,0" EndPoint="102,0" />
<GeometryGroup.Transform>
<TranslateTransform Y="100" x:Name="SplineProgressTransform" />
</GeometryGroup.Transform>
</GeometryGroup>
<LineGeometry StartPoint="0,0" EndPoint="0,100">
<LineGeometry.Transform>
<TranslateTransform X="100" x:Name="TimeProgressTransform" />
</LineGeometry.Transform>
</LineGeometry>
</GeometryGroup>
</GeometryDrawing.Geometry>
</GeometryDrawing>
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
</Image.Source>
</Image>
五、图表及立方体的动画触发
- 对KeySpline控制线的Y轴KeySpline帧动画
- 对时间线的X轴均匀动画
- 对立方体的X轴KeySpline帧动画
<EventTrigger RoutedEvent="Page.Loaded">
<BeginStoryboard Name="ExampleBeginStoryboard">
<!-- Although the animations is this storyboard are databound,
their clocks won't be automatically regenerated as
their databound properties change. -->
<Storyboard x:Name="ExampleStoryboard">
<!-- Animates the spline progress illustration. -->
<DoubleAnimationUsingKeyFrames
Storyboard.TargetName="SplineProgressTransform"
Storyboard.TargetProperty="Y"
Duration="0:0:5" AutoReverse="True" RepeatBehavior="Forever">
<DiscreteDoubleKeyFrame Value="100" KeyTime="0%" />
<SplineDoubleKeyFrame x:Name="mySplineKeyFrame"
Value="0" KeySpline="0.0,0.0 0.0,0.0" KeyTime="100%"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimation
Storyboard.TargetName="TimeProgressTransform"
Storyboard.TargetProperty="X"
From="0" To="100" Duration="0:0:5"
AutoReverse="True" RepeatBehavior="Forever" />
<!--Animates the 3-D picture cube using
splined interpolation.-->
<DoubleAnimationUsingKeyFrames
Storyboard.TargetName="myTranslateTransform3D"
Storyboard.TargetProperty="OffsetX"
AutoReverse="True" Duration="0:0:5" RepeatBehavior="Forever">
<DiscreteDoubleKeyFrame Value="-2.5" KeyTime="0%" />
<SplineDoubleKeyFrame x:Name="myVector3DSplineKeyFrame"
Value="2.5" KeySpline="0.0,0.0 0.0,0.0" KeyTime="100%"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Page.Triggers>
六、滑块移动事件驱动画面更新
- 在每次有滑值变动时找到对应的变动控制点
- 重新设置图标中曲线对应控制点的坐标
- 重新设置立方体平移帧动画的2个控制点
- 设置图标中控制点及移动轴线的坐标
- 针对页面触发的演示版动画更新,重定位
public partial class SplineExample : Page
{
private Point _controlPoint1 = new Point(0, 100);
private Point _controlPoint2 = new Point(0, 100);
private void OnSliderChanged(object sender, RoutedEventArgs e)
{
// Retrieve the name of slider.
var name = ((Slider) sender).Name;
var args = e as RoutedPropertyChangedEventArgs<double>;
switch (name)
{
case "SliderControlPoint1X":
mySplineKeyFrame.KeySpline.ControlPoint1 = new Point(args.NewValue,
mySplineKeyFrame.KeySpline.ControlPoint1.Y);
_controlPoint1.X = 100*args.NewValue;
break;
case "SliderControlPoint1Y":
mySplineKeyFrame.KeySpline.ControlPoint1 = new Point(mySplineKeyFrame.KeySpline.ControlPoint1.X,
args.NewValue);
_controlPoint1.Y = 100 - (100*args.NewValue);
break;
case "SliderControlPoint2X":
mySplineKeyFrame.KeySpline.ControlPoint2 = new Point(args.NewValue,
mySplineKeyFrame.KeySpline.ControlPoint2.Y);
_controlPoint2.X = 100*args.NewValue;
break;
case "SliderControlPoint2Y":
mySplineKeyFrame.KeySpline.ControlPoint2 = new Point(mySplineKeyFrame.KeySpline.ControlPoint2.X,
args.NewValue);
_controlPoint2.Y = 100 - (100*args.NewValue);
break;
}
// Update the animations and illustrations.
myVector3DSplineKeyFrame.KeySpline.ControlPoint1 = mySplineKeyFrame.KeySpline.ControlPoint1;
myVector3DSplineKeyFrame.KeySpline.ControlPoint2 = mySplineKeyFrame.KeySpline.ControlPoint2;
SplineIllustrationSegment.Point1 = _controlPoint1;
SplineIllustrationSegment.Point2 = _controlPoint2;
SplineControlPoint1Marker.Center = _controlPoint1;
SplineControlPoint2Marker.Center = _controlPoint2;
keySplineText.Text =
"KeySpline=\"" + mySplineKeyFrame.KeySpline.ControlPoint1.X.ToString("N") + "," +
mySplineKeyFrame.KeySpline.ControlPoint1.Y.ToString("N") + " " +
mySplineKeyFrame.KeySpline.ControlPoint2.X.ToString("N") + "," +
mySplineKeyFrame.KeySpline.ControlPoint2.Y.ToString("N") + "\"";
// Determine the storyboard's current time.
TimeSpan? oldTime = (TimeSpan) ExampleStoryboard.GetCurrentTime(this);
// Generate new clocks for the animations by calling
// the Begin method.
ExampleStoryboard.Begin(this, true);
// Because the storyboard was reset, advance it to its previous
// position using the Seek method.
ExampleStoryboard.Seek(this, (TimeSpan) oldTime, TimeSeekOrigin.BeginTime);
//以下为单独在Viewport3D容器下更新其演示版动画
//TimeSpan? oldTime1 = (TimeSpan)my3DModelStoryboard.GetCurrentTime(myViewport3D);
//my3DModelStoryboard.Begin(myViewport3D, true);
//my3DModelStoryboard.Seek(myViewport3D, (TimeSpan)oldTime1, TimeSeekOrigin.BeginTime);
}
}
其他具体关注知识点见下一章
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。