Справочные материалы по переносу с GLSL на HLSL

Вы переносите код с GLSL на HLSL, когда портируете графическую архитектуру с OpenGL ES 2.0 на Direct3D 11, чтобы создавать игры для универсальной платформы Windows (UWP). Язык GLSL, о котором пойдет речь в этом разделе, совместим с OpenGL ES 2.0. Язык HLSL совместим с Direct3D 11. Подробнее об отличиях Direct3D 11 от предыдущих версий Direct3D см. в разделе Сопоставление компонентов.

Сравнение OpenGL ES 2.0 и Direct3D 11

Между OpenGL ES 2.0 и Direct3D 11 много общего. У них похожие конвейеры отрисовки и графические компоненты. Но Direct3D 11 представляет собой реализацию отрисовки и API, а не спецификацию. OpenGL ES 2.0 является спецификацией отрисовки и API, а не реализацией. В целом Direct3D 11 и OpenGL ES 2.0 отличаются в следующем.

OpenGL ES 2.0 Direct3D 11
Не зависящая от оборудования и операционной системы спецификация с реализациями, предоставленными поставщиком Реализация аппаратной абстракции Майкрософт и сертификация на платформах Windows
Отделенная для поддержки многообразия оборудования среда выполнения управляет большей частью ресурсов Прямой доступ к аппаратной структуре; приложение может управлять ресурсами и обработкой
Предоставляет модули более высокого уровня через сторонние библиотеки (например, SDL) Модули более высокого уровня, такие как Direct2D, основаны на модулях более низкого уровня, чтобы упростить разработку приложений для Windows
Поставщики оборудования различаются с помощью расширений Майкрософт добавляет к API универсальные дополнительные компоненты, чтобы они не были специфическими ни для одного конкретного поставщика

 

GLSL и HLSL отличаются в следующем.

GLSL HLSL
Процессуальный, сконцентрированный на этапах (как C) Объектно-ориентированный, сконцентрированный на данных (как C++)
Компиляция шейдера интегрирована в графический API Компилятор HLSL компилирует шейдер в промежуточное двоичное представление, прежде чем Direct3D передает его драйверу.
Примечание Это двоичное представление не зависит от оборудования. Оно обычно компилируется во время сборки приложения, а не во время его выполнения.
 
Модификаторы хранилищ переменных Буферы констант и передачи данных через объявления входных макетов

Типы

Стандартный тип вектора: vec2/3/4

lowp, mediump, highp

Стандартный тип вектора: float2/3/4

min10float, min16float

texture2D [функция] texture.Sample [тип_данных.функция]
sampler2D [тип_данных] Texture2D [тип_данных]
Развернутые по строкам матрицы (по умолчанию) Развернутые по столбцам матрицы (по умолчанию)
Примечание Используйте модификатор типа row_major , чтобы изменить макет для одной переменной. Подробнее см. Синтаксис переменной. Вы также можете указать флажок компилятора или псевдокомментарий, чтобы изменить глобальное значение по умолчанию.
 
Шейдер фрагмента Построитель текстуры

 

Примечание HLSL содержит текстуры и образцы как два отдельных объекта. В GLSL, как в Direct3D 9, привязка текстуры является частью состояния дискретизатора.

 

В GLSL вы представляете значительную часть состояния OpenGL в виде предопределенных глобальных переменных. Например, в GLSL используется переменная gl_Position для указания положения вершины и переменная gl_FragColor для указания цвета фрагмента. В HLSL вы явно передаете состояние Direct3D из кода приложения в шейдер. Например, при использовании Direct3D и HLSL данные, введенные в вершинный шейдер, должны соответствовать формату данных в буфере вершины, а структура буфера констант в коде приложения должна соответствовать структуре буфера констант (cbuffer) в коде шейдера.

Перенос переменных GLSL в HLSL

В GLSL вы применяете модификаторы (квалификаторы) к объявлению глобальной переменной шейдера, чтобы обеспечить определенные реакции этой переменной на события в вашем шейдере. В HLSL вам не нужны эти модификаторы, потому что вы определяете поток шейдера с помощью аргументов, которые передаете шейдеру и возвращаете от него.

Поведение переменной GLSL Эквивалент HLSL

Однородный элемент

Вы передаете неизменную переменную из кода приложения в вершинный шейдер и (или) шейдер фрагмента. Вы должны передать значения всех неизменных переменных перед отрисовкой какого-либо треугольника с помощью этих шейдеров, чтобы их значения остались теми же во время отрисовки треугольной сетки. Эти значения не меняются. Некоторые неизменные значения устанавливаются для всего кадра, другие — для одной конкретной пары вершина-пиксель.

Неизменные переменные индивидуальны для полигона.

Используйте буфер констант.

См. разделы Краткое руководство: создание буфера констант и Постоянные шейдера.

Различной

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

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

атрибут

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

Определите буфер вершины в коде приложения Direct3D и обеспечьте его соответствие входным данным вершины, определенным в вершинном шейдере. При желании определите буфер индексов. См. разделы Краткое руководство: создание буфера вершины и Краткое руководство: создание буфера индексов.

Создайте макет входных данных в коде приложения Direct3D и обеспечьте соответствие семантических значений семантическим значениям входных данных вершины. См. раздел Создание входного макета.

const

Постоянные, которые компилируются в шейдер и никогда не меняются.

Используйте static const static означает, что значение не предоставляется буферам констант, const означает, что шейдер не может изменить значение. Таким образом, значение известно во время компиляции на основании инициализатора.

 

В GLSL переменные без модификаторов являются лишь простыми глобальными переменными, частными для каждого шейдера.

Когда вы передаете данные текстурам (Texture2D в HLSL) и их соответствующим дискретизаторам (SamplerState в HLSL), вы обычно объявляете их как глобальные переменные в построителе текстуры.

Перенос типов GLSL в HLSL

Используйте эту таблицу для переноса типов GLSL в HLSL.

Тип GLSL Тип HLSL
скалярные типы: float, int, bool

скалярные типы: float, int, bool

также uint, double

Подробнее: Скалярные типы.

векторные типы

  • вектор из чисел с плавающей точкой: vec2, vec3, vec4
  • логический вектор: bvec2, bvec3, bvec4
  • вектор из знаковых целых чисел: ivec2, ivec3, ivec4

векторные типы

  • float2, float3, float4 и float1
  • bool2, bool3, bool4 и bool1
  • int2, int3, int4 и int1
  • Эти типы также располагают векторными расширениями, схожими с float, bool и int:

    • uint
    • min10float, min16float
    • min12int, min16int
    • min16uint

Подробнее см. в разделах Тип вектора и Ключевые слова.

тип вектора также можно определить, как float4 (typedef vector <float, 4> vector;). Дополнительные сведения см. в разделе Определяемый пользователем тип.

тип матрицы

  • mat2: плавающая матрица 2x2
  • mat3: плавающая матрица 3x3
  • mat4: плавающая матрица 4x4

тип матрицы

  • float2x2
  • float3x3
  • float4x4
  • также float1x1, float1x2, float1x3, float1x4, float2x1, float2x3, float2x4, float3x1, float3x2, float3x4, float4x1, float4x2, float4x3
  • Эти типы также располагают матричными расширениями, схожими с float:

    • int, uint, bool
    • min10float, min16float
    • min12int, min16int
    • min16uint

Вы также можете воспользоваться типом матрицы, чтобы определить матрицу.

Например: matrix <float, 2, 2> fMatrix = {0.0f, 0.1, 2.1f, 2.2f};

тип матрицы также можно определить как float4x4 (typedef matrix <float, 4, 4> matrix;). Дополнительные сведения см. в разделе Определяемый пользователем тип.

Квалификатор точности для числа с плавающей запятой, целого числа, дискретизатора

  • highp

    Этот квалификатор обеспечивает минимальные требования к точности, которые больше предоставляемых типом min16float и меньше полного 32-разрядного числа с плавающей запятой. Эквивалент в HLSL:

    highp float -> число с плавающей точкой

    highp int -> целое число

  • mediump

    Этот квалификатор в применении к числу с плавающей запятой и целому числу эквивалентен типам min16float и min12int в HLSL. Минимум 10 бит мантиссы, не как min10float.

  • lowp

    Этот квалификатор в применении к числу с плавающей точкой предоставляет диапазон плавающей запятой от –2 до 2. Эквивалентен типу min10float в HLSL.

типы точности

  • min16float: минимум 16-разрядное значение плавающей запятой
  • min10float

    Минимальное значение с фиксированной запятой и знаком на 2,8 бита (2 бита целого числа и 8 бит дробного компонента). 8-разрядный дробный компонент может включать 1, чтобы дать полный суммарный диапазон от –2 до 2.

  • min16int: минимум 16-разрядное знаковое целое число
  • min12int: минимум 12-разрядное знаковое целое число

    Этот тип для 10Level9 (уровни функций 9_x), где целые числа представлены числами с плавающей точкой. Это точность, которую вы можете получить, когда эмулируете целое число с помощью 16-разрядного числа с плавающей точкой.

  • min16uint: минимум 16-разрядное целое число без знака

Подробнее см. в разделах Скалярные типы и Использование минимальной точности HLSL.

sampler2D Texture2D
samplerCube TextureCube

 

Перенос предварительно определенных глобальных переменных GLSL в HLSL

Используйте эту таблицу для переноса предварительно определенных глобальных переменных GLSL в HLSL.

Предварительно определенные глобальные переменные GLSL Семантика HLSL

gl_Position

Эта переменная относится к типу vec4.

Положение вершины

например, - gl_Position = position;

SV_Position

POSITION в Direct3D 9

Эта семантика относится к типу float4.

Выходные данные вершинного шейдера

Положение вершины

например, - float4 vPosition : SV_Position;

gl_PointSize

Эта переменная относится к типу float.

Размер точки

PSIZE

Значение отсутствует, если вы не используете Direct3D 9

Эта семантика относится к типу float.

Выходные данные вершинного шейдера

Размер точки

gl_FragColor

Эта переменная относится к типу vec4.

Цвет фрагмента

например, - gl_FragColor = vec4(colorVarying, 1.0);

SV_Target

COLOR в Direct3D 9

Эта семантика относится к типу float4.

Выходные данные построителя текстуры

Цвет пикселя

например, - float4 Color[4] : SV_Target;

gl_FragData[n]

Эта переменная относится к типу vec4.

Цвет фрагмента для прикрепления цвета n

SV_Target[n]

Эта семантика относится к типу float4.

Выходное значение построителя текстуры, которое хранится в однобуферной прорисовке n, где 0 <= n <= 7.

gl_FragCoord

Эта переменная относится к типу vec4.

Положение фрагмента в буфере кадров

SV_Position

Отсутствует в Direct3D 9

Эта семантика относится к типу float4.

Входные данные построителя текстуры

Координаты пространства экрана

например, - float4 screenSpace : SV_Position

gl_FrontFacing

Эта переменная относится к типу bool.

Определяет, принадлежит ли фрагмент лицевому примитиву.

SV_IsFrontFace

VFACE в Direct3D 9

SV_IsFrontFace относится к типу bool.

VFACE относится к типу float.

Входные данные построителя текстуры

Лицевая поверхность примитива

gl_PointCoord

Эта переменная относится к типу vec2.

Положение фрагмента в пределах точки (только растеризация точки)

SV_Position

VPOS в Direct3D 9

SV_Position относится к типу float4.

VPOS относится к типу float2.

Входные данные построителя текстуры

Положение пикселя или образца на пространстве экрана

например, - float4 pos : SV_Position

gl_FragDepth

Эта переменная относится к типу float.

Данные буфера глубины

SV_Depth

DEPTH в Direct3D 9

SV_Depth относится к типу float.

Выходные данные построителя текстуры

Данные буфера глубины

 

Вы используете семантику, чтобы указать положение, цвет и прочие сведения для входных данных вершинного шейдера и построителя текстуры. Значения семантики в макете входных данных должны соответствовать входным данным вершинного шейдера. Например, см. раздел Примеры переноса переменных GLSL в HLSL. Подробнее о семантике HLSL: Семантика.

Пример переноса переменных GLSL в HLSL

Здесь мы приведем примеры использования переменных GLSL в коде OpenGL/GLSL и эквивалентный пример в коде Direct3D/HLSL.

Неизменная переменная, атрибут и меняющаяся переменная в GLSL

Код приложения OpenGL

// Uniform values can be set in app code and then processed in the shader code.
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;

// Incoming position of vertex
attribute vec4 position;
 
// Incoming color for the vertex
attribute vec3 color;
 
// The varying variable tells the shader pipeline to pass it  
// on to the fragment shader.
varying vec3 colorVarying;

Код вершинного шейдера GLSL

//The shader entry point is the main method.
void main()
{
colorVarying = color; //Use the varying variable to pass the color to the fragment shader
gl_Position = position; //Copy the position to the gl_Position pre-defined global variable
}

Код шейдера фрагмента GLSL

void main()
{
//Pad the colorVarying vec3 with a 1.0 for alpha to create a vec4 color
//and assign that color to the gl_FragColor pre-defined global variable
//This color then becomes the fragment's color.
gl_FragColor = vec4(colorVarying, 1.0);
}

Буферы констант и передача данных в HLSL

Вот пример передачи данных вершинному шейдеру HLSL, которые затем направляются построителю текстуры. В коде приложения определите вершину и буфер констант. Затем в коде вершинного шейдера определите буфер констант как cbuffer и сохраните индивидуальные данные вершины и входные данные построителя текстуры. Здесь мы используем структуры, называемые VertexShaderInput и PixelShaderInput.

Код приложения Direct3D

struct ConstantBuffer
{
    XMFLOAT4X4 model;
    XMFLOAT4X4 view;
    XMFLOAT4X4 projection;
};
struct SimpleCubeVertex
{
    XMFLOAT3 pos;   // position
    XMFLOAT3 color; // color
};

 // Create an input layout that matches the layout defined in the vertex shader code.
 const D3D11_INPUT_ELEMENT_DESC basicVertexLayoutDesc[] =
 {
     { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0,  0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
     { "COLOR",    0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },
 };

// Create vertex and index buffers that define a geometry.

Код вершинного шейдера HLSL

cbuffer ModelViewProjectionCB : register( b0 )
{
    matrix model; 
    matrix view;
    matrix projection;
};
// The POSITION and COLOR semantics must match the semantics in the input layout Direct3D app code.
struct VertexShaderInput
{
    float3 pos : POSITION; // Incoming position of vertex 
    float3 color : COLOR; // Incoming color for the vertex
};

struct PixelShaderInput
{
    float4 pos : SV_Position; // Copy the vertex position.
    float4 color : COLOR; // Pass the color to the pixel shader.
};

PixelShaderInput main(VertexShaderInput input)
{
    PixelShaderInput vertexShaderOutput;

    // shader source code

    return vertexShaderOutput;
}

Код построителя текстуры HLSL

// Collect input from the vertex shader. 
// The COLOR semantic must match the semantic in the vertex shader code.
struct PixelShaderInput
{
    float4 pos : SV_Position;
    float4 color : COLOR; // Color for the pixel
};

// Set the pixel color value for the renter target. 
float4 main(PixelShaderInput input) : SV_Target
{
    return input.color;
}

Примеры переноса кода отрисовки OpenGL в Direct3D

Здесь мы продемонстрируем пример отрисовки в коде OpenGL ES 2.0 и эквивалентный пример в коде Direct3D 11.

Код отрисовки OpenGL

// Bind shaders to the pipeline. 
// Both vertex shader and fragment shader are in a program.
glUseProgram(m_shader->getProgram());
 
// Input asssembly 
// Get the position and color attributes of the vertex.

m_positionLocation = glGetAttribLocation(m_shader->getProgram(), "position");
glEnableVertexAttribArray(m_positionLocation);

m_colorLocation = glGetAttribColor(m_shader->getProgram(), "color");
glEnableVertexAttribArray(m_colorLocation);
 
// Bind the vertex buffer object to the input assembler.
glBindBuffer(GL_ARRAY_BUFFER, m_geometryBuffer);
glVertexAttribPointer(m_positionLocation, 4, GL_FLOAT, GL_FALSE, 0, NULL);
glBindBuffer(GL_ARRAY_BUFFER, m_colorBuffer);
glVertexAttribPointer(m_colorLocation, 3, GL_FLOAT, GL_FALSE, 0, NULL);
 
// Draw a triangle with 3 vertices.
glDrawArray(GL_TRIANGLES, 0, 3);

Код отрисовки Direct3D

// Bind the vertex shader and pixel shader to the pipeline.
m_d3dDeviceContext->VSSetShader(vertexShader.Get(),nullptr,0);
m_d3dDeviceContext->PSSetShader(pixelShader.Get(),nullptr,0);
 
// Declare the inputs that the shaders expect.
m_d3dDeviceContext->IASetInputLayout(inputLayout.Get());
m_d3dDeviceContext->IASetVertexBuffers(0, 1, vertexBuffer.GetAddressOf(), &stride, &offset);

// Set the primitive's topology.
m_d3dDeviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);

// Draw a triangle with 3 vertices. triangleVertices is an array of 3 vertices.
m_d3dDeviceContext->Draw(ARRAYSIZE(triangleVertices),0);