InputLayout, который связывает атрибуты вершин с постоянным значением?

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

const GLfloat data[] = { 1.0f, 0.0f, 0.0f, 1.0f };
GLuint location = glGetAttribLocation(program, name);
glDisableVertexAttribArray(location);
glVertexAttrib4fv(location, data);

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

В DirectX нужно создать ID3D11InputLayout, соответствующий шейдеру, например:

ID3D11InputLayout* layout = nullptr;
D3D11_INPUT_ELEMENT_DESC ied[] = {
  { "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 },
};
device->CreateInputLayout(ied, 2, vertexShader.data(), vertexShader.size(), &layout);

Но если InputLayout не покрывает все атрибуты вершин, ожидаемые шейдером, возникнет исключение во время выполнения.

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

  • создавать отдельные шейдеры, например, для постоянного цвета (исходя из постоянного буфера/униформы вместо атрибута) → но это приведет к дополнительным объектам шейдера и дополнительному коду шейдера для поддержки
  • дублирование атрибута вершины одного цвета для каждой вершины → но это приведет к потере большого количества памяти

Есть ли другое решение? Какова наилучшая практика в DirectX для обработки таких случаев?


person Constantin    schedule 16.05.2018    source источник


Ответы (2)


В Direct3D нет эквивалента — способ решить эту проблему — создать несколько объектов шейдера и использовать каждый объект шейдера вместе со связанным с ним входным макетом для рендеринга объектов в вашей сцене.

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

person Alex    schedule 16.05.2018

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

Пример:

struct VertexInputType
{
    float4 inPosition : POSITION;
#ifdef USE_COLOR
    float4 inColor : COLOR;
#endif
};

#ifndef USE_COLOR
static const float4 inColor = { 1.0, 0.0f, 0.0f, 1.0f };
#endif
person Yura.S    schedule 16.05.2018