Ответ на этот вопрос удивительно сложен, и становится все труднее, так как аппаратное обеспечение графического процессора становится все более и более мощным. Система D3DX FX является примером всей работы, которую необходимо выполнить, поэтому ее использование является хорошим шагом к тому, чтобы просто заставить работать в краткосрочной перспективе.
Шейдеры - это код, но они живут на другом компьютере с процессором, поэтому нужно все их данные маршализовать. Фиксированные части: основные состояния рендеринга, такие как состояния глубины, состояния трафарета, режимы наложения, команды рисования; очень легко реализовать. Сложной задачей является создание моста для программируемых частей: шейдеров, буферов, сэмплеров и текстур.
Индексные буферы просто работают, так как у вас может быть только один или ни один в случае рендеринга неиндексированной геометрии.
С вершинными буферами более или менее легко работать, поскольку аппаратное обеспечение может быть запрограммировано для процедурного считывания вершинных буферов. Ваши вершинные буферы должны предоставлять как минимум столько информации, сколько требуется для вершинного шейдера. Модификации для ввода вершин шейдера или формата вершин, требующие редактирования обеих сторон одновременно, и поэтому с ними достаточно легко работать.
Сэмплеры и текстуры являются следующими «легкими» из твердых частей для зацепления: у них есть имя переменной и довольно жесткий тип. Например, при компиляции шейдера 'foo' текстуре 'myNormalMap' назначается слот текстуры 3. Вам нужно посмотреть (через API отражения), какой слот был назначен текстуре, и установить текстуру, которую ваш движок считает 'myNormalMap', равной быть в слот 3 во время выполнения, и, конечно, также использовать API, чтобы определить, нужна ли текстура вообще. Именно здесь начинают иметь значение соглашения о присвоении имен для шейдерных переменных, поэтому можно сделать несколько шейдеров совместимыми с одним и тем же кодом C ++.
Постоянные буферы (или необработанные константы шейдера в D3D9) намного сложнее, особенно с программируемой средой шейдеров, которую вы можете найти в таких движках, как Unreal. Константы, которые использует любой данный шейдер, являются подмножеством полного списка, но сторона C ++ обычно должна быть написана так, как будто все они необходимы. Снова API-интерфейсы отражения необходимы для определения не только того, на какие переменные действительно ссылаются в шейдере, но и где они расположены. Это стало немного более управляемым в D3D10 и новее, так как cbuffers являются структурами и менее гибкими, чем система D3D9, которая была сильно ограничена количеством регистров, но это также добавляет необходимость использования API отражения для определения порядка cbuffer привязки (и на какие cbuffers также ссылаются).
В конце концов, есть один дизайн, который заставит все это работать:
Создайте класс, который управляет определенным архетипом шейдера. Для каждой переменной, которую этот класс предоставляет шейдеру (будь то текстура, постоянный буфер и т. Д.), Найдите информацию об отражении, если она используется, выясните ее местоположение и установите ее. Быть быстрым, гибким и расширяемым - сложная задача.