本案例以 WPF 3D 完整複刻 Windows 7 Win+Tab (Aero Flip 3D) 視窗切換效果:按 Ctrl+↑/↓ 在 6 個頁面間平滑滑動導航。

原始碼下載:Aero.rar
| 元素 | 角色 |
|---|---|
| Viewport3D | 2D 視覺樹中的 3D 容器,持有 Camera 與 Children 集合 |
| PerspectiveCamera | 透視投影攝影機,Position="0,0,8" |
| AmbientLight | 環境光照亮場景 |
| Viewport2DVisual3D | 在 3D 場景承載互動式 2D 控制項 (本例為 Image),共 6 個 |
| RotateTransform3D | Y 軸 35° 旋轉,形成扇形立體感 |
| TranslateTransform3D | X/Y/Z 位移,構建層疊深度 |
| ScaleTransform3D | X 軸 1.5 倍拉伸,修正透視變形 |
<Viewport3D x:Name="Viewport3D" ...>
<Viewport3D.Camera><PerspectiveCamera Position="0,0,8" /></Viewport3D.Camera>
<Viewport2DVisual3D x:Name="viewport2DVisual3D0" Geometry="{StaticResource geometry}" Material="{StaticResource material}">
<Viewport2DVisual3D.Transform>
<Transform3DGroup>
<RotateTransform3D><AxisAngleRotation3D Axis="0,1,0" Angle="35"/></RotateTransform3D>
<TranslateTransform3D OffsetX="0" OffsetY="0" OffsetZ="0"/>
<ScaleTransform3D ScaleX="1.5" ScaleY="1" />
</Transform3DGroup>
</Viewport2DVisual3D.Transform>
<Viewport2DVisual3D.Visual><Image Source="Images\051027nature01.jpg" Stretch="Fill"/></Viewport2DVisual3D.Visual>
</Viewport2DVisual3D>
<Viewport2DVisual3D x:Name="viewport2DVisual3D1" ... OffsetX="-1" OffsetY="1" OffsetZ="-4" ...>...</Viewport2DVisual3D>
<Viewport2DVisual3D x:Name="viewport2DVisual3D2" ... OffsetX="-2" OffsetY="1.5" OffsetZ="-8" ...>...</Viewport2DVisual3D>
<Viewport2DVisual3D x:Name="viewport2DVisual3D3" ... OffsetX="-3" OffsetY="1.5" OffsetZ="-12" ...>...</Viewport2DVisual3D>
<Viewport2DVisual3D x:Name="viewport2DVisual3D4" ... OffsetX="-4" OffsetY="1.5" OffsetZ="-16" ...>...</Viewport2DVisual3D>
<Viewport2DVisual3D x:Name="viewport2DVisual3D5" ... OffsetX="-5" OffsetY="1.5" OffsetZ="-20" ...>...</Viewport2DVisual3D>
<ModelVisual3D><AmbientLight Color="White"/></ModelVisual3D>
</Viewport3D>
TranslateTransform3D 的 OffsetX/Y/Z 皆為 Double 相依屬性,可直接套用 DoubleAnimation。核心方法:
private void AnimationVisualElement(TranslateTransform3D translate, bool forward,
double targetX, double targetY, double targetZ)
{
var duration = new Duration(TimeSpan.FromSeconds(0.4));
var animX = new DoubleAnimation { To = targetX, Duration = duration,
AccelerationRatio = forward ? 0 : 1, DecelerationRatio = forward ? 1 : 0 };
translate.BeginAnimation(TranslateTransform3D.OffsetXProperty, animX);
var animY = new DoubleAnimation { To = targetY, Duration = duration,
AccelerationRatio = forward ? 0.7 : 0.3, DecelerationRatio = forward ? 0.3 : 0.7 };
translate.BeginAnimation(TranslateTransform3D.OffsetYProperty, animY);
var animZ = new DoubleAnimation { To = targetZ, Duration = duration,
AccelerationRatio = forward ? 0.3 : 0.7, DecelerationRatio = forward ? 0.7 : 0.3 };
translate.BeginAnimation(TranslateTransform3D.OffsetZProperty, animZ);
}
// 向前 (下一個)
public void MoveCurrentToNext()
{
var current = Viewport3D.Children[0]; // 最前面
var children = Viewport3D.Children.Cast<Viewport2DVisual3D>().Skip(1).ToArray();
Viewport3D.Children.RemoveAt(0);
Viewport3D.Children.Add(current); // 移至最後 (最遠)
// 當前:移至最遠位置
AnimationVisualElement(current.Translate, true, -5.0, 1.5, -20.0);
AnimationVisualElement(current.Visual as FrameworkElement, 0.3); // 可見度動畫
// 其餘 5 個:依序前移一個位置
AnimationVisualElement(children[0].Translate, true, 0, 0, 0); // → 最前
AnimationVisualElement(children[1].Translate, true, -1.0, 1.0, -4.0);
AnimationVisualElement(children[2].Translate, true, -2.0, 1.5, -8.0);
AnimationVisualElement(children[3].Translate, true, -3.0, 1.5, -12.0);
AnimationVisualElement(children[4].Translate, true, -4.0, 1.5, -16.0);
}
// 向後 (上一個) - 邏輯對稱
public void MoveCurrentToPrevious() { ... }
// 視覺元素可見度動畫 (切換時短暫隱藏避免重疊閃爍)
private void AnimationVisualElement(FrameworkElement element, double duration) { ... }
private void Window_KeyDown(object sender, KeyEventArgs e)
{
if (Keyboard.Modifiers == ModifierKeys.Control)
{
if (e.Key == Key.Down) MoveCurrentToNext();
else if (e.Key == Key.Up) MoveCurrentToPrevious();
}
else if (e.Key == Key.Escape) Application.Current.Shutdown();
}
效能優化關鍵:本例使用 6 個 Viewport2DVisual3D 承載 Image。若頁面內容複雜,強烈建議改用 單一 ModelVisual3D + 6 個 GeometryModel3D (DiffuseMaterial + ImageBrush) + Model3DGroup 方案:僅需一個 3D 容器,材質貼圖取代視覺樹承載,大幅降低渲染開銷。