Листинг 1
struct MyVertexInputs {
float3 vxPosition : POSITION;
float3 vxNormal : NORMAL;
};
Листинг 2
technique noPixelShaderVersion
{...};
technique PixelShaderVersion
{...};
technique FixedFunctionVersion
{...};
technique LowDetailVersion
{...};
Листинг 3
technique PixelShaderVersion
{
pass p0 {
VertexShader = compile vs_1_1 goochVS(wvp,liteColor,lightPos);
}
}
Листинг 4
vertexOutput vertexShader(
appdata IN,
uniform float4 liteColor,
uniform float4 darkColor,
uniform float3 LightPos)
{
vertexOutput OUT;
/* Здесь проводим всевозможные вычисления c данными вершин и записываем их в OUT */
return OUT;
}
pixelOutput pixelShader(
vertexOutput IN,
uniform sampler2D colorMap)
{
pixelOutput OUT;
/* Здесь проводим всевозможные вычисления c данными пикселов и записываем их в OUT */
return OUT;
}
Листинг 5
float4 lightPos : Position
<
string Object = ?PointLight?;
string Space = ?World?;
> = {100.0f, 100.0f, 100.0f, 0.0f};
float4 liteColor : Diffuse
<
string Desc = ?Basic Surface Color?;
> = {0.8f, 0.5f, 0.1f, 1.0f};
Листинг 6
/* Первые две строки позволяют задать текстовое описание шейдера,
которое будет отображено в поле настройки */
string Category = ?Учебные шейдеры?;
string description = ?Мой первый шейдер?;
/* Ниже мы объявляем внешнюю переменную — видовую матрицу преобразования.
Ее использование обязательно
в вершинном шейдере для корректного отображения модели */
float4x4 wvp : WorldViewProj;
float4 lightPos : Position
<
string Object = ?PointLight?;
string Space = ?World?;
> = {100.0f, 100.0f, 100.0f, 0.0f};
float4 liteColor : Diffuse
<
string Desc = ?Basic Surface Color?;
> = {0.8f, 0.5f, 0.1f, 1.0f};
/* Объявим структуру входных данных для вершинного шейдера. На его вход будут поданы
координаты вершины (POSITION) и ее нормаль (NORMAL) */
struct appdata {
float4 Position : POSITION;
float4 Normal : NORMAL;
};
/* Выходная структура, в которой используется дополнительное поле цвета вершины */
struct vertexOutput {
float4 ps : POSITION;
float4 diffCol : COLOR0;
};
/* Объявляем функцию, выполняющую роль вершинного шейдера, в ее входных параметрах задаются
импортированные из внешней программы переменные */
vertexOutput goochVS(appdata IN,
uniform float4x4 wvp,
uniform float4 liteColor,
uniform float4 LightPos)
{
/* OUT - структура, которую мы после возвратим из функции */
vertexOutput OUT;
/* Это простейший пример преобразований в шейдере.
Сначала мы находим скалярное произведение между нормалью
к вершине и позицией источника света.
Напомню, что его значение будет стремиться к нулю,
если угол между векторами приближается к 90°.
Далее полю цвета выходной структуры присваиваем
заданный пользователем цвет, деленный на косинус полученного значения.
Поделив цвет на косинус, мы тем самым создаем неравномерное
распределение цветовых составляющих в пространстве.
Результат смотрите на рис.3 */
float ug = dot(IN.Normal, LightPos);
OUT.diffCol = liteColor/cos(ug);
/* Это обязательная операция для всех вершинных шейдеров. Каждая вершина
перемножается на видовую матрицу преобразований */
OUT.ps = mul(wvp, IN.Position);
/* И наконец, возвращаем результат пиксельному шейдеру, которого
в нашем случае просто нет, а значит, результат поступает сразу на выход из шейдера */
return OUT;
}
technique PixelShaderVersion
{
pass p0 {
/* Таким образом мы определяем, что вышеописанная функция
является шейдером и должна быть компилирована.
На самом деле в теле эффектов можно использовать
и старый ?ассемблероподобный? код, но тогда нужно указывать asm вместо compile.
Аббревиатура vs_1_1 определяет версию требуемого оборудования,
на котором сможет работать данный шейдер.
В данном случае речь идет об оборудовании,
поддерживающем шейдеры версии 1.1 (GeForce3 поддерживает 1.3) */
VertexShader = compile vs_1_1 goochVS(wvp,liteColor,lightPos);
}
}
technique NoPixelShaderVersion
{
pass p0 {
VertexShader = compile vs_1_1 goochVS(wvp,liteColor,lightPos);
}
}