Основы анимации

189

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

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

Модель анимации Silverlight аналогична модели анимации WPF, поэтому подробно рассматривать ее не будем. За справкой обратитесь к разделу - Графика и анимация WPF.

Производительность анимации

Чаще всего для анимации пользовательского интерфейса достаточно создать и сконфигурировать объекты раскадровки и анимации. Однако иногда, особенно если одновременно выполняется много анимаций, необходимо уделить внимание их производительности. Некоторые эффекты могут существенно замедлить выполнение приложения.

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

В Silverlight встроено несколько способов управления производительностью. В следующих разделах вы научитесь правильно устанавливать частоту кадров и кэшировать большие растровые изображения в видеокарте. Эти две технологии уменьшают нагрузку на процессор. Кроме того, вы узнаете о нескольких способах выяснения того, оптимально ли выполняется анимация или необходимо ваше вмешательство.

Частота кадров

В реальных анимациях чаще всего используется метод линейной интерполяции, т.е. свойство монотонно изменяется от начальной точки до конечной. Например, если начальное значение равно 1, а конечное — 10, свойство получает значения 1, 1.1, 1.2 и т.д., пока не достигнет значения 10.

Как в Silverlight определяется шаг приращения? К счастью, разработчик освобожден от решения этой задачи, потому что шаг вычисляется автоматически. Надстройка Silverlight самостоятельно вычисляет приращение, необходимое для плавного изменения рисунка. Шаг вычисляется на основе частоты кадров. Стандартная частота равна 60 кадрам в секунду. Иными словами, каждую 1/60 секунды Silverlight вычисляет новые анимированные значения и обновляет изменяемые свойства. При частоте 60 кадров в секунду обеспечивается плавное изменение рисунка от начала до конца анимации. В зависимости от клиентского оборудования и производительности анимации Silverlight может уменьшить частоту кадров.

Уменьшить частоту кадров можно также, изменив код страницы. Обычно это делают, если считают, что при меньшей частоте анимация выглядит достаточно хорошо и незачем зря загружать процессор. В некоторых случаях анимация выполняется лучше при меньшей частоте кадров на устаревшем оборудовании. В Интернете для большинства объектов анимации установлены скромные 15 кадров в секунду.

Чтобы изменить частоту кадров, добавьте параметр maxFramerate на входную страницу приложения:

<div id="silverlightControlHost">
        <object data="data:application/x-silverlight-2," 
              type="application/x-silverlight-2" width="100%" height="100%">
          <param name="maxFramerate" value="15" />
          ...

Для повышения производительности анимации не злоупотребляйте управлением прозрачностью, постарайтесь отказаться от изменения размеров текста (шрифты прорисовываются долго) и не используйте безоконный режим, позволяющий видеть HTML-элементы сквозь содержимое Silverlight.

Аппаратное ускорение

Золотое правило графического программирования состоит в том, что нужно переложить как можно больше работы на графический процессор, расположенный на графической карте. В конце концов, графические карты специально созданы для быстрого и эффективного решения определенных типов графических задач (например, масштабирования растрового изображения). Однако при выполнении типичного веб-приложения графическая карта почти не работает. Во многих случаях имеет смысл прибегнуть к ее помощи, разгрузив, хотя бы немного, центральный процессор.

Передача части работы центрального процессора графической карте называется аппаратным ускорением. Эта процедура существенно ускоряет выполнение сложных графических задач, таких как вывод трехмерных объектов в компьютерных играх. В Silverlight аппаратное ускорение может уменьшить нагрузку на процессор и позволяет увеличить частоту кадров анимации, в результате чего она будет выполняться более плавно и привлекательно.

К сожалению, реализация аппаратного ускорения — не такая простая задача, как может показаться на первый взгляд. Наиболее существенная проблема состоит в том, что для реализации ускорения на платформе, на которой выполняется приложение Silverlight, необходим дополнительный слой программной поддержки видеокарты. На компьютерах Windows это означает необходимость видеокарты, совместимой с DirectX 9, а на Mac OSX— с OpenGL2 и соответствующими драйверами. Более того, в Mac аппаратное ускорение выполняется только в полноэкранном режиме приложения Silverlight. Платформа Windows не накладывает на Silverlight столь жесткого ограничения.

Еще одна проблема состоит в том, что видеокарты разработаны для ускорения лишь определенного типа графических операций (например, раскрашивания крошечных треугольников, из которых состоят трехмерные сцены). Многие процедуры ускорения для Silverlight непригодны. Фактически в приложении Silverlight можно применить лишь два типа оптимизации: задействовать способность видеокарты кэшировать некоторые визуальные элементы (такие, как растровые изображения) и выполнять над ними преобразования некоторых типов (такие, как масштабирование, отсечение, поворот, наложение частичной непрозрачности). Другие типы аппаратного ускорения в принципе возможны, однако в Silverlight они в данный момент не поддерживаются.

Включение аппаратного ускорения

Чтобы ускорение можно было применить в приложении, нужно соответствующим образом сконфигурировать входную страницу. Для этого необходимо добавить в объект <object> параметр enableGPUAcceleration и присвоить ему значение true:

<div id="silverlightControlHost">
     <object data="data:application/x-silverlight-2," 
        type="application/x-silverlight-2" width="100%" height="100%">
          <param name="enableGPUAcceleration" value="true" />
          <param name="enableCacheVisualization" value="true" />
          <param name="enableFrameRateCounter" value="true" />
          ...

В приведенной выше разметке добавлены также два необязательных параметра, используемых совместно с аппаратным ускорением. Параметр enableCacheVisualization отмечает подсвечиванием области приложения, в которых не используется хеширование растровых изображений в видеокарте. Параметр enableFrameRateCounter выводит счетчик частоты кадров, автоматически обновляемый во время выполнения анимации. Оба параметра предназначены для диагностики и тестирования приложения. Они облегчают оценку производительности. В окончательной версии приложения их необходимо удалить.

Установка параметра enableGPUAcceleration не приводит к немедленному эффекту. Он лишь предоставляет возможность подключать кэширование к индивидуальным элементам. Пока не будет выполнена эта операция, производительность приложения не улучшится.

Кэширование растровых изображений

Инструкции кэширования сообщают надстройке Silverlight о необходимости скопировать растровое изображение в память видеокарты. После этого видеокарта принимает на себя задачи манипулирования растровым изображением и обновления его на экране. Этот процесс протекает намного быстрее, чем обработка изображения надстройкой Silverlight, что требует постоянного обращения процессора к видеокарте.

Однако видеокарта может делать с растровым изображением не все. В Silverlight она поддерживает лишь следующие операции:

  • масштабирование растрового изображения с помощью объекта ScaleTransform и поворот изображения с помощью объекта RenderTransform;

  • применение трехмерных эффектов (например, перспективного преобразования) к растровому изображению с помощью свойства Projection;

  • изменение прозрачности изображения с помощью свойства Opacity;

  • отсечение изображения прямоугольной секущей областью с помощью свойства Clip.

Следовательно, если в анимации применяется масштабирование, повороты или затенение элементов, можно воспользоваться аппаратным ускорением. Однако если анимация делает что-либо еще (например, наклоняет элемент, изменяет его цвет, вращает объект в трехмерном пространстве методом перспективного проецирования, раскрашивает пиксели и т.п.), видеокарта ничем не поможет. В этих ситуациях надстройка Silverlight вынуждена постоянно передавать обновленные копии растровых изображений видеокарте, обновляя ее кэш несколько раз в секунду. Естественно, это существенно ухудшает производительность.

Чтобы включить кэширование растрового изображения, нужно присвоить свойству CacheMode соответствующего элемента значение BitmapCache. Каждый элемент обладает этим свойством, поэтому можно точно задать, какие элементы должны кэшироваться, а какие — нет.

Чтобы лучше понять принципы кэширования, рассмотрим следующий пример. На рисунке показано, что выполняются две анимации. Первая поворачивает элемент Image, содержащий рисунок, а вторая изменяет размеры кнопки с помощью объекта ScaleTransform, все время растягивая и сокращая ее. Обе анимации доступны для кэширования:

    <UserControl.Resources>
        <Storyboard x:Name="storyboard">
            <DoubleAnimation Storyboard.TargetName="rotateTransform"
                             Storyboard.TargetProperty="Angle"
                             To="360" Duration="0:0:2" RepeatBehavior="Forever"/>
            <DoubleAnimation Storyboard.TargetName="scaleTransform"
                             Storyboard.TargetProperty="ScaleX" AutoReverse="True"
                             To="20" Duration="0:0:1.8" RepeatBehavior="Forever"/>
            <DoubleAnimation Storyboard.TargetName="scaleTransform"
                             Storyboard.TargetProperty="ScaleY" AutoReverse="True"
                             To="20" Duration="0:0:1.8" RepeatBehavior="Forever"/>
        </Storyboard>

    </UserControl.Resources>

    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition></RowDefinition>
            <RowDefinition Height="Auto"></RowDefinition>
        </Grid.RowDefinitions>

        <Canvas>
            <Image x:Name="img" Source="super_man.png" Stretch="None" CacheMode="BitmapCache">
                <Image.RenderTransform>
                    <RotateTransform x:Name="rotateTransform" CenterX="300" CenterY="100"></RotateTransform>
                </Image.RenderTransform>
            </Image>

            <Button x:Name="cmd" Content="Изменяющаяся кнопка" Canvas.Top="70" Canvas.Left="10" Click="cmd_Click">
                <Button.CacheMode>
                    <BitmapCache RenderAtScale="5"></BitmapCache>
                </Button.CacheMode>
                <Button.RenderTransform>
                    <ScaleTransform x:Name="scaleTransform"></ScaleTransform>
                </Button.RenderTransform>
            </Button>
        </Canvas>

        <CheckBox Grid.Row="1" x:Name="chkCache" Content="Включение кэширования"
                  IsChecked="True" Click="chkCache_Click"></CheckBox>
    </Grid>
using System.Threading;
   
...   
   
public partial class MainPage : UserControl
{
        public MainPage()
        {
            InitializeComponent();
        }

        private void UserControl_Loaded(object sender, RoutedEventArgs e)
        {
            storyboard.Begin();
        }

        private void chkCache_Click(object sender, RoutedEventArgs e)
        {
            if (chkCache.IsChecked == true)
            {
                BitmapCache bitmapCache = new BitmapCache();
                bitmapCache.RenderAtScale = 5;
                cmd.CacheMode = bitmapCache;
                img.CacheMode = new BitmapCache();
            }
            else
            {
                cmd.CacheMode = null;
                img.CacheMode = null;
            }
        }

        private void cmd_Click(object sender, RoutedEventArgs e)
        {
            Thread.Sleep(TimeSpan.FromSeconds(5));
        }
}
Тестовая страница с двумя анимированнълми элементами
Оценка эффекта аппаратного ускорения

Оценить эффективность кэширования растровых изображений легче всего, выполняя приложение по очереди в двух режимах: с ускорением и без. В большинстве случаев разница визуально незаметна. Возможно, у ваших пользователей компьютеры медленнее. Поэтому проверьте использование процессора и частоту кадров анимации. Чтобы проверить использование процессора, откройте окно диспетчера задач Windows, а в нем — вкладку Performance (Быстродействие).

На компьютере с процессором AMD Phenom X4 и видеокартой Geforce GTX295 нагрузка при включении кэширования уменьшилась с 30 до 6%. Можете включать и отключать кэширование с помощью флажка, расположенного в нижней части окна приложения. Включить кэширование программно можно с помощью следующего оператора:

img.CacheMode = new BitmapCache();

Еще один полезный инструмент Silverlight — встроенные средства диагностики. Параметры enableCacheVisualization и enableFrameRateCounter (описанные выше) позволяют получить дополнительную диагностическую информацию. На рисунке ниже показано приложение, когда оба эти параметра включены и включено кэширование:

Использование визуализации кэша и счетчика частоты кадров

Элементы Image и Button отмечены красным цветом (благодаря параметру enableCacheVisualization. Ряд чисел в левом верхнем углу окна предоставляют следующую информацию, полученную от счетчика частоты кадров (благодаря параметру enableFrameRateCounter) - первое число — это частота кадров анимации, второе число — объем используемой памяти видеокарты, третье число — общее количество полигонов, обрабатываемых процедурой ускорения, четвертое число — количество неявно обрабатываемых поверхностей.

Для сравнения ниже показан скриншот с отключенным кэшированием:

Использование визуализации кэша и счетчика частоты кадров с отключенным кэшированием

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

Пройди тесты
Лучший чат для C# программистов