netlib.narod.ru< Назад | Оглавление | Далее >

Высокоуровневый язык шейдеров HLSL

XNA поддерживает программирование шейдеров с использованием предлагаемого Microsoft высокоуровневого языка шейдеров (HLSL, High Level Shading Language). В HLSL есть небольшой набор функций, включающий математические операции, доступ к текстурам и управление потоком исполнения. Поддерживаемые HLSL типы данных похожи на используемые в языке C, за исключением векторов, матриц и объектов выборки.

Типы данных

HLSL поддерживает много различных типов данных, включая скаляры, векторы, матрицы и объекты выборки. В таблице 8.1 показаны представленные в языке скалярные типы данных. Заметьте, что для всех представленных в языке скалярных типов данных можно создавать векторы и матрицы, такие как float2, float4, bool3x3, double2x2 и т.д.


Таблица 8.1. Скалярные типы HLSL



Тип Значение

bool true или false
int 32-разрядное целое со знаком
half 16-разрядное с плавающей точкой
float 32-разрядное с плавающей точкой
double 64-разрядное с плавающей точкой


Другим представленным в HLSL типом данных является тип sampler, используемый для чтения (выборки) данных из текстур. Есть несколько различных типов объектов выборки, таких как sampler, sampler1D, sampler2D и sampler3D, используемых для выборки из одномерных, двухмерных и трехмерных текстур. Объект выборки имеет несколько связанных с ним состояний, которые задают текстуру из которой производится выборка, применяемый тип фильтрации и режим адресации (обертывания) текстуры. Ниже приведен пример объекта выборки для двухмерной текстуры:

// Объявляем входную текстуру
texture skyTexture;

// Объявляем объект выборки, используемый для
// доступа к skyTexture
sampler2D skySampler = sampler_state
{
    Texture = skyTexture;

    MinFilter = Linear;
    MagFilter = Linear;
    MipFilter = Linear;

    AddressU = Wrap;
    AddressV = Wrap;
    AddressW = Wrap;
}

Состояние Texture представляет текстуру из которой будет производиться выборка; используя данный объект выборкм можно будет читать данные только из этой текстуры. MinFilter, MagFilter и MipFilter это состояния фильтрации, а AddressU, AddressV и AddressW — состояния адресации. За дополнительной информацией обращайтесь к документации DirectX SDK (http://msdn2.microsoft.com/en-us/library/bb509638.aspx), где есть полный справочник по представленным в HLSL типам данных.

Неизменные и меняющиеся входные данные

В HLSL есть две разновидности входных типов данных: неизменные и меняющиеся. Неизменные входные данные — это данные, остающиеся в шейдере постоянными в ходе обработки всех входных данных. Например, во время визуализации машины, текстура и мировая матрица постоянны.

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

Меняющиеся входные данные — это данные, которые меняются при каждом исполнении шейдера. Например, во время визуализации машины, все вершины модели машины передаются этапу обработки вершин. Таким образом, каждый раз при выполнении вершинный шейдер получает в качестве входных данных вершину с отличающимися атрибутами (местоположением, цветом, нормалью и т.д.). Итак, атрибуты вершин не постоянны в процессе визуализации всей машины. В отличие от неизменных входных данных, вы объявляете меняющиеся входные данные используя семантику.

Семантика

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

float4 vertexPosition : POSITION0;

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


Таблица 8.2. Семантики вершинных шейдеров



Входная семантика Описание Тип

POSITION[n] Местоположение вершины в пространстве объекта float4
COLOR[n] Рассеиваемый и отражаемый цвет float4
NORMAL[n] Вектор нормали float4
TEXCOORD[n] Координаты текстуры float4
TANGENT[n] Вектор касательной float4
BINORMAL[n] Вектор бинормали float4
BLENDINDICES[n] Индексы смешивания костей int4
BLENDWEIGHT[n] Веса смешивания костей float4



Выходная семантика Описание Тип

POSITION[n] Местоположение вершины в однородном пространстве (X, Y, Z, W) float4
COLOR[n] Рассеиваемый или отражаемый цвет float4
TEXCOORD[n] Координаты текстуры float4
FOG Туман вершины float


Вы используете входные семантики вершинного шейдера для меняющихся данных, получаемых вершинным шейдером. Наиболее часто используются семантики POSITION, COLOR, NORMAL и TEXCOORD. Семантики TANGENT и BINORMAL вы применяете, если у вершины есть вектор касательной (tangent) или вектор бинормали (binormal), которые перпендикулярны вектору нормали вершины. Вы используете эти три вектора для создания системы координат, которая будет параллельна поверхности объекта в заданной точке (называемой касательным пространством). Семантики BLENDINDICES и BLENDWEIGHT вы используете когда вершины связаны с костями (bone). Кости используются для деформирования вершин сетки и будут рассмотрены в главе 11.

Обратите внимание, что [n] — это необязательное целое число, определяющее количество используемых ресурсов. Например, если у модели три текстуры, [n] в семантике TEXCOORD может варьироваться от 0 до 2. Таким образом, допустимыми входными семантиками для вершинного шейдера будут TEXCOORD0, TEXCOORD1 и TEXCOORD2. Таблица 8.3 показывает некоторые семантики пиксельных шейдеров.


Таблица 8.3. Семантики пиксельных шейдеров



Входная семантика Описание Тип

COLOR[n] Рассеиваемый или отражаемый цвет float4
TEXCOORD[n] Координаты текстуры float4



Выходная семантика Описание Тип

COLOR[n] Итоговый цвет float4
DEPTH[n] Итоговая глубина float


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

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

Функции

HLSL позволяет создавать функции, используя синтаксис, подобный языку C, где у каждой функции есть объявление и тело. Объявление функции содержит имя функции и тип возвращаемого значения, а также может иметь список параметров. Кроме того, у типа, возвращаемого функцией, может быть связанная с ним семантика. Ниже показан код функции, используемой как точка входа пиксельного шейдера. Мы покажем, как определить, какие функции будут использованы в качестве точек входа для вершинного и пиксельного шейдера, в разделе «Эффекты».

float4 simplePS(float4 inputColor : COLOR0) : COLOR0
{
    return inputColor * 0.5f;
}

Поскольку функция simplePS используется как точка входа пиксельного шейдера, каждому из ее параметров должна быть назначена семантика. В данном случае функция simplePS масштабирует полученный параметр цвета, используя коэффициент 0.5, и возвращает итоговый цвет пикселя. Обратите внимание, что параметры функции могут иметь другие модификаторы, такие как in, out и inout, применяемые для описания входных, выходных и двунаправленных параметров.

Встроенные функции

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


Таблица 8.4. Некоторые функции HLSL



Функция Описание

dot Возвращает скалярное произведение двух векторов
cross Возвращает векторное произведение двух трехмерных векторов с плавающей точкой
lerp Выполняет линейную интерполяцию между двумя значениями
mul Выполняет матричное умножение X и Y
normalize Нормализует заданный вектор с плавающей точкой
pow Возвращает X в степени Y
reflect Возвращает вектор отражения, получая направление входящего луча и нормаль поверхности
refract Возвращает вектор преломления, используя направление входящего луча, нормаль поверхности и коэффициент преломления
saturate Ограничивает заданное значение диапазоном от 0 до 1
tex2d Выполняет просмотр двухмерной текстуры
tex3d Выполняет просмотр трехмерной объемной текстуры


Создание простого шейдера

В этом разделе вы создадите свой первый шейдер, используя HLSL. Сперва вы должны объявить неизменные и меняющиеся переменные шейдера:

// Матрица, получаемая от приложения - неизменная
// (Мировая * Вид * Проекция)
float4x4 matWVP : WorldViewProjection;

// Структура, используемая для входных вершин - меняющаяся
struct vertexInput
{
    float4 position : POSITION0;
};

// Структура, используемая для передачи выходных данных
// вершинного шейдера на вход пиксельного шейдера - меняющаяся
struct vertexOutput
{
    float4 hposition : POSITION;
    float3 color : COLOR0;
};

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

У структуры vertexInput есть единственный атрибут: местоположение вершины. В структуре vertexOutput два атрибута, и ими являются итоговое местоположение вершины и цвет. Итак, функция вершинного шейдера получает местоположение вершины и должна вывести итоговое местоположение и цвет.

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

// Код вершинного шейдера
pixelInput SimpleVS(vertexInput IN)
{
    pixelInput OUT;

    // Преобразуем местоположение вершины
    OUT.hposition = mul(IN.position, matWVP);
    OUT.color = float3(1.0f, 1.0f, 0.0f);

    return OUT;
}

В функции SimpleVS вы вычисляете местоположение выходной вершины трансформировав (умножив) ее посредством матрицы matWVP (которая является комбинацией мировой матрицы, матрицы вида и матрицы проекции). Выходной цвет вершины делается желтым, RGB(1, 1, 0). Теперь вы должны объявить функцию, используемую как точка входа пиксельного шейдера:

// Код пиксельного шейдера
float4 SimplePS(pixelInput IN) : COLOR0
{
    return float4(IN.color.rgb, 1.0f);
}

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

Эффекты

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

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

technique basicShader
{
    pass p0
    {
        VertexShader = compile vs_2_0 SimpleVS();
        PixelShader = compile ps_2_0 SimplePS();
    }
}

В технике basicShader всего один проход, названный p0. Внутри каждого прохода вы определяете, какие функции будут использованы в качестве точек входа вершинного и пиксельного шейдеров. В данном случае вы используете функцию SimpleVS как точку входа вершинного шейдера и функцию SimplePS как точку входа пиксельного шейдера. Вам также надо определить какая шейдерная модель будет использована при компиляции шейдеров. В данном случае вы используете шейдерную модель 2.0.

Шейдерные модели эволюционируют, начиная с DirectX 8.1, и XNA поддерживает шейдерные модели вплоть до 3.0. Каждая шейдерная модель отличается своими возможностями и позволяет создавать шейдеры с различным количеством команд. Например, операции динамического управления потоком выполнения (if, while и т.д.) для вершинных и пиксельных шейдеров доступны только в шейдерной модели версии 3.0 или выше. Таблица 8.5 показывает количество слотов инструкций, доступное в каждой из шейдерных моделей. Обратите внимание, что каждая функция HLSL может использовать один или несколько слотов инструкций, поскольку нет прямого отображения на команды ассемблера GPU.


Таблица 8.5. Количество слотов инструкций в шейдерных моделях



Версия шейдеров Количество инструкций

VS_1_1 128
VS_2_0 256
VS_2_A 256
VS_3_0 >= 512
PS_1_1 12 (4 текстурных и 8 арифметических)
PS_2_0 96 (32 текстурных и 64 арифметических)
PS_2_A 512
PS_3_0 >= 512


netlib.narod.ru< Назад | Оглавление | Далее >

Сайт управляется системой uCoz