понедельник, 23 января 2012 г.

DirectGL progress

Завершил работу над функциями по загрузке 2D-текстур. Решено реализовать только загрузку BMP, TGA и DDS форматов (без поддержки расширений DX10, т. к. они всё равно не применимы в DX9-рендере). Я написал простой unit test который грузит DDS текстуры разных форматов (как сжатые, так и различных форматов вида RGB8, R5G6B5 и т. д.), а фактически текстуры разделены на два лагеря - несжатые RGBA8 и сжатые DXT, всё остальное практически никогда не используется для хранения в видеопамяти. Для полноты необходимо реализовать ещё загрузку cubemap текстуры из DDS, но это если руки дойдут.

Решено также постепенно подключать к проекту различные unit test-ы, как это практикуется в Wine, чтобы тестировать враппер на соответствие реальному поведению рантайма Direct3D. Из того же Wine эти тесты и думаю заимствовать (как-никак open source).

Также заставил работать через враппер два сэмпла из DirectX 9 SDK - EmptyProject и SimpleSample. Как и другие примеры они интенсивно используют DXUT, так что это хороший тест "на прочность". Но тут обнаружился интересный баг - шрифт рисуется в бэк-буфер перевернутым по оси ординат:


Тут нужно отметить, что при портировании Direct3D кода на OpenGL есть один неприятный момент:  начало системы текстурных координат Direct3D находится в левом верхнем углу, тогда как в OpenGL - в левом нижнем. Для обычных текстур это не имеет значения, т. к. похоже драйвер правильно укладывает их в память (или железо вычисляет адрес в памяти) в зависимости от используемого API. Но с render target текстурами при их семплировании в шейдере приходится инвертировать текстурные координаты по оси Y. Это решение имеет по крайней мере два недостатка:

1) Необходимо пересмотреть код всех шейдеров и в тех местах, где семплируется render target, поправить текстурные координаты.

2) Возможны случаи, когда в шейдер на один и тот же текстурный слот попеременно передаётся обычная текстура и render target. Тут приходится заводить дополнительный булевый флажок либо создавать отдельный шейдер для каждого случая. При использовании флажка, если он по какой-то причине не отражает реальное положение дел (упустили где-то, энджин-то большой), изображение нарисуется перевёрнутым.

Оба эти решения являются неприемлемыми.

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

Если же использовать этот метод, то любые другие способы записи в render target (например, отображение шрифта силами GDI), не проходят преобразование матрицей, и попадают в render target с исходными координатами - соответственно при семплировании в шейдере изображение перевернётся. Впрочем, это минорный недостаток, в реальных играх вся графика полигональна.

Общий вид GDI текста с инвертированием текстурных координат:


Как видно, теперь перевернулись элементы интерфейса, нарисованные с помощью полигонов. Надеюсь, дилемма понятна.

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

3 комментария:

  1. Тебя бы спосло расширение ARB_fragment_coord_conventions

    ОтветитьУдалить
  2. Привет! Только сейчас наткнулся на твой проект. Прости за глупый вопрос - ты заворачиваешь OpenGL в DX или наоборот?

    Для меня сейчас весьма актуально первое - я недавно обзавёлся 3D-очками от nVidia, а их драйвер работает только с DirectX играми. А мне бы очень хотелось увидеть продвинутые порты Quake и Quake 2, да и многие другие игры, в 3D. А они все на OpenGL, и довольно продвинутом. Существующие врапперы весьма устарели и поддерживают только совсем старые версии. Из всех интересующих меня портов удалось запустить только Doomsday с его примитивной на сегодняшний день графикой.

    Если я понял правильно, в чём я не уверен, буду внимательно следить за твоей разработкой и очень ждать релиза!

    С уважением, Максим.

    ОтветитьУдалить