Форум Статьи Контакты
Строительство — возведение зданий и сооружений, а также их капитальный и текущий ремонт, реконструкция, реставрация и реновация.

HLSL

Дата: 8-11-2020, 21:24 » Раздел: Статьи  » 

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>) <оператор>

Функции

математические функции

функции для работы с текстурами

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

Вершинные и фрагментные шейдеры имеют два типа входящих данных: 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 данные, которые передаются из вершинного буфера, а во фрагментном шейдере — интерполированные данные, полученные из вершинного шейдера.

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

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

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

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

Программы для создания шейдеров

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

  • RenderMonkey от ATI (ATI 3D Application Research Group)
  • ShaderWorks от Mad Software Inc
  • FXComposer от Nvidia
  • Shader Config

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

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

Примеры

простейший шейдер «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_matrix, 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) читает из текстурного сэмплера (из текстуры) цвет её текселя с заданными текстурными координатами. Это и будет цвет выводимого пикселя. */ }

простой шейдер «Головокружение»

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)); }

шейдер, имитирующий электрический разряд

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; }

пластилиновая модель

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; }

имитация деревянной поверхности

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
(голосов:0)

Пожожие новости
Комментарии

Ваше Имя:   Ваш E-Mail: