XNA для начинающих. Введение в шейдеры

XNA для начинающих. Введение в шейдеры

Программируемый конвейер

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

Графический конвейер состоит из нескольких этапов, рассмотрим каждый из этих этапов:

На вход графического конвейра поступает информация о вершинах и графических примитивах, которые нужно рисовать на экране.

  • Vertex Data – информация о вершинах в вершинных буферах
  • Primitive Data – информация об используемых примитивах (точках, линиях, треугольниках)
  • Tesselation – разбиение сложных объектов на вершины и треугольники, сохранение их в вершинные буферы

    Информация о вершинах поступает на этап Vertex Processing.

  • Vertex Processing – геометрические преобразования над вершинами, такие как аффинные преобразования, на этом этапе выполняются преобразования из локальных координат объектов в экранные. Также на этом этапе производится вычисление различных параметров вершинах (например, интенсивности освещения для модели закраси по Гуро)
  • Geometry Processing – отсечение невидимых объектов, граней и другие геометрические операции

Далее информация о каждом пикселе поступает на этап Pixel Processing, на котором вычисляется значение цвета пикселя.

  • Pixel Processing – окрашивание, текстурирование
  • Texture Sampler, Texture Surface – поволяют рабоать с тексурами
  • Pixel Rendering – На данном этапе получается итоговое значение цвета пикселя и рисуется на экране

У данного подхода есть определенные недостатки:

  • Графический конвейер действует по заранее заданной программе и программист, ни каким образом, не может повлиять на ход обработки трехмерных объектов.

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

  • Программируемый конвейер и шейдеры позволяют изменить данную программу на этапах:
    • Vertex Processing – для обработки каждой вершины
    • Pixel Processing — для обработки каждого пикселя

Важно отметить, что XNA поддерживает ТОЛЬКО программируемый конвейер, это означает, что на работы приложений, разработанных на XNA Framework, необходима видео-карта поддерживающая программируемый конвейер определнной версии, а также тот факт, что в XNA приложения нельзя использовать стандартные методы графического конвейера и для всех операций необходимо разрабатывать собственные шейдеры.

К счастью, в XNA Framework содержится класс BasicEffect, который реализует простой шейдер (который практически повторяет реализацию стандартного графического конвейера). Данный класс избавляет начинающих разработчиков от изучения и разработки собственных шейдеров, что способствует более быстрой разработке программ.

Таким образом, BasicEffect – это встроенная в XNA реализация базового шейдера, он поддерживает:

  • Источники света
  • Попиксельное освещение
  • Туман
  • Текстурирование
  • И т.д.

Реализацию BasicEffect можно скачать с сайта creators.xna.com

http://creators.xna.com/en-US/utilities/basiceffectshader

На самом деле, SpriteBatch (основной класс для работы с двумерной графикой) также реализует шейдер и может быть скачан по адресу:

http://creators.xna.com/en-us/utilities/spritebatchshader

Стоит отметить, что XNA Framework использует формат описания шейдеров аналогичный формату, используемому в DirectX. Таким образом, можно легко найти достаточно большое количество материала по шейдерам на сайтах-сообществах DirectX и HLSL. Также удобно использовать библиотеки, такие как библиотека nVidia.

DirectX 9 и XNA 3.0 поддерживают 2 вида шейдеров

  • Вершинный (Vertex Shader)

В нем выполняются операции над вершинами: трансформации, смещения, вычисления параметров материала в вершинах и т.д.

Вершинный шейдер оперирует данными, сопоставленными с вершинами многогранников. К таким данным, в частности, относятся координаты вершины в пространстве, текстурные координаты, тангенс-вектор, вектор бинормали, вектор нормали. Вершинный шейдер может быть использован для видового и перспективного преобразования вершин, генерации текстурных координат, расчета освещения и т. д. [wikipedia]

  • Пиксельный (Pixel Shader) (В некоторых API, в частности openGL, называется Фрагментарным шейдером)

В нем выполняются операции над пикселями: освещение, текстурирование и т.д.

Фрагментный шейдер работает с фрагментами изображения. Под фрагментом изображения в данном случае понимается пиксель, которому поставлен в соответствие некоторый набор атрибутов, таких как цвет, глубина, текстурные координаты. Фрагментный шейдер используется на последней стадии графического конвейера для формирования фрагмента изображения. [wikipedia]

Начиная с версии 10 DirectX поддерживает также и геометрические шейдеры, однако, поскольку XNA Framework на сегодняшний день базируется на DirectX версии 9, геометрические шейдеры в нем не поддерживаются.

История развития шейдров

DirectX ASM – По синтаксису сходен с Ассемблером. Существует несколько версий, различающихся по набору команд, а также по требуемому оборудованию. Существует разделение на вершинные (vertex) и пиксельные (pixel) шейдеры.

  • HLSL – High Level Shader Language – С-подобный язык.
  • Поддерживаются различные модели шейдеров:
    • Shader model 1
    • Shader model 2
    • Shader model 3
      • Различаются максимальным количеством инструкций в шейдерах, доступными функциями и т.д.
  • Другие примеры шейдерных языков:
  • Cg – Разработан nVidia совместно с Microsoft (такой же по сути язык от Microsoft называется HLSL, включён в DirectX 9). Cg расшифровывается как C for Graphics. Язык действительно очень похож на C, он использует схожие типы (int, float, а также специальный 16-битный тип с плавающей запятой — half). Поддерживаются функции и структуры. Язык обладает своеобразными оптимизациями в виде упакованных массивов (packed arrays) — объявления типа «float a[4]» и «float4 a» в нём соответствуют разным типам. Второе объявление и есть упакованный массив, операции с упакованным массивом выполняются быстрее, чем с обычными. Несмотря на то, что язык разработан nVidia, он без проблем работает и с видеокартами ATI. Однако следует учесть, что все шейдерные программы обладают своими особенностями, которые следует получить из специализированных источников. [wikipedia]
  • GLSL – Шейдерный язык OpenGL носит название GLSL (The OpenGL Shading Language). GLSL основан на языке ANSI C. Большинство возможностей языка ANSI C сохранено, к ним добавлены векторные и матричные типы данных, часто применяющиеся при работе с трехмерной графикой. В контексте GLSL шейдером называется независимо компилируемая единица, написанная на этом языке. Программой называется набор откомпилированных шейдеров, связанных вместе. [Wikipedia]

    В качестве примера шейдерной программы на языке HLSL приведу пример стандартного шейдера SpriteBatch:

    //——————————————————————————

    // SpriteBatch.fx

    //

    // Microsoft XNA Community Game Platform

    // Copyright (C) Microsoft Corporation. All rights reserved.

    //——————————————————————————

    // Input parameters.

    float2 ViewportSize : register(c0);

    float2 TextureSize : register(c1);

    float4x4 MatrixTransform : register(c2);

    sampler TextureSampler : register(s0);

    #ifdef XBOX360

    // Vertex shader for rendering sprites on Xbox.

    void SpriteVertexShader(int index : INDEX,

    out float4 outputPosition : POSITION0,

    out float4 outputColor : COLOR0,

    out float2 outputTexCoord : TEXCOORD0)

    {

    // Read input data from the vertex buffer.

    float4 source;

    float4 destination;

    float4 originRotationDepth;

    float4 effects;

    float4 color;

    int vertexIndex = index / 4;

    int cornerIndex = index % 4;

    asm

    {

    vfetch source, vertexIndex, texcoord0

    vfetch destination, vertexIndex, texcoord1

    vfetch originRotationDepth, vertexIndex, texcoord2

    vfetch effects, vertexIndex, texcoord3

    vfetch color, vertexIndex, texcoord4

    };

    // Unpack into local variables, to make the following code more readable.

    float2 texCoordPosition = source.xy;

    float2 texCoordSize = source.zw;

    float2 position = destination.xy;

    float2 size = destination.zw;

    float2 origin = originRotationDepth.xy;

    float rotation = originRotationDepth.z;

    float depth = originRotationDepth.w;

    // Which of the four sprite corners are we currently shading?

    float2 whichCorner;

    if (cornerIndex == 0) whichCorner = float2(0, 0);

    else if (cornerIndex == 1) whichCorner = float2(1, 0);

    else if (cornerIndex == 2) whichCorner = float2(1, 1);

    else whichCorner = float2(0, 1);

    // Calculate the vertex position.

    float2 cornerOffset = (whichCorner — origin / texCoordSize) * size;

    // Rotation.

    float cosRotation = cos(rotation);

    float sinRotation = sin(rotation);

    position += mul(cornerOffset, float2x2(cosRotation, sinRotation, -sinRotation, cosRotation));

    // Apply the matrix transform.

    outputPosition = mul(float4(position, depth, 1), transpose(MatrixTransform));

    // Half pixel offset for correct texel centering.

    outputPosition.xy -= 0.5;

    // Viewport adjustment.

    outputPosition.xy /= ViewportSize;

    outputPosition.xy *= float2(2, -2);

    outputPosition.xy -= float2(1, -1);

    // Texture mirroring.

    whichCorner = lerp(whichCorner, 1 — whichCorner, effects);

    // Compute the texture coordinate.

    outputTexCoord = (texCoordPosition + whichCorner * texCoordSize) / TextureSize;

    // Simple color output.

    outputColor = color;

    }

    #else

    // Vertex shader for rendering sprites on Windows.

    void SpriteVertexShader(inout float4 position : POSITION0,

    inout float4 color : COLOR0,

    inout float2 texCoord : TEXCOORD0)

    {

    // Apply the matrix transform.

    position = mul(position, transpose(MatrixTransform));

    // Half pixel offset for correct texel centering.

    position.xy -= 0.5;

    // Viewport adjustment.

    position.xy /= ViewportSize;

    position.xy *= float2(2, -2);

    position.xy -= float2(1, -1);

    // Compute the texture coordinate.

    texCoord /= TextureSize;

    }

    #endif

    // Pixel shader for rendering sprites (shared between Windows and Xbox).

    void SpritePixelShader(inout float4 color : COLOR0, float2 texCoord : TEXCOORD0)

    {

    color *= tex2D(TextureSampler, texCoord);

    }

    technique SpriteBatch

    {

    pass

    {

    VertexShader = compile vs_1_1 SpriteVertexShader();

    PixelShader = compile ps_1_1 SpritePixelShader();

    }

    }

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

    GraphicsDeviceCapabilities caps =     graphics.GraphicsDevice.GraphicsDeviceCapabilities;

    if (caps.MaxPixelShaderProfile == ShaderProfile.PS_3_0)

    {

    // поддерживается shader mode 3

    }

    Инструменты разработки

    Программирование и отладка шейдров является сложной задачей, Visual Studio не имеет встроенных средств работы с шейдерами (имеется подсветка кода на High Level Shader Language и некоторые элементы IntelliSence). Однако такие средства предлагаются сторонними производителями.

    Можно отметить следующие популярные и удобные инструменты для работы с шейдерами

    • nVidia FX Composer

    http://developer.nvidia.com/object/fx_composer_home.html

    • AMD RenderMonkey

    http://developer.amd.com/GPU/RENDERMONKEY/Pages/default.aspx


    Если Вам нужна более подробная информация о шейдерах и High Level Shader Language, обратитесь к следующему материалу:

    • MSDN Library -> Win32 and COM Development -> Graphics and Multimedia -> DirectX -> SDK Documentation -> DirectX SDK -> DirectX Graphics -> HLSL
Реклама
Запись опубликована в рубрике Uncategorized. Добавьте в закладки постоянную ссылку.

Добавить комментарий

Заполните поля или щелкните по значку, чтобы оставить свой комментарий:

Логотип WordPress.com

Для комментария используется ваша учётная запись WordPress.com. Выход / Изменить )

Фотография Twitter

Для комментария используется ваша учётная запись Twitter. Выход / Изменить )

Фотография Facebook

Для комментария используется ваша учётная запись Facebook. Выход / Изменить )

Google+ photo

Для комментария используется ваша учётная запись Google+. Выход / Изменить )

Connecting to %s