Урок 9. Шейдеры в Direct3D10

01.08.2012

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

Шейдеры

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

Сейчас шейдеры являются ключевым аспектом DirectXприложения. Фактически, трудно что-нибудь сделать без их использования. Вся графика игр, многочисленные спецэффекты, и тот реализм, который на сегодняшний день достигла графическая часть игр – это всё получилось благодаря использованию шейдеров. Взглянем лишь на некоторые примеры использования шейдеров:

  • Обычное применение: матрицы камеры и освещениями в вершинномшейдере, текстуры и определение текущего цвета пикселя в пиксельном шейдере
  • Композиции из нескольких текстур, использования глубоких текстур, для тонкой детализации ландшафта и моделей
  • Эффекты освещения и теней
  • Системы частиц – туман, задымление а также различные виды вспышек

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

Особенности компиляции и загрузки шейдера

Хотя шейдер является очень низкоуровневой структурой – он должен выполняться очень быстро, но вы можете его писать на языке, подобном C++, этот язык называется HLSL. Это потому, что шейдер на ходу компилируется в машинный код видеоускорителя. Кроме того, не нужен специальный компилятор. Язык HLSLявляется стандартным и его компиляция осуществляется на ходу любой 3dсистемой, например DirectXили OpenGL. Таким образом, вы просто указываете на исходный файл формата .fxи он автоматически загружается, компилируется и выполняется непосредственно в вашем 3dприложении.

Язык HLSL

Взглянем на пример шейдера с точки зрения программирования. Посмотрим на типичный код шейдера:

//------------------------------------------------------------------------------------
// Constant Buffer Variables
//------------------------------------------------------------------------------------
Texture2D g_txDiffuse;
SamplerState samLinear
{
    Filter = MIN_MAG_MIP_LINEAR;
    AddressU = Wrap;
    AddressV = Wrap;
};
 
struct VS_INPUT
{
    float3 Pos          : POSITION;         //position
    float3 Norm         : NORMAL;           //normal
    float2 Tex          : TEXCOORD0;        //texture coordinate
};
 
struct PS_INPUT
{
    float4 Pos          : SV_POSITION;
    float3 Norm         : TEXCOORD0;
    float2 Tex          : TEXCOORD1;
};
 
//------------------------------------------------------------------------------------
// Vertex Shader
//------------------------------------------------------------------------------------
PS_INPUT VS( VS_INPUT input )
{
    PS_INPUT output = (PS_INPUT)0;
    output.Pos = mul( float4(input.Pos,1), World );
    output.Pos = mul( output.Pos, View );
    output.Pos = mul( output.Pos, Projection );
    output.Norm = mul( input.Norm, World );
    output.Tex = input.Tex;
 
    return output;
}
 
//------------------------------------------------------------------------------------
// Pixel Shader
//------------------------------------------------------------------------------------
float4 PS( PS_INPUT input) : SV_Target
{
    //calculate lighting assuming light color is <1,1,1,1>
    float fLighting = saturate( dot( input.Norm, vLightDir ) );
    float4 outputColor = g_txDiffuse.Sample( samLinear, input.Tex ) * fLighting;
    outputColor.a = 1;
    return outputColor;
}
 
//------------------------------------------------------------------------------------
// Technique
//------------------------------------------------------------------------------------
technique10 Render
{
    pass P0
    {
        SetVertexShader( CompileShader( vs_4_0, VS() ) );
        SetGeometryShader( NULL );
        SetPixelShader( CompileShader( ps_4_0, PS() ) );
    }
}

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

Типы данных HLSL

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

Тип данных Примечание
Buffer Массив
Scalar Одно компонентная скалярная величина
Vector,Matrix Несколько компонентный вектор или матрица
Sampler, Shader, Texture Встроенные типы данных – сэмплер, шейдер, текстура
Struct, User Defined Пользовательский тип данных

Рассмотрим эти типы данных. Тип данных Scalar определяет скалярную величину и может быть одним из следующих:

bool
int
uint
half
float
double

Тип данных Vectorи Matrixобозначается добавлением количества компонент к типу данных scalar. НапримерFloat4 определяет четырехкомпонентный вектор пример определения вектора. Для матрицы, например Float4x4 добавляем NxN, то есть указываем размеренность матрицы. Пример определения вектора и матрицы:

float3 fVector = { 0.2f, 0.3f, 0.4f };
double3x3 dMatrix;   
float2x2 fMatrix = { 0.0f, 0.1, // row 1
                     2.1f, 2.2f // row 2  };

Типы Sampler используется для описания типа фильтрации текстуры. Тип Shaderиспользуется для техники. Тип Textureдля указания на используемую текстуру. Примеры определений для этих типов данных. Тип данных Sampler:

sampler MeshTextureSampler = 
sampler_state
{
    Texture = <g_MeshTexture>;
    MipFilter = LINEAR;
    MinFilter = LINEAR;
    MagFilter = LINEAR;
};

Тип данных Shader:

technique10 Render
{
    pass P0
    {
        SetVertexShader( CompileShader( vs_4_0, VS() ) );
        SetGeometryShader( NULL );
        SetPixelShader( CompileShader( ps_4_0, PS() ) );
    }
}

Тип данных Texture:

texture g_MeshTexture;
Output.RGBColor = tex2D(MeshTextureSampler, In.TextureUV) * In.Diffuse;

Тип данных Texture, еще один вариант:

Texture2D g_MeshTexture;
Output.RGBColor = g_MeshTexture.Sample(MeshTextureSampler, In.TextureUV) * In.Diffuse;

Операции ветвления кода в HLSL

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

Операция ветвления Примечание
break Операция прерывания цикла
continue Продолжение цикла
discard Специфическое ветвление для пиксельногошейдера
do Ветвление
for Цикл
if Условный переход
switch Операция выбора
while Ветвление

 

Операции ветвления в HLSLимеют тот же синтаксис, что и в языке C++.

Определения функций и блоки в HLSL

Остальная структура языка может быть сведена к следующей таблице:

Элемент Примечание
Функции Определение функций
Операции ветвления См. предыдущий раздел
Блоки Блок определяется символами {}
Выражение return Операция возвращения из блока функции
Выражения Любое математическое выражение а также оператор присваивания.
Операторы Пример символов операторов: +,-,*,/,=,+=,++,<<,>>,==,!=,>=,!
Встроенные функции Intrinsic Functions

Определение функций имеет некоторые характерные черты в HLSL. Об этом далее.

Типы данных, для вершинного и пиксельного шейдера

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

struct VS_INPUT
{
    float3 Pos          : POSITION;         //position
    float3 Norm         : NORMAL;           //normal
    float2 Tex          : TEXCOORD0;        //texture coordinate
};

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

Выходящие данные вершинногошейдера являются входящими данными пиксельного шейдера и имеют идентичный формат:

struct PS_INPUT
{
    float4 Pos          : SV_POSITION;
    float3 Norm         : TEXCOORD0;
    float2 Tex          : TEXCOORD1;
};

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

float 4 color= g_txDiffuse.Sample( ...
return color;

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

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

abs
sin
cos
dot
cross
fmod
log
mul
max
min
round
sqrt
tan
tex1d
tex2d
texCUBE

В этом отрывке кода из вершинного шейдера

output.Pos = mul( output.Pos, View );
output.Pos = mul( output.Pos, Projection );
output.Norm = mul( input.Norm, World );

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

Заключение

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

 

Заполнен: DirectX10
Присвоен тэг:

avatar

Об Авторе ()

Планета назначения, JO - 8703 - IV, обозначается светлой точкой на объемном экране корабля. К тому времени, как Робоид нанялся на юпитерианский круговой рейс, ему следовало бы стать главным инженером, но после Суховодного пионерского его вышибли, внеся в черный список, и высадили в Луна-Сити за то, что вместо слежения за приборами он провел время, программируя синтезатор пищи корабля строжайше запрещенной корабельными инструкциями последовательностью синтеза пива.

Комментирование закрыто.

Наверх