3d 穿梭效果?使用 uwp 也能搞定

3d 穿梭效果?使用 uwp 也能搞定

晚上回家吃飯溜娃打打帝國時代 4,突然想起我很久沒有寵幸 uwp 了。一股“吾有上將 uwp,可搞定 3d 穿梭效果”的豪氣油然而生。

最后更新 2022/2/21 下午2:31
dino.c
预计阅读 5 分钟
分类
.NET
标签
.NET C# UWP

昨天 chokcoco 大佬搞了個 3d 穿梭效果出來,具體可見這裡:

3D 穿梭效果?使用 CSS 轻松搞定

這個效果太神奇了,他還問我能不能用 wpf 搞出來,因為我完全沒用過 wpf 的 3d,我第一反應是“這太難為我了”。

晚上回家吃飯溜娃打打帝國時代 4,突然想起我很久沒有寵幸 uwp 了。一股“吾有上將 uwp,可搞定 3d 穿梭效果”的豪氣油然而生。

於是就把這動畫效果造出來了。

總的來說,實現 3d 穿梭的原理是靠改變 css 中的 perspective 產生透視效果。perspective 指定了觀察者與 z=0 平面的距離,使具有三維位置變換的元素產生透視效果。它的值越小,視角越深。

perspective 的具體用法可見此文檔:

perspective - CSS(层叠样式表) _ MDN

與之對應,uwp 中提供了 perspectivetransform3d 類,它的 depth 屬性 也有類似的效果,當 depth 越小,視覺越深,與平面相交的對象就越變形:

了解原理後馬上開工。首先在 xaml 中將 grid 的大小寫死為 300,然後將 perspectivetransform3d 的 depth 設得很小:

<Grid Height="300" Width="300">
  <Grid.Transform3D>
    <media3D:PerspectiveTransform3D Depth="2" />
  </Grid.Transform3D>
</Grid>

然後從 chokcoco 大佬那裡搞到張星空圖片,放在 grid 里:

然後將 compositetransform3d 的 rotationy 設為 -90,這時候圖片就扭曲起來了:

<media3D:CompositeTransform3D RotationY="-90" />

然後再設置 translatez="100",讓圖片向外拉伸:

<media3D:CompositeTransform3D RotationY="-90" TranslateZ="100" />

搞定了一個方向後,所有方向都大致這樣操作,只是改變 rotation 和 translate 還有中心點,就完成了一張靜態的 3d 穿梭圖:

<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}"
/>

下一步就是要讓這四張圖片動起來。這簡單,用最基本的 doubleanimation 操作 translatez 從 10 變到 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>

這時候基本的動畫就已經實現了,但是沒辦法做到首尾相連,所以先把之前的成果封裝成一個控制項:

然後給它加上透明度變化的動畫:

<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>

通過疊加兩個 galaxyshuttlecontrol ,並且控制它們動畫開始的時間,互相掩蓋開頭和結尾動畫銜接不上的問題:

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/>

這樣 3d 穿梭效果就實現了。

最后还差一点,ChokCoco 大佬的动画里加上了 hueRotate ,让颜色一直变化。UWP 里也可以使用 HueRotationEffect 实现这点,不过它的 Angle 的值范围是 0 到 2 * Math.Pi。要实现它的动画可以试试 Windows Community Toolkit 里的 PipelineVisualFactoryAnimationSet,这两个工具可以用来处理很复杂的效果和动画,用在这里反而大材小用:

<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>

最終實現的效果如下:

滿足了好奇心後,下一步(自己生成圖片)就不玩了。3d 穿梭動畫實現起來不算難,最難的部分是 chokcoco 大佬提供的創意,期待 chokcoco 大佬下次再有別的動畫讓我抄來玩。

最後說一句,雖然用 maiu 或 winui3 應該都能搞,而且這兩個技術聽起來更時髦些,可惜它們還沒發布正式版,我還是趁現在多陪陪 uwp 好了。

源碼:https://github.com/DinoChan/uwp_design_and_animation_lab

Keep Exploring

延伸阅读

更多文章
同分类 / 同标签 2026/2/7

aot使用經驗總結

從項目創建伊始,就應養成良好的習慣,即只要添加了新功能或使用了較新的語法,就及時進行 aot 發布測試。

继续阅读