HLSL

Материал из Википедии — свободной энциклопедии
Перейти к: навигация, поиск

HLSL (англ. High Level Shader Language) — C-подобный язык высокого уровня для программирования шейдеров.

Был создан корпорацией Microsoft и включён в пакет DirectX 9.0

Типы данных[править | править вики-текст]

HLSL поддерживает скалярные типы, векторные типы, матрицы и структуры.

скалярные типы[править | править вики-текст]

  • bool — булев тип
  • int — 32 битовое знаковое целое
  • half — 16 битовое число с плавающей точкой
  • float — 32 битовое число с плавающей точкой
  • double — 64 битовое число с плавающей точкой

векторные типы[править | править вики-текст]

Пример: vector <float, 4> color;

Пример: float4 newcolor;

Пример: float oldcolor[4]

Пример: newcolor = float4(oldcolor[0], oldcolor[1], oldcolor[2], oldcolor[3])

матрицы[править | править вики-текст]

Пример: matrix <float, 4> view_matrix;

Пример: float 4x4 view_matrix;

структуры[править | править вики-текст]

struct vs_input {

float4 pos:POSITION;
float3 nor:NORMAL;
float2 uv:TEXCOORD0;

}; struct ps_input {

float4 pos:POSITION;
float3 nor:NORMAL;
float2 uv:TEXCOORD0;
float CustomVar;
texture2D CustomTexture;
//и так далее… :POSITION :NORMAL и т. д. это сентиматики, о них ниже.

};

Операторы[править | править вики-текст]

Операции Операторы
Арифметические -, +, *, /, %
Инкремент, декремент ++, --
Логические \|, ?:
Унарные !, -, +
Сравнения <, >, <=, >=, ==, !=
Назначение =, -=, +=, *=, /=
Приведение типов (тип)
Запятая ,
Член структуры .
Член массива [индекс]

Ветвления[править | править вики-текст]

if (выражение) <оператор> [else <оператор>]

Циклы[править | править вики-текст]

В HLSL различают 3 вида циклов:

  • do <оператор> while (<выражение>);
  • while (<выражение>) <оператор>;
  • for (<выражение1>; <выражение2>; <выражение3>) <оператор>

Функции[править | править вики-текст]

математические функции[править | править вики-текст]

abs(x) возвращает абсолютную величину каждого компонента x
acos(x) возвращает арккосинус каждого компонента x. Каждый компонент должен быть в диапазоне [-1, 1]
asin(x) возвращает арксинус каждого компонента x. Каждый компонент должен быть в диапазоне [-pi/2, pi/2]
atan(x) возвращает арктангенс каждого компонента x. Каждый компонент должен быть в диапазоне [-pi/2, pi/2]
ceil(x) возвращает наименьшее целое число, которое больше чем или равно x
cos(x) возвращает косинус x
cosh(x) возвращает гиперболический косинус x
clamp(x, a, b) Если x < a, то возвращает а, если x > b, то возвращает b, иначе возвращает x.
ddx(x) возвращает частную производную x относительно screen-space x-координаты
ddy(x) возвращает частную производную x относительно screen-space y-координаты
degrees(x) Конвертирование x с радианы в градусы
distance(a, b) возвращает расстояние между двумя точками a и b
dot(a, b) возвращает скалярное произведение двух векторов a и b
exp(x) возвращает экспоненту с основанием e, или ex
floor(x) возвращает самое большое целое число, которое является меньше чем или равным x
fwidth(x) возвращает abs(ddx(x))+abs(ddy(x))
len(v) Векторная длина
length(v) возвращает длину вектора v
lerp(a, b, s) возвращает a + s (b — a)
log(x) возвращает логарифм x
log10(x) возвращает десятичный логарифм x
mul(a, b) делает матричное умножение между a и b
normalize(v) возвращает нормированный вектор v
pow(x, y) возвращает xy
radians(x) конвертирует x из градусов в радианы
reflect(i, n) возвращает вектор отражения
refract(i, n, eta) возвращает вектор преломления.
rsqrt(x) возвращает 1 / sqrt(x)
saturate(x) Аналогично clamp(x,0,1)
sin(x) возвращает синус x.
sincos(x, out s, out c) возвращает синус и косинус x
sinh(x) возвращает гиперболический синус x
sqrt(x) возвращает квадратный корень каждого компонента
step(a, x) возвращает 1 если x >= a, иначе возвращает 0
tan(x) возвращает тангенс x
tanh(x) возвращает гиперболический тангенс x

функции для работы с текстурами[править | править вики-текст]

tex1D(s, t) Чтение из одномерной текстуры
s — sampler, t — скаляр.
tex1D(s, t, ddx, ddy) Чтение из одномерной текстуры, с производными
s — sampler, t, ddx, и ddy — скаляры.
tex1Dproj(s, t) Чтение из одномерной проективной текстуры
s — sampler, t — 4D вектор.
t делится на t.w перед выполнением функции.
tex1Dbias(s, t) Чтение из одномерной текстуры со смещением, s — sampler, t — 4-х мерный вектор.
Мип-уровень смещается на t.w до того, как производится поиск.
tex2D(s, t) Чтение из двухмерной текстуры
s — sampler, t — 2D вектор.
tex2D(s, t, ddx, ddy) Чтение из двухмерной текстуры, с производными.
s — sampler, t — 2D текстурные координаты. ddx, ddy- 2D вектора.
tex2Dproj(s, t) Чтение из двумерной проективной текстуры.
s — sampler, t — 4D вектор.
t делится на t.w перед выполнением функции.
tex2Dbias(s, t) Чтение из двумерной текстуры со смещением.
s — sampler, t — 4-х мерный вектор.
Мип-уровень смещается на t.w до того, как производится поиск.
tex3D(s, t) Чтение из трёхмерной текстуры.
s — sampler, t — 3D вектор.
tex3D(s, t, ddx, ddy) Чтение из трёхмерной текстуры, с производными.
s — sampler, t — 2D текстурные координаты, ddx, ddy — 3D вектора.
tex3Dproj(s, t) Чтение из трёхмерной проективной текстуры.
s — sampler, t — 4D вектор.
t делится на t.w перед выполнением функции.
tex3Dbias(s, t) Чтение из трёхмерной текстуры со смещением.
s — sampler, t — 4-х мерный вектор.
Мип-уровень смещается на t.w до того, как производится поиск.
texCUBE(s, t) Чтение из кубической текстуры.
s — sampler, t — 2D текстурные координаты.
texCUBE(s, t, ddx, ddy) Чтение из кубической текстуры.
s — sampler, t — 3D текстурные координаты, ddx, ddy — 3D вектора.
texCUBEproj(s, t) Чтение из кубической проективной текстуры.
s — sampler, t — 4D вектор.
t делиться на t.w перед выполнением функции.
texCUBEbias(s, t) Чтение из кубической текстуры.
sampler, t — 4D вектор.
Мип-уровень смещается на t.w до того, как производится поиск.

Входящие и исходящие данные для вершинного и пиксельного шейдеров[править | править вики-текст]

Вершинные и фрагментные шейдеры имеют два типа входящих данных: varying и uniform.

Uniform — данные, которые постоянны для многократного использования в шейдере. Объявление uniform данных в HLSL можно сделать двумя способами:

1)Объявить данные как extern переменную. Например:

float4 value;

float4 main () : COLOR
{
  return value;
}

2)Объявить данные через определитель uniform. Например:

float4 main (uniform float4 value) : COLOR
{
  return value;
}

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

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

Основные входящие семантические типы:

BINORMAL Бинормаль
BLENDWEIGHT Весовой коэффициент
BLENDINDICES Индекс весовой матрицы
COLOR Цвет
NORMAL Нормаль
POSITION Позиция
PSIZE Размер точки
TANGENT Тангент
TESSFACTOR Фактор тесселяции
TEXCOORD Текстурные координаты

Использование varying данных во фрагментном шейдере определяет состояние одного фрагмента. Основные входящие семантические типы:

COLOR Цвет
TEXCOORD Текстурные координаты

Исходящие данные для вершинного шейдера:

POSITION Позиция
PSIZE Размер точки
FOG Коэффициент «туманности» для вершины
COLOR Цвет
TEXCOORD Текстурные координаты

Исходящие данные для фрагментного шейдера:

COLOR Цвет
DEPTH Значение глубины

Программы для создания шейдеров[править | править вики-текст]

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

Также пиксельные шейдеры используются визуализаторами, например,

  • Milkdrop от Nullsoft — Этот плагин позволяет создавать шейдеры, зависящие от музыки.

Примеры [источник не указан 1725 дней][править | править вики-текст]

простейший шейдер «Texture mapping»[править | править вики-текст]

Код в этом листинге работает в ATI Rendermonkey и Nvidia FX composer. Для использования в кастомном движке нужно указать SamplerState и technique.

/* ========== ВЕРШИННЫЙ ШЕЙДЕР ========== */
/* world_matrix, view_matrix, proj_matrix необходимо получить из приложения, установив константы шейдера. 
Константы шейдера загружаются в регистры. */
float4x4 world_matrix; // мировая матрица
float4x4 view_matrix;  // матрица вида
float4x4 proj_matrix;  // матрица проекции
 
struct VS_OUTPUT // экземпляр этой структуры будет возвращать вершинный шейдер
{
   float4 Pos: POSITION0; /* POSITION0 и TEXCOORD0 - семантики, обозначающие слоты, из которых пиксельный 
шейдер будет в дальнейшем получать данные. Семантики, указанные здесь должны совпадать с семантиками во 
входных данных пиксельного шейдера. Имена переменных и их порядок может различаться.*/
   float2 TexCoord: TEXCOORD0;
};
 
VS_OUTPUT VS_Main(float4 InPos: POSITION0, float2 InTexCoord : TEXCOORD0) /* Вершинный шейдер выполняется 
для каждой вершины выводимого объекта. InPos и InTexCoord получены из данных stream-mapping'a */
{
   VS_OUTPUT Out;
 
   float4x4 worldViewProj_matrix = mul(world_matrix, view_matrix);
   worldViewProj_matrix = mul(worldViewProj, proj_matrix);
 
   Out.Pos = mul(InPos,  worldViewProj_matrix); // трансформируем вершину в clip-space
   Out.TexCoord = InTexCoord; // текстурные координаты мы получаем извне, ничего модифицировать не нужно
 
   return Out;
}
 
/* ========== ПИКСЕЛЬНЫЙ ШЕЙДЕР ========== */
 
sampler2D baseMap; // sampler2D - специальный слот "текстурный слот" в который можно загрузить текстуру.
 
float4 PS_Main(float2 texCoord: TEXCOORD0) : COLOR0 / *пиксельный шейдер всегда возвращает цвет выводимого 
пикселя с семантикой COLOR0 в формате float4. Пиксельный шейдер выполняется для каждого пикселя выводимого 
на экран изображения (а не для каждого текселя текстуры) */
{
   return tex2D( baseMap, texCoord ); /* tex2d(sampler2D, float2) читает из текстурного сэмплера 
(из текстуры) цвет ее текселя с заданными текстурными координатами. Это и будет цвет выводимого пикселя. */
}

простой шейдер «Головокружение»[править | править вики-текст]

HLSL dizzy effect.png
float4x4 view_proj_matrix: register(c0);
 
struct VS_OUTPUT 
{
   float4 Pos: POSITION;
   float2 texCoord: TEXCOORD0;
};
 
VS_OUTPUT VS_Dizzy(float4 Pos: POSITION)
{
   VS_OUTPUT Out;
 
   Pos.xy = sign(Pos.xy);
 
   Out.Pos = float4(Pos.xy, 0, 1);
   Out.texCoord = Pos.xy;
 
   return Out;
}
 
float time_0_X: register(c0);
float rings: register(c1);
float speed: register(c2);
float exponent: register(c3);
 
float4 PS_Dizzy(float2 texCoord: TEXCOORD0) : COLOR 
{
   float ang = atan2(texCoord.x, texCoord.y);
   float rad = pow(dot(texCoord, texCoord), exponent);
 
   return 0.5 * (1 + sin(ang + rings * rad + speed * time_0_X));
}

шейдер, имитирующий электрический разряд[править | править вики-текст]

HLSL electricity effect.jpg
struct VS_OUTPUT 
{
   float4 Pos: POSITION;
   float2 texCoord: TEXCOORD;
};
 
VS_OUTPUT VS_Electricity(float4 Pos: POSITION)
{
   VS_OUTPUT Out;
 
   // Clean up inaccuracies
   Pos.xy = sign(Pos.xy);
 
   Out.Pos = float4(Pos.xy, 0, 1);
   Out.texCoord = Pos.xy;
 
   return Out;
}
 
float4 color: register(c1);
float glowStrength: register(c2);
float height: register(c3);
float glowFallOff: register(c4);
float speed: register(c5);
float sampleDist: register(c6);
float ambientGlow: register(c7);
float ambientGlowHeightScale: register(c8);
float vertNoise: register(c9);
float time_0_X: register(c0);
sampler Noise: register(s0);
 
float4 PS_Electricity(float2 texCoord: TEXCOORD) : COLOR 
{
   float2 t = float2(speed * time_0_X * 0.5871 - vertNoise * abs(texCoord.y), speed * time_0_X);
 
   // Sample at three positions for some horizontal blur
   // The shader should blur fine by itself in vertical direction
   float xs0 = texCoord.x - sampleDist;
   float xs1 = texCoord.x;
   float xs2 = texCoord.x + sampleDist;
 
   // Noise for the three samples
   float noise0 = tex3D(Noise, float3(xs0, t));
   float noise1 = tex3D(Noise, float3(xs1, t));
   float noise2 = tex3D(Noise, float3(xs2, t));
 
   // The position of the flash
   float mid0 = height * (noise0 * 2 - 1) * (1 - xs0 * xs0);
   float mid1 = height * (noise1 * 2 - 1) * (1 - xs1 * xs1);
   float mid2 = height * (noise2 * 2 - 1) * (1 - xs2 * xs2);
 
   // Distance to flash
   float dist0 = abs(texCoord.y - mid0);
   float dist1 = abs(texCoord.y - mid1);
   float dist2 = abs(texCoord.y - mid2);
 
   // Glow according to distance to flash
   float glow = 1.0 - pow(0.25 * (dist0 + 2 * dist1 + dist2), glowFallOff);
 
   // Add some ambient glow to get some power in the air feeling
   float ambGlow = ambientGlow * (1 - xs1 * xs1) * (1 - abs(ambientGlowHeightScale * texCoord.y));
 
   return (glowStrength * glow * glow + ambGlow) * color;
}

пластилиновая модель[править | править вики-текст]

HLSL plastic example.jpg
float4x4 view_proj_matrix: register(c0);
 
float4 view_position: register(c4);
 
struct VS_OUTPUT 
{
	float4 Pos: POSITION;
	float3 normal: TEXCOORD0;
	float3 viewVec: TEXCOORD1;
};
 
VS_OUTPUT VS_Plastic(float4 Pos: POSITION, float3 normal: NORMAL)
{
	VS_OUTPUT Out;
 
	Out.Pos = mul(view_proj_matrix, Pos);
 
	Out.normal = normal;
	Out.viewVec = view_position - Pos;
 
	return Out;
}
 
float4 color: register(c0);
 
float4 PS_Plastic(float3 normal: TEXCOORD0, float3 viewVec: TEXCOORD1) : COLOR 
{
	float v = 0.5 * (1 + dot(normalize(viewVec), normal));
 
	return v * color;
}

имитация деревянной поверхности[править | править вики-текст]

HLSL wood example.jpg
float trunk_wobble_frequency;
 
float4x4 view_matrix;
float4x4 view_proj_matrix;
 
float4x4 texture_matrix0;
float4x4 texture_matrix1;
float4x4 texture_matrix2;
 
struct VS_OUTPUT
{
	float4 Pos : POSITION;
	float3 TCoord0 : TEXCOORD0;
	float3 TCoord1 : TEXCOORD1;
	float3 TCoord2 : TEXCOORD2;
	float3 TCoord3 : TEXCOORD3;
	float3 TCoord4 : TEXCOORD4;
	float3 TCoord6 : TEXCOORD6;
	float3 TCoord7 : TEXCOORD7;
};
 
VS_OUTPUT VS_Wood (float4 vPosition: POSITION, float3 vNormal: NORMAL)
{
	VS_OUTPUT Out = (VS_OUTPUT) 0;
	float4 TransformedPshade;
 
	// Transform position to clip space
	Out.Pos = mul (view_proj_matrix, vPosition);
 
	// Transform Pshade (using texture matrices) and output to pixel shader
	TransformedPshade = mul (texture_matrix0, vPosition);
	Out.TCoord0 = TransformedPshade;
	Out.TCoord1 = mul (texture_matrix1, vPosition);
	Out.TCoord2 = mul (texture_matrix2, vPosition);
 
	// Create two coordinates for sampling noise volume to get wobble
	Out.TCoord3 = float3(trunk_wobble_frequency * TransformedPshade.z, 0.0f, 0.0f);
	Out.TCoord4 = float3(trunk_wobble_frequency * TransformedPshade.z + 0.5f, 0.0f, 0.0f);
 
	// Transform position and normal to eye space
	Out.TCoord6 = mul (view_matrix, vPosition);
	Out.TCoord7 = mul (view_matrix, vNormal);
 
	return Out;
}
 
float4 light_pos;
float4 eye_pos;
float4 light_wood_color;
float4 dark_wood_color;
 
float noise_amplitude;
float trunk_wobble_amplitude;
float ring_freq;
 
sampler noise_volume;
sampler pulse_train;
sampler variable_specular;
 
float4 PS_Wood (float3 Pshade0 : TEXCOORD0,
				float3 Pshade1 : TEXCOORD1,
				float3 Pshade2 : TEXCOORD2,
				float3 zWobble0 : TEXCOORD3,
				float3 zWobble1 : TEXCOORD4,
				float3 Peye : TEXCOORD6,
				float3 Neye : TEXCOORD7) : COLOR
{
	float3 coloredNoise;
	float3 wobble;
 
	// Construct colored noise from three samples
	coloredNoise.x = tex3D (noise_volume, Pshade0);
	coloredNoise.y = tex3D (noise_volume, Pshade1);
	coloredNoise.z = tex3D (noise_volume, Pshade2);
 
	wobble.x = tex3D (noise_volume, zWobble0);
	wobble.y = tex3D (noise_volume, zWobble1);
	wobble.z = 0.5f;
 
	// Make signed
	coloredNoise = coloredNoise * 2.0f - 1.0f;
	wobble = wobble * 2.0f - 1.0f;
 
	// Scale noise and add to Pshade
	float3 noisyWobblyPshade = Pshade0 + coloredNoise * noise_amplitude + wobble * trunk_wobble_amplitude;
 
	float scaledDistFromZAxis = sqrt(dot(noisyWobblyPshade.xy, noisyWobblyPshade.xy)) * ring_freq;
 
	// Lookup blend factor from pulse train
	float4 blendFactor = tex1D (pulse_train, scaledDistFromZAxis);
 
	// Blend wood colors together
	float4 albedo = lerp (dark_wood_color, light_wood_color, blendFactor.x);
 
	// Compute normalized vector from vertex to light in eye space (Leye)
	float3 Leye = (light_pos - Peye) / length(light_pos - Peye);
 
	// Normalize interpolated normal
	Neye = Neye / length(Neye);
 
	// Compute Veye
	float3 Veye = -(Peye / length(Peye));
 
	// Compute half-angle
	float3 Heye = (Leye + Veye) / length(Leye + Veye);
 
	// Compute N.H
	float NdotH = clamp(dot(Neye, Heye), 0.0f, 1.0f);
 
	// Scale and bias specular exponent from pulse train into decent range
	float k = blendFactor.z;
 
	// Evaluate (N.H)^k via dependent read
	float specular = tex2D (variable_s

Ссылки[править | править вики-текст]