SilverShader: введение в пиксельные шейдеры для Silverlight и WPF

Coding4Fun
Опубликовано 25 мая 2010 г.

В этой статье поясняется, как писать пиксельные шейдеры для платформы Microsoft Silverlight и WPF с помощью HLSL, а также как создать расширяемое приложение Silverlight для демонстрации шейдеров.

Автор: Рене Шульте (René Schulte),
Microsoft Silverlight MVP,
https://blog.rene-schulte.info
https://flavors.me/rschu
Исходный код: загрузить с CodePlex
Попробовать выполнить: прямо сейчас
Сложность: начальная
Необходимое время: 1–4 часа
Затраты: бесплатно!
ПО: Microsoft Visual Studio 2010, Microsoft Silverlight 4 Tools for Visual Studio 2010, Microsoft DirectX SDK, Shazzam Tool
Оборудование: компьютер

Введение

Почти десять лет назад Microsoft объявила о выпуске DirectX 8.0, включая Direct3D 8.0, который ознаменовал собой огромный шаг вперед в компьютерной графике реального времени. В Direct3D 8.0 были введены программируемые шейдеры, и у разработчиков появилась возможность создавать невиданные ранее эффекты и использовать их в дополнение к конвейеру графики с фиксированными функциями. С появлением новых возможностей (шейдеров) в Direct3D 8.0 стало возможным корректно просчитывать собственные визуальные эффекты на мейнстримовом графическом оборудовании. Современное графическое оборудование способно выполнять сотни шейдеров параллельно, и нынешние игры интенсивно используют эту технологию для создания сногсшибательных эффектов.

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

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

Демонстрационное приложение

Демонстрационное приложение позволяет применять различные шейдеры к изображению или к видеопотоку от веб-камеры в реальном времени. Оно поставляется не только с двумя шейдерами, которые будут реализованы в этой статье, но и содержит еще три шейдера, которые я написал раньше. Полный исходный код лицензируется по Ms-PL, и его можно скачать с сайта CodePlex.

Как минимум, вам понадобятся исполняющая среда Silverlight 4 для выполнения примера, и веб-камера, чтобы увидеть полную функциональность. Исполняющая среда доступна для Windows и Mac.

Открыть пример (рис. 1)

clip_image002

Рис . 1. Экранный снимок демонстрационного приложения

Как использовать?

Запускать и останавливать веб-камеру можно кнопкой clip_image003, а загружать изображение с диска — кнопкой clip_image004. Используйте ComboBox (поле с раскрывающимся списком) для смены шейдера, применяемого к источнику. Для каждого шейдера предусмотрены свои элементы управления, позволяющие изменять используемые им параметры. Эти элементы управления понятны и без объяснений — просто опробуйте их в деле.

В первый раз щелкнув кнопку clip_image005, вы обнаружите, что нужно получить разрешение на захват. Это приложение использует устройство захвата для Silverlight по умолчанию. Вы можете сменить видео- и аудиоустройства по умолчанию в окне настройки Silverlight Configuration. Просто щелкните правой кнопкой мыши окно приложения, выберите из контекстного меню Silverlight, а затем откройте вкладку Webcam/Mic для задания устройств.

С чего начать?

Какие возможности есть в Silverlightи WPF ?

Пиксельные шейдеры были введены в WPF 3.5 SP1 и позднее в Silverlight 3 в виде так называемых ShaderEffect. Шейдерные эффекты можно применять к любому элементу управления для создания всяческих визуальных эффектов. WPF 3.5 SP1 и Silverlight поддерживают модель шейдеров версии 2, которая накладывает ограничение на общее количество инструкций — максимум 96 (64 арифметических и 32 текстурных). Современные видеокарты с поддержкой DirectX 11 поддерживают уже модель шейдеров версии 5, в которой таких ограничений нет. Однако пиксельные шейдеры WPF 3.5 SP1 и Silverlight выполняются центральным процессором, а не специализированным графическим процессором. Так как программные конвейеры рендеринга используют возможности современных процессоров вроде SSE и многоядерности, они все равно работают весьма быстро и являются правильным способом реализации эффектов в Silverlight и WPF.

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

Какпрограммироватьшейдеры ?

Есть несколько способов написания и компиляции шейдерных программ. В наши дни самый распространенный способ, применяемый в Direct3D и мире Windows, — язык High Level Shading Language (HLSL). Компилятор шейдеров Direct3D под названием fxc.exe транслирует HLSL-код в байтовый, который и выполняется исполняющей средой.

HLSL — это язык в стиле C, содержащий некоторые специфические типы данных и встроенные функции, но указателей в нем нет. Если вы знаете, как писать код на С-подобных языках вроде C#, вы быстро научитесь создавать шейдеры с помощью HLSL. Кстати, если вы знаете HLSL, вам известен и шейдерный язык Cg от NVIDIA. Cg и HLSL имеют одинаковые корни и очень похожи.

HLSL определяет скалярные и различные векторные/матричные типы данных для целочисленных операций и операций с плавающей точкой. Встроенные функции поддерживают скалярные и векторные типы данных. Выражения, управляющие потоком выполнения, такие как if, switch, for и while, тоже поддерживаются. Конечно же, допустимы фигурные скобки, отделяющие блоки кода, и большинство операторов C. Компилятор использует семантику, чтобы определять предназначение параметра и предоставлять для него корректные данные. Параметр обычно передается в шейдерную программу с указанием ключевого слова register. К элементам векторных типов можно обращаться с использованием различных псевдонимов, например x, y, z, w; r, g, b, a; u, v; и др. Также можно комбинировать все перечисленное выше и писать элегантные и короткие выражения, используя обращения по псевдонимам (swizzling):

HLSL

 // Создаем трехмерный вектор значений с плавающей точкой a и b с разным синтаксисом

float3 a = float3(1, 2, 3);

float3 b = {5, 6, 7};

// Вычисляем произведение векторов a и b, используя обращение по псевдонимам

float3 crossProduct = a.yzx * b.zxy - a.zxy * b.yzx;

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

Какиеинструментынужноиспользовать ?

Конечно, можно написать пиксельный шейдер в простом текстовом редакторе, а потом скомпилировать его утилитой командной строки fxc.exe, но есть отличный инструмент, который существенно упрощает весь процесс. Shazzam Tool от Walt Ritscher — обязательный инструмент для разработки шейдеров, ориентированных на Silverlight и WPF. Он поставляется с HLSL-редактором, поддерживающим выделение синтаксиса, позволяет компилировать шейдер и сразу же применять его к источнику. Он также генерирует элементы управления для каждого параметра, что дает возможность «на лету» изменять настройки шейдера, и создает необходимый файл исходного кода на C# или VB с классом, производным от ShaderEffect.

Вот что вам понадобится перед началом работы.

  1. Скачать DirectX SDK и установить его.
  2. Скачать Shazzam Tool и установить его.
  3. После запуска Shazzam Tool убедитесь, что у вас задан путь к компилятору DirectXFX(рис. 2). Утилита fxc.exe обычно находится в папке установки DirectX SDK в каталоге Utilities\bin\x86. Также проверьте, что выбрана правильная Targetframework (целевая инфраструктура) и задано Generatednamespace (сгенерированное пространство имен).
  4. Чтобы посмотреть, все ли работает как надо, откройте SampleShader (пример шейдера) с помощью ShaderLoader (загрузчика шейдеров), откройте вкладку для этого примера и поэкспериментируйте с элементами управления на странице ChangeShaderSettings (рис. 3).

clip_image009

Рис . 2. Настройки Shazzam Tool

Рис . 3. Общий вид Shazzam Tool

Какнаписатьпиксельныйшейдер ?

Теперь, когда у нас установлены и сконфигурированы нужные инструменты, мы готовы написать первый пиксельный шейдер и приложение Silverlight, которое будет его использовать.

Пример 1: шейдероттенков

Первым будет довольно простой шейдер оттенков (tint shader), который преобразует цвет пикселя в серый и меняет его оттенок параметризованным цветом.

В Shazzam Tool выберите File|NewShaderFile, укажите местонахождение файла HLSL FX и присвойте ему имя TintShader. Shazzam автоматически создаст базовый код пиксельного шейдера, включая float-параметр SampleI. Нажмите клавишу F5, чтобы скомпилировать и применить этот шейдер к выбранному образцу изображения.

HLSL

 sampler2D input : register(s0);

/// <summary>Поясняет предназначение этой переменной.</summary>

/// <minValue>05/minValue>

/// <maxValue>10</maxValue>

/// <defaultValue>3.5</defaultValue>

float SampleI : register(C0);

float4 main(float2 uv : TEXCOORD) : COLOR 

{

    float4 Color; 

    Color = tex2D(input, uv.xy);

    return Color; 

}

Входным регистром является собственно битовая карта/текстура, которая содержит пиксели и обрабатывается пиксельным шейдером. Функция main в этом пиксельном шейдере служит точкой входа и выполняется для каждого пикселя входной битовой карты. Координаты текущего обрабатываемого пикселя передаются как параметр uvтипаfloat2. Эти координаты нормализуются до диапазона [0, 1]. Цвет пикселя в данных координатах извлекается как значение типа float4 с помощью встроенной функции tex2D. Ожидается, что этот пиксельный шейдер вернет значение float4 COLOR.

Рис . 4. Вывод начального кода шейдера (исходное изображение)

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

Преобразование в серые оттенки

HLSL

 sampler2D input : register(s0);

float4 main(float2 uv : TEXCOORD) : COLOR 

{

    // Извлекаем исходный цвет в указанных координатах

    float4 color = tex2D(input, uv);

    // Преобразуем цвет в оттенок серого

    float gray = dot(color.rgb, float3(0.2126, 0.7152, 0.0722));

    // Возвращаем серый цвет с исходным значением альфа-канала

    return float4(gray, gray, gray, color.a); 

}

Шейдер извлекает исходный цвет, а затем преобразует его в оттенок серого, используя функцию dot, которая умножает значения RGB (red, green и blue) на вектор констант типа float3. Результат представляет яркость пикселя. Скалярное произведение перемножает элементы вектора color на элементы вектора констант и добавляет три результата умножения, образуя скалярное значение типа float. Этот пиксельный шейдер возвращает новый цвет, состоящий из значения оттенка серого для RGB и исходного значения альфа-канала (прозрачности) выбранного пикселя (рис. 5).

Рис . 5. Вывод шейдера, преобразующего цвета в оттенки серого

Преобразование в оттенки серого с параметризацией

Шейдер преобразования в оттенок серого можно расширить так, чтобы он использовал вместо серого любой другой цвет, переданный как параметр через шейдерный register.

HLSL

 /// <summary>Цвет окраски</summary>

/// <type>Color</type>

/// <defaultValue>0.9,0.7,0.3,1</defaultValue>

float4 TintColor : register(C0);

sampler2D Input : register(s0);

float4 main(float2 uv : TEXCOORD) : COLOR 

{

    // Извлекаем исходный цвет в указанных координатах

    float4 color = tex2D(Input, uv);

    // Преобразуем цвет в оттенок серого

    float gray = dot(color.rgb, float3(0.2126, 0.7152, 0.0722)); 

    // Создаем серый цвет с исходным значением альфа-канала

    float4 grayColor = float4(gray, gray, gray, color.a); 

    // Возвращаем пиксель, окрашенный в TintColor

    return grayColor * TintColor;

}

Цвет окраски каждого пикселя передается как параметр и поэтому определяется как первый регистр — register C0 (следующий параметр должен помещаться в register C1). XML-комментарий используется утилитой Shazzam для создания удобных элементов управления и инициализации сгенерированного кода. Shazzam создает элементы управления, соответствующие типу данных, и использует defaultValue, minValue и maxValue (рис. 6). Измененный цвет элемента управления применяется напрямую к образцу изображения, что ускоряет и облегчает разработку шейдера.

Каждый элемент (RGBA) переданного параметра TintColor затем умножается на значение оттенка серого типа float4 и возвращается. В результате применения значений TintColor по умолчанию мы получаем изображение, сделанное в стиле рисунка сепией (рис. 7).

Рис . 6. Настройкишейдерав Shazzam Tool

Рис . 7. Вывод шейдера

Подключениешейдерак Silverlight

Теперь самое время использовать шейдер в приложении Silverlight и применить его к Image, MediaElement или любому другому нужному вам UIElement.

  1. Запустите Visual Studio, создайте новый проект SilverlightApplication и выберите в качестве целевой инфраструктуры как минимум Silverlight 3.
  2. В Shazzam Tool выберите Compile Shader из меню Tools, а затем Explore Compiled Shaders. Убедитесь, что параметр Generatednamespace (рис. 2) соответствует имени сборки приложения Silverlight.
  3. Скопируйте файл скомпилированного шейдера TintShader.ps и соответствующий файл TintShaderEffect.cs|vb на C# или VB из вложенной в папку GeneratedShaders папки CS|VB в каталог проекта Silverlight.
  4. В Visual Studio добавьте в проект файлы TintShaderEffect.cs|vb и TintShader.ps. Свойство BuildAction файла TintShader.ps должно быть установлено в Resource. Вновь скомпилируйте решение.
  5. Откройте файл MainPage.xaml и добавьте объявление пространства имен, а также Button или любой другой элемент управления, к которому применяется класс TintShaderEffect (см. ниже).
  6. Нажмите клавишу F5 и посмотрите на свое шейдерное приложение Silverlight в действии (рис. 8).

XAML

 <UserControl x:Class="ShaderDemoApp.MainPage"

xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"

xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"

xmlns:d="https://schemas.microsoft.com/expression/blend/2008"

xmlns:mc="https://schemas.openxmlformats.org/markup-compatibility/2006"

mc:Ignorable="d"

d:DesignHeight="300" d:DesignWidth="400"

xmlns:local="clr-namespace:ShaderDemoApp">

<Grid x:Name="LayoutRoot" Background="Gray">

<Button Content="Big Tinted Button" Width="200" 

Height="200" Background="Blue">

<Button.Effect>

<local:TintShaderEffect />

</Button.Effect>

</Button>

</Grid>

</UserControl>

Рис . 8. TintShader, примененныйккнопке

Вот и все, что нужно для того, чтобы пиксельный шейдер начал работать в приложении Silverlight. Пожалуйста, обратите внимание на то, что вам не пришлось вручную писать какой-либо отделенный код на C# или VB.

Пример 2: мозаичный шейдер akaшейдер пончиков

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

Для разработки этого шейдера мы используем другое изображение. С этой целью укажите OpenImageFile в меню File утилиты Shazzam. Я выбрал знаменитую тестовую картинку для проверки алгоритмов обработки изображений: Lenna (рис. 9). Кстати, на этой картинке изображена Лена Содерберг (Lena Söderberg), и с ней связана весьма интересная история.

clip_image023

Рис . 9. Исходное тестовое изображение Lenna

Пикселизация ввода

HLSL

 /// <summary>Количество пиксельных блоков</summary>

/// <type>Single</type>

/// <defaultValue>25</defaultValue>

float BlockCount : register(C0);

sampler2D input : register(S0);

// Статически вычисляемые переменные для оптимизации

static float BlockSize = 1.0f / BlockCount; 

float4 main(float2 uv : TEXCOORD) : COLOR

{

    // Вычисляем центр блока

    float2 blockPos = floor(uv * BlockCount);

    float2 blockCenter = blockPos * BlockSize + BlockSize * 0.5;

    // Получаем цвет в вычисленных координатах

    return tex2D(input, blockCenter);

}

Параметр BlockCount типаfloatопределяет количество блоков («крупных пикселей»), на которое делится полученное изображение. Размер блока (BlockSize) является обратным значением BlockCount и вычисляется как staticfloat для экономии процессорного времени. Координаты текущего пикселя (uv) используются для определения блока, к которому он относится. Это определение зависит от BlockCount и является результатом встроенной функции floor. Чтобы получить цвет выходного пикселя, определяются координаты центра каждого блока, и извлекается цвет пикселя в этом центре.

clip_image025

Рис . 10. Вывод стадии пикселизации

Округлениеблоков пикселей

HLSL

 /// <summary>Количество блоков пикселей</summary>

/// <type>Single</type>

/// <defaultValue>25</defaultValue>

float BlockCount : register(C0);

/// <summary>Округление блока пикселей</summary>

/// <type>Single</type>

/// <defaultValue>0.45</defaultValue>

float Max : register(C2);

sampler2D input : register(S0);

// Статически вычисляемые переменные для оптимизации

static float BlockSize = 1.0f / BlockCount; 

float4 main(float2 uv : TEXCOORD) : COLOR

{

    // Вычисляем центр блока

    float2 blockPos = floor(uv * BlockCount);

    float2 blockCenter = blockPos * BlockSize + BlockSize * 0.5;

    // Округляем блок, проверяя расстояние

    // пикселя в данных координатах до центра

    float dist = length(uv - blockCenter) * BlockCount;

    if(dist > Max)

    {

          return 0;

    }

    // Получаем цвет в вычисленных координатах

    return tex2D(input, blockCenter);

}

Параметр Max определяет максимальное расстояние пикселя до центра своего блока, а значит, и степень округления блока пикселей. Если длина вектора между текущими координатами пикселя (uv) и центром его блока превышает значение параметра Max, возвращается прозрачный пиксель (0). Для вычисления скалярной длины вектора расстояния применяется встроенная функция length. На рис. 11 и 12 показаны результаты округления с разными значениями параметра Max.

clip_image021

Рис . 11. Вывод стадии округления ( Max = 0.45)

clip_image022

Рис . 12. Вывод стадии округления ( Max = 0.60)

Выпекаем пончики

HLSL

 /// <summary>Количество блоков пикселей</summary>

/// <type>Single</type>

/// <defaultValue>25</defaultValue>

float BlockCount : register(C0);

/// <summary>Округление блока пикселей</summary>

/// <type>Single</type>

/// <defaultValue>0.2</defaultValue>

float Min : register(C1);

/// <summary>Округление блока пикселей</summary>

/// <type>Single</type>

/// <defaultValue>0.45</defaultValue>

float Max : register(C2);

sampler2D input : register(S0);

// Статически вычисляемые переменные для оптимизации

static float BlockSize = 1.0f / BlockCount; 

float4 main(float2 uv : TEXCOORD) : COLOR

{

// Вычисляем центр блока

float2 blockPos = floor(uv * BlockCount);

float2 blockCenter = blockPos * BlockSize + BlockSize * 0.5;

// Округляем блок, проверяя расстояние

// пикселя в данных координатах до центра

float dist = length(uv - blockCenter) * BlockCount;

if(dist < Min || dist > Max)

{

       return 0;

}

// Получаем цвет в вычисленных координатах

return tex2D(input, blockCenter);

}

Чтобы получить симпатичные кольца (пончики), осталось добавить проверку на минимальное расстояние. Это довольно легко и делается с помощью дополнительного параметра Min (рис. 13).

clip_image023

Рис . 13. Вывод стадии округления ( Min = 0.20, Max = 0.45)

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

Какработаетдемонстрационноеприложение ?

Демонстрационное приложение на Silverlight довольно гибкое и может быть использовано для проверки самых разнообразных шейдерных эффектов без модификации базовой функциональности. В этой последней части статьи я покажу, как достигается такая расширяемость. Все объяснения насчет того, как пользоваться веб-камерой в Silverlight и как загружать изображение с диска, см. в моей предыдущей статье «FaceLight — распознавание лиц в реальном времени в Silverlight 4» .

Расширяемость приложения достигается в основном применением Managed Extensibility Framework (MEF) и подхода на основе View-ViewModel. MEF — отличный способ создания несопряженных и гибких приложений; она является частью инфраструктуры Silverlight, начиная с версии 4. MEF аналогична Meth для разработчиков под .NET и Silverlight, но без нежелательных побочных эффектов.

Изящество MEF лучше всего иллюстрирует исходный код. Как видно в окне демонстрационного приложения (рис. 1), вы можете выбирать пиксельный шейдер с помощью поля с раскрывающимся списком (элемента управления ComboBox). Элементы в этом списке в странице MainPage заполняются привязкой данных к ObservableCollection <T>, и этот набор создается MEF.

C#

 /// <summary>

/// Основная страница приложения

/// </summary>

public partial class MainPage : UserControl

{

[ImportMany(AllowRecomposition = true)]

public ObservableCollection<IShaderViewModel> Shaders;

public MainPage()

{

      InitializeComponent();

}

private void Initialize()

{

     // Формируем фрагменты с помощью MEF

     var container = new CompositionContainer(

     new AssemblyCatalog(GetType().Assembly));
      container.ComposeParts(this);

     // Заполняем ComboBox

     CmbShaders.ItemsSource = Shaders;

     CmbShaders.DisplayMemberPath = "Name";

     CmbShaders.SelectedIndex = 0;

     // ...

}

    // ...

}

/// <summary>

/// Интерфейс ViewModel для шейдерного эффекта

/// </summary>

[InheritedExport]

public interface IShaderViewModel

{

    string Name { get; }
 
    ShaderEffect Shader { get; }

    UserControl View { get; }

}

В MainPage есть свойство-набор Shaders, содержащее элементы, которые реализуют интерфейс IShaderViewModel. Этот набор инициализируется с помощью MEF-объектов CompositionContainer и AssemblyCatalog и метода ComposeParts. ComposeParts анализирует все типы в предоставленном Catalog (здесь — в сборке), проверяет, назначены ли им определенные атрибуты, и связывает эти так называемые фрагменты (parts) воедино. Проще говоря, создается экземпляр типа, дополненный атрибутом Export, и назначается каждому полю/свойству/параметру типа, у которого есть атрибут Import.

Интерфейс IShaderViewModel дополнен атрибутом InheritedExport, а это означает, что реализации этого интерфейса будут автоматически предоставлять такой экспорт. Набор Shaders в свою очередь использует атрибут ImportMany, сообщая MEF заполнить список всеми совпадающими экспортами (в данном случае — всеми классами, реализующими интерфейс IShaderViewModel).

После того как MEF заполняет набор, он связывается через механизм привязки данных со свойством ItemsSource объекта ComboBox. Свойство Name интерфейса IShaderViewModel используется как DisplayMember.

Здесь преимущество MEF должно быть очевидно: вы должны реализовать IShaderViewModel и, возможно, пользовательский элемент управления View для параметров шейдера, но вам не нужно вручную добавлять экземпляр ViewModel шейдера в набор Shaders. Так как IShaderViewModel дополнен атрибутом InheritedExport, вам даже не требуется добавлять специальный MEF-атрибут к новому типу ViewModel шейдера. Кроме того, можно асинхронно загрузить дополнительную сборку и впоследствии возложить на MEF композицию фрагментов и обновление набора. Устанавливая параметр AllowRecomposition атрибута ImportMany в true, вы просите MEF разрешить динамическое обновление.

Как видите, MEF довольно проста в работе, но обладает широкими возможностями. Однако мы лишь едва коснулись этой тематики, поэтому, если вы хотите узнать больше о MEF, прочтите эту статью в блоге и посмотрите ресурсы MSDN — они послужат вам хорошей отправной точкой.

Дополнительные ресурсы

В Интернете много отличных ресурсов для разработки HLSL-шейдеров. В следующем списке перечислены некоторые сайты, где уделяется внимание пиксельным шейдерам для Silverlight и WPF. Если я упустил какой-то хороший ресурс, пожалуйста, напишите о нем в комментариях.

  • WPF Pixel Shader Effects Library на CodePlex с открытым исходным кодом содержит множество пиксельных шейдеров для распространенных эффектов.
  • Никола Михайлов (Nikola Mihaylov) (aka Nokola) написал отличный онлайновый редактор изображений на Silverlight, использующий для эффектов пиксельные шейдеры. Он опубликовал пиксельные шейдеры, применяемые в EasyPainter, как открытый исходный код. Кроме того, он открыл исходный код собственных элементов управления в своем редакторе. Элементы управления Slider и ColorPicker, примененные в демонстрационном приложении, как раз оттуда и взяты. Я лишь изменил некоторые свойства на свойства зависимостей, чтобы элементы управления поддерживали связывание с данными. Мой респект Николе!
  • Замечательный Shazzam Tool Уолта Ритшера (Walt Ritscher) также поставляется с уймой интересных пиксельных шейдеров в качестве примеров. Снимаю шляпу перед Уолтом, сумевшим создать такой отличный инструмент!
  • Кроме того, время от времени я пишу некоторые шейдеры и выкладываю их в своем блоге. Теперь, когда у нас есть расширяемое демонстрационное приложение шейдеров на Silverlight, я совершенно точно интегрирую свои будущие шейдеры прямо в это приложение.

Пока я писал эту статью, на CodePlex был опубликован проект WPF Meta-Effects с открытым исходным кодом. Инфраструктура WPF Meta-Effects позволяет писать шейдеры для WPF на C#, используя атрибуты, делегаты и динамическую компиляцию HLSL. Идея отличная, но из-за динамической компиляции шейдеров инфраструктура применима к WPF, но не к Silverlight. Кроме того, на мой взгляд, писать шейдеры на HLSL куда проще, чем на C#. Именно поэтому и был создан язык HLSL: смотрите примеры сами.

Заключение

В этой статье было рассмотрено, что такое шейдеры и HLSL и как писать пиксельные шейдеры для Silverlight и WPF. В ней было показано, какие инструменты/инфраструктуры следует использовать для максимального упрощения разработки. Также было дано введение в то, как создать расширяемое приложение с помощью MEF.

Надеюсь, теперь вы меньше боитесь языка HLSL и разработки шейдеров. Я также рассчитываю, что моя статья поможет вам в написании собственных шейдеров. С нетерпением жду, что у вас получится. Желаю вам весело провести время!

Ссылки на демонстрационное приложение и его исходный код находятся в самом начале статьи.

clip_image024Об авторе

Рене Шульте (René Schulte) — разработчик ПО для .NET и Silverlight, а также обладатель звания Microsoft Silverlight MVP. Он неравнодушен к компьютерной графике, моделированию физических объектов, искусственного интеллекта и к алгоритмам, а также любит C#, шейдеры и Augmented Reality. Он является зачинателем Silverlight-проектов SLARToolkit, WriteableBitmapEx и Matrix3DEx с открытым исходным кодом и создал веб-сайт на основе Silverlight, где используются операции над физическими объектами в реальном времени. Постоянный автор Microsoft Coding4Fun. Контактную информацию можно найти на его веб-сайте на основе Silverlight, в блоге или на Twitter.