Поделиться через


Использование шейдеров в Direct3D 10

Конвейер состоит из трех этапов шейдера, и каждый из них запрограммирован с помощью шейдера HLSL. Все шейдеры Direct3D 10 написаны на языке HLSL, предназначенном для модели 4 шейдеров.

Различия между Direct3D 9 и Direct3D 10:

  • В отличие от моделей шейдеров Direct3D 9, которые можно создать на промежуточном языке ассемблера, шейдеры модели 4.0 создаются только в HLSL. Автономная компиляция шейдеров в байт-код устройства по-прежнему поддерживается и рекомендуется для большинства сценариев.

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

После создания шейдера HLSL (в этом примере используется вершинный шейдер HLSLWithoutFX.vsh), необходимо подготовить его к определенному этапу конвейера, который будет его использовать. Для этого необходимо:

Эти шаги необходимо повторить для каждого шейдера в конвейере.

Компиляция шейдера

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

    IPD3D10Blob * pBlob;
    
        
    // Compile the vertex shader from the file
    D3D10CompileShader( strPath, strlen( strPath ), "HLSLWithoutFX.vsh", 
        NULL, NULL, "Ripple", "vs_4_0", dwShaderFlags, &pBlob, NULL );

Эта функция принимает следующие параметры:

  • Имя файла ( и длина строки имени в байтах), содержащего шейдер. В этом примере используется только вершинный шейдер (в файле HLSLWithoutFX.vsh, где расширение VSH является сокращением вершинного шейдера).

  • Имя функции шейдера. В этом примере компилируется вершинный шейдер из функции Ripple, которая принимает один вход и возвращает выходную структуру (функция из примера HLSLWithoutFX):

    VS_OUTPUT Ripple( in float2 vPosition : POSITION )
    
  • Указатель на все макросы, используемые шейдером. Используйте D3D10_SHADER_MACRO для определения макросов; Просто создайте строку имени, содержащую все имена макросов (с каждым именем, разделенным пробелом) и строку определения (с каждым текстом макроса, разделенным пробелом). Обе строки должны быть завершены со значением NULL.

  • Указатель на любые другие файлы, которые необходимо включить для компиляции шейдеров. Для этого используется интерфейс ID3D10Include, который имеет два метода, реализованных пользователем: Open и Close. Для выполнения этой работы необходимо реализовать текст методов Open и Close. В методе Open добавьте код, который будет использоваться для открытия любых включаемого файла, а в функции Close добавьте код, чтобы закрыть файлы после завершения работы с ними.

  • Имя компилировать функции шейдера. Этот шейдер компилирует функцию Ripple.

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

  • Флаги компилятора шейдера. Эти флаги сообщают компилятору, какие сведения следует поместить в скомпилированные выходные данные и как вы хотите оптимизировать выходной код: для скорости, для отладки и т. д. Список доступных флагов см. в разделе Константы эффектов (Direct3D 10 ). Пример содержит код, который можно использовать для задания значений флага компилятора для проекта. Это в основном вопрос о том, нужно ли создавать отладочную информацию.

  • Указатель на буфер, содержащий скомпилированный код шейдера. Буфер также содержит все сведения о внедренной отладке и таблице символов, запрашиваемые флагами компилятора.

  • Указатель на буфер, содержащий список ошибок и предупреждений, которые были обнаружены во время компиляции. Это те же сообщения, которые вы увидите в выходных данных отладки, если бы вы запускали отладчик во время компиляции шейдера. ЗНАЧЕНИЕ NULL является допустимым значением, если вы не хотите, чтобы ошибки возвращались в буфер.

Если шейдер успешно компилируется, указатель на код шейдера возвращается в виде интерфейса ID3D10Blob. Он называется интерфейсом BLOB-объекта, так как указатель указывает на расположение в памяти, состоящее из массива DWORD. Интерфейс предоставляется для получения указателя на скомпилированный шейдер, который понадобится на следующем шаге.

Начиная с выпуска пакета SDK за декабрь 2006 г. компилятор DirectX 10 HLSL теперь является компилятором по умолчанию как в DirectX 9, так и в DirectX 10. Дополнительные сведения см. в разделе Effect-Compiler Tool .

Получение указателя на скомпилированный шейдер

Для нескольких методов API требуется указатель на скомпилированный шейдер. Этот аргумент обычно называется pShaderBytecode , так как он указывает на скомпилированный шейдер, представленный в виде последовательности байтовых кодов. Чтобы получить указатель на скомпилированный шейдер, сначала скомпилируйте шейдер, вызвав D3D10CompileShader или аналогичную функцию. Если компиляция выполнена успешно, скомпилированный шейдер возвращается в интерфейсе ID3D10Blob . Наконец, используйте метод GetBufferPointer для возврата указателя.

Создание объекта шейдера

После компиляции шейдера вызовите CreateVertexShader, чтобы создать объект шейдера:

    ID3D10VertexShader ** ppVertexShader
    ID3D10Blob pBlob;


    // Create the vertex shader
    hr = pd3dDevice->CreateVertexShader( (DWORD*)pBlob->GetBufferPointer(),
        pBlob->GetBufferSize(), &ppVertexShader );

    // Release the pointer to the compiled shader once you are done with it
    pBlob->Release();

Чтобы создать объект шейдера, передайте указатель на скомпилированный шейдер в CreateVertexShader. Так как сначала вам пришлось успешно скомпилировать шейдер, этот вызов почти наверняка пройдет, если на компьютере не возникла проблема с памятью.

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

Установка объекта шейдера

Последний шаг — установка шейдера на этап конвейера. Так как в конвейере есть три этапа шейдера, необходимо выполнить три вызова API, по одному для каждого этапа.

    // Set a vertex shader
    pd3dDevice->VSSetShader( g_pVS10 );

Вызов VSSetShader принимает указатель на вершинный шейдер, созданный на шаге 1. При этом задается шейдер на устройстве. Этап вершинного шейдера теперь инициализируется с помощью кода вершинного шейдера. Остается только инициализация переменных шейдера.

Повторите для всех 3 этапов шейдера

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

Компиляция шейдеров

Руководство по программированию для HLSL