Yesterday, ChokCoco boss created a 3D shuttle effect. You can see here:
This effect is so amazing that he even asked me if I could use WPF to get it, because I had never used WPF 3D at all, and my first reaction was "This is too difficult for me."
When I went home for dinner at night, I played Empire Age 4, and suddenly remembered that I hadn't favored UWP for a long time. A sense of pride emerged spontaneously that "I have General UWP, which can handle the 3D shuttle effect".
So this animation effect was created.
In general, the principle of achieving 3D shuttle is to create perspective effects by changing the perspective in CSS. Perspective specifies the distance of the observer from the z=0 plane, allowing elements with three-dimensional positional transformations to produce perspective effects. The lower its value, the deeper the viewing angle.

The specific usage of perspective can be found in this document:
perspective - CSS(层叠样式表) _ MDN
Correspondingly, the PerspectiveTransform3D class is provided in UWP, and its Depth attribute has a similar effect. When the Depth is smaller, the deeper the vision, the more deformed the objects that intersect the plane are:

Start immediately after you understand the principles. First, set the case of the Grid to 300 in Xaml, and then set the Depth of PerspectiveTransform3D to very small:
<Grid Height="300" Width="300">
<Grid.Transform3D>
<media3D:PerspectiveTransform3D Depth="2" />
</Grid.Transform3D>
</Grid>
Then I got a starry sky picture from ChokCoco boss and put it in the Grid:

Then set the RotationY of CompositeTransform3D to-90, and the picture becomes distorted:
<media3D:CompositeTransform3D RotationY="-90" />

Then set TranslateZ="100" to stretch the image outward:
<media3D:CompositeTransform3D RotationY="-90" TranslateZ="100" />

After settling one direction, all directions are operated roughly like this. Just changing Rotation, Translate and the center point, a static 3D shuttle diagram is completed:
<media3D:CompositeTransform3D
x:Name="TransformLeft"
x:Key="TransformLeft"
RotationY="-90"
TranslateZ="100"
/>
<media3D:CompositeTransform3D
x:Name="TransformUp"
x:Key="TransformUp"
RotationX="90"
TranslateZ="50"
/>
<media3D:CompositeTransform3D
x:Name="TransformRight"
x:Key="TransformRight"
RotationY="90"
CenterX="300"
TranslateZ="50"
/>
<media3D:CompositeTransform3D
x:Name="TransformDown"
x:Key="TransformDown"
RotationX="-90"
CenterY="300"
TranslateZ="50"
/>
<Grid
Background="{StaticResource ImageBackground}"
Transform3D="{StaticResource TransformLeft}"
/>
<Grid
Background="{StaticResource ImageBackground}"
Transform3D="{StaticResource TransformUp}"
/>
<Grid
Background="{StaticResource ImageBackground}"
Transform3D="{StaticResource TransformRight}"
/>
<Grid
Background="{StaticResource ImageBackground}"
Transform3D="{StaticResource TransformDown}"
/>

The next step is to make these four pictures move. It's simple, using the most basic DoubleAnimation operation to change TranslateZ from 10 to 200:
<Storyboard x:Name="Move" x:Key="Move" RepeatBehavior="Forever">
<DoubleAnimation
Storyboard.TargetName="TransformLeft"
Storyboard.TargetProperty="TranslateZ"
From="10"
To="200"
Duration="0:0:8"
/>
<DoubleAnimation
Storyboard.TargetName="TransformUp"
Storyboard.TargetProperty="TranslateZ"
From="10"
To="200"
Duration="0:0:8"
/>
<DoubleAnimation
Storyboard.TargetName="TransformRight"
Storyboard.TargetProperty="TranslateZ"
From="10"
To="200"
Duration="0:0:8"
/>
<DoubleAnimation
Storyboard.TargetName="TransformDown"
Storyboard.TargetProperty="TranslateZ"
From="10"
To="200"
Duration="0:0:8"
/>
</Storyboard>
At this time, the basic animation has been implemented, but there is no way to connect it end to end, so first package the previous results into a control:
Then animate it with changes in transparency:
<Storyboard x:Name="Fade" RepeatBehavior="Forever">
<DoubleAnimationUsingKeyFrames
Storyboard.TargetName="Root"
Storyboard.TargetProperty="Opacity"
Duration="0:0:8"
>
<LinearDoubleKeyFrame KeyTime="0:0:0" Value="0" />
<LinearDoubleKeyFrame KeyTime="0:0:2" Value="1" />
<LinearDoubleKeyFrame KeyTime="0:0:4.8" Value="1" />
<LinearDoubleKeyFrame KeyTime="0:0:8" Value="0" />
</DoubleAnimationUsingKeyFrames>
</Storyboard>
By superimposing two GalaxyShuttleControls and controlling the start time of their animations, they cover up each other's problem of not connecting the beginning and end animations:
public TimeSpan Delay { get; set; }
private async void GalaxyShettleControl_Loaded(object sender, RoutedEventArgs e)
{
await Task.Delay(Delay);
Move.Begin();
Fade.Begin();
}
<galaxyshuttles:GalaxyShuttleControl Delay="0:0:4" />
<galaxyshuttles:GalaxyShuttleControl/>
In this way, the 3D shuttle effect is realized.
最后还差一点,ChokCoco 大佬的动画里加上了 hueRotate ,让颜色一直变化。UWP 里也可以使用 HueRotationEffect 实现这点,不过它的 Angle 的值范围是 0 到 2 * Math.Pi。要实现它的动画可以试试 Windows Community Toolkit 里的 PipelineVisualFactory 和 AnimationSet,这两个工具可以用来处理很复杂的效果和动画,用在这里反而大材小用:
<media:UIElementExtensions.VisualFactory>
<media:PipelineVisualFactory>
<media:HueRotationEffect x:Name="HueRotationEffect" IsAnimatable="True"/>
</media:PipelineVisualFactory>
</media:UIElementExtensions.VisualFactory>
<animations:Explicit.Animations>
<animations:AnimationSet x:Name="HueAnimation" >
<animations:AnimationScope>
<animations:HueRotationEffectAnimation From="0" To="6.28318530718" Target="{Binding ElementName=HueRotationEffect}" Repeat="Forever" Duration="0:0:28"/>
</animations:AnimationScope>
</animations:AnimationSet>
</animations:Explicit.Animations>
The final effect is as follows:

After satisfying your curiosity, the next step (generating your own pictures) is to stop playing. It is not difficult to implement 3D shuttle animation. The most difficult part is the creativity provided by ChokCoco. I hope that ChokCoco will have another animation for me to copy and play next time.
Finally, although it should be possible to do it with MAIU or WinUI3, and these two technologies sound more fashionable, unfortunately, they have not been released yet, so I'd better spend more time with UWP.
Source code: https://github.com/DinoChan/uwp_design_and_animation_lab