Оптимизация анимации затухающих блоков

#c# #wpf #xaml #animation

#c# #wpf #xaml #Анимация

Вопрос:

Я пытаюсь создать интерактивный фон для своего приложения WPF. Как вы можете видеть на скриншоте ниже, он состоит из отдельных прямоугольников, разбросанных по всему фону, и я хочу, чтобы они по отдельности исчезали и исчезали.

Я вычисляю количество требуемых прямоугольников на основе размера виртуального экрана компьютера пользователя (например, у меня 3200×1200). Таким образом, при максимизации и минимизации окна будет отображаться больше фона. Как уже говорилось, для моего разрешения мне понадобится 3220 прямоугольников.

То, как я это реализовал сейчас, заключается в том, что все прямоугольники добавляются на холст со случайно сгенерированными альфа-значениями. Затем я откладываю запуск анимации автоматического цикла (см. Ниже). К сожалению, это приводит к тому, что мое приложение работает крайне медленно (и это справедливо). Могу ли я в любом случае реализовать этот тип эффекта и добиться гораздо лучшей производительности?

 <Storyboard x:Key="uiStoryboardTile" AutoReverse="True" RepeatBehavior="Forever">
    <ColorAnimationUsingKeyFrames
        Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)">
        <EasingColorKeyFrame KeyTime="0:0:2" Value="Transparent"/>
    </ColorAnimationUsingKeyFrames>
</Storyboard>
 

Исчезающие поля

Ответ №1:

Вот что я бы сделал для повышения производительности:

1) Создайте только те прямоугольники, которые видны на заднем плане.

2) Случайным образом привязать свойство заливки каждого прямоугольника к одному из нескольких StaticResources предопределенных цветов (10-20, вероятно, должно сработать).

3) Создайте раскадровку, которая анимирует эти статические ресурсы.

Вы потеряете индивидуальность каждого прямоугольника, но он должен анимироваться, не убивая ваше приложение.

РЕДАКТИРОВАТЬ — Примеры кода

Например, добавьте некоторые ресурсы для анимации (они представляют собой прямоугольники, поскольку вы не можете анимировать SolidColorBrush напрямую):

 <Window.Resources>
        <Rectangle x:Key="Color0" Fill="#FFFFCFFF" />
        <Rectangle x:Key="Color1" Fill="#FFFFC2C2" />
        <Rectangle x:Key="Color2" Fill="#FFFFEFD2" />
        ...
</Window.Resources>
 

Ваша раскадровка будет выглядеть примерно так:

     <Storyboard x:Key="BackgroundAnimation" AutoReverse="True" RepeatBehavior="Forever">
        <ColorAnimationUsingKeyFrames Storyboard.Target="{StaticResource Color0}"
                                      Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)"
                                      BeginTime="0:0:0:0"
                                      AutoReverse="True"
                                      Duration="00:00:03.00">
            <ColorKeyFrameCollection>
                <EasingColorKeyFrame Value="Transparent" />
            </ColorKeyFrameCollection>
        </ColorAnimationUsingKeyFrames>

     <!-- Add keyframes for each color, varying start and duration -->
      ...
</Storyboard>
 

В вашем коде, где вы генерируете все прямоугольники, вам нужно будет привязаться к ресурсам. Итак, где-то в цикле вам нужно будет добавить:

  // I'll leave the implementation of GetRandomColorId to you
 resourceId = GetRandomColorId(MAX_COLORS);

 Shape source = (Shape)this.FindResource("Color"   resourceId);
                    Binding binding = new Binding
                                          {
                                              Path = new PropertyPath("Fill"),
                                              Source = source
                                          };

                    rect.SetBinding(Shape.FillProperty, binding);
 

Наконец, все, что вам нужно будет сделать, это запустить BackgroundAnimation.

Комментарии:

1. Я думаю, вы все еще можете анимировать Brushes с помощью ObjectAnimationUsingKeyFrames ?

Ответ №2:

Есть несколько вариантов:

a. Не используйте так много прямоугольников. Я знаю, что это очевидно, но серьезно, три тысячи элементов для анимации — это МНОГО даже для высокопроизводительной машины.

б. Попробуйте анимировать непрозрачность разных прямоугольников вместо цвета на кисти заливки. Согласно моей теории wild ass guess (WAG), это может иметь положительный эффект.

c. Попробуйте анимировать непрозрачность / цвета каждого из прямоугольников вручную вместо того, чтобы использовать раскадровки для настройки цвета. Например:

 // Disclaimer: This code was written in the SO text editor.  Might not be correct.
foreach (MyRect rect in MyRectangles)
{
  if (rect.FadingIn)
  {
    rect.Opacity  = 0.1;
    if (rect.Opacity >= 1) { rect.FadingIn = false; }
  }
  else
  {
    rect.Opacity -= 0.1;
    if (rect.Opacity <= 0 ) { rect.FadingIn = true; }
  }
}
 

Вы заметите специальный класс, который содержит немного дополнительной информации для ваших нужд.

 class MyRect
{
  public Shape Rectangle;
  public bool FadingIn;

  public double Opacity
  {
    get { return Rectangle.Opacity; }
    set { Rectangle.Opacity = value }
  }

  //... etc.
}
 

Конечно, есть еще некоторый вспомогательный код, который вам нужно будет ввести, например, доставить ваши прямоугольники на их хост и т.д. Но, похоже, вы уже зашли так далеко самостоятельно.

Ответ №3:

Вы пробовали анимировать их в группах? Хотя у вас может быть более 1000 прямоугольников, возможно, вы могли бы разбить их на группы и одновременно запускать только 10 или около того анимаций. Если блоки расположены правильно, они все равно должны выглядеть как случайно анимированные прямоугольники.

Это можно сделать, создав слои блоков, где каждый слой прозрачен, и на нем видны только его блоки. Сложите слои друг на друга и анимируйте альфа каждого слоя.