| Россия |
Использование шейдеров с помощью языка HLSL. Графический процессор
Следующий шаг – получение указателя на откомпилированный код шейдера. Реализуется этот шаг вызовом метода CreatePixelShader() интерфейса IDirect3DDevice9.
| C++ |
LPDIRECT3DPIXELSHADER9 PixelShader = NULL;
device->CreatePixelShader( (DWORD*)Code->GetBufferPointer(),
&PixelShader ); |
| Pascal |
var PixelShader: IDirect3DPixelShader9; ... device.CreatePixelShader(Code.GetBufferPointer, PixelShader); |
Следующий шаг заключается в установке пиксельного шейдера в функции рендеринга. Осуществляется это путем вызова метода SetPixelShader() интерфейса IDirect3DDevice9, где в качестве параметра передается указатель на пиксельный шейдер.
Рассмотрим теперь что из себя представляет код пиксельного шейдера на языке HLSL. Как и в случае с вершинным шейдером, код пиксельного шейдера можно формально разбить на четыре раздела: область глобальных переменных, разделы описания входной и выходной структур и основная процедура обработки. В самом простейшем случае пиксельный шейдер – процедура, приминающая на вход цвет пикселя и выдающая также цвет пикселя.
struct PS_INPUT
{
float4 color: COLOR;
};
struct PS_OUTPUT
{
float4 color : COLOR;
};
PS_OUTPUT main (PS_INPUT input)
{
PS_OUTPUT output;
output.color = input.color;
return output;
};В данном случае пиксельный шейдер фактически просто "проталкивает" пиксель дальше по графическому конвейеру, не подвергая его никакой обработке. Рассмотрим несколько способов возможной обработки точек в пиксельном шейдере на примере плоского цветного треугольника.
| "проталкивание" пикселя | output.color = input.color; | |
| инвертирование цветов | output.color = 1-input.color; | |
| увеличение яркости | output.color = 2*input.color; | |
| уменьшение яркости | output.color = 0.5*input.color; | |
| блокирование цветового канала | output.color = input.color; output.color.r = 0; |
|
| сложная обработка | output.color.r=0.5*input.color.r; output.color.g=2.0*input.color.g; output.color.b=input.color.b*input.color.b; |
Так как пиксельные шейдеры предназначены для замены блока мультитекстурирования, то рассмотрим каким образом происходит обработка текселей текстур. Для работы с текстурами в пиксельном шейдере предусмотрены так называемые семплеры. Семплер представляет собой текстуру, и набор правил (режим адресации текстурных координат, их индекс и тип установленной фильтрации текстур) для извлечения определенного текселя. Выбор текселя осуществляется с помощью функции tex2D(), которая имеет два параметра: название семплера и текстурные координаты. Ниже приведен пример пиксельного шейдера, в котором присутствует функция выборки текселя из текстуры.
sampler tex0;
struct PS_INPUT
{
float2 base : TEXCOORD0;
};
struct PS_OUTPUT
{
float4 diffuse : COLOR0;
};
PS_OUTPUT Main (PS_INPUT input)
{
PS_OUTPUT output;
output.diffuse = tex2D(tex0, input.base);
return output;
};В первой строке шейдера объявляется семплер (tex0). Операция выбора текселя из семплера называют семплированием. Следует заметить, что входная структура шейдера (PS_INPUT) содержит лишь текстурные координаты пикселя. Вообще говоря, в пиксельный шейдер можно передавать те данные, которые программист считает нужными (цвет вершины, вектор нормали, положение источника света и т.д.). Например, ниже приводится пример, в котором входная структура пиксельного шейдера содержит цвет и двое текстурных координат.
struct PS_INPUT
{
float2 uv0 : TEXCOORD0;
float2 uv1 : TEXCOORD1;
float4 color : COLOR0;
};Пусть у нас вершина описана через положение на плоскости (преобразованная вершина), цвет и две текстурные координаты:
| C++ |
struct MYVERTEX
{
FLOAT x, y, z, rhw;
DWORD color;
FLOAT u1, v1;
FLOAT u2, v2;
}
#define MY_FVF (D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX2); |
| Pascal |
type
MyVertex = packed record
x, y, z, rhw: Single;
color: DWORD;
u1,v1: Single;
u2,v2: Single;
end;
const
MY_FVF = D3DFVF_XYZRHW or D3DFVF_DIFFUSE or D3DFVF_TEX2; |
Рассмотрим пример мультитекстурирования на примере следующих исходных данных. Две заданные текстуры и способ закраски примитива (квадрата) показаны ниже.
Пример пиксельного шейдера, реализующего мультитекстурирование показан ниже.
sampler tex0;
sampler tex1;
struct PS_INPUT
{
float2 uv0 : TEXCOORD0;
float2 uv1 : TEXCOORD1;
float4 color: COLOR0;
};
struct PS_OUTPUT
{
float4 diffuse : COLOR0;
};
PS_OUTPUT Main (PS_INPUT input)
{
PS_OUTPUT output;
float4 texel0 = tex2D(tex0, input.uv0);
float4 texel1 = tex2D(tex1, input.uv1);
output.diffuse = ...;
return output;
};Некоторые способы взаимодействия двух этих поверхностей (текстуры и цветного квадрата) представлены в таблице.












