Давайте напишем ... MMO! Часть 13: The Cake is a Lie!

Опубликовано NowhereMan -

18 февраля 2011

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

Непрозрачные: 1,87 мс Прозрачные: 16,49 мс Всего: 18,36 мс Частота кадров: 54 fps

Мне нужна была функция под названием текстурные массивы, которых не было в DX9, поэтому я решил попробовать OpenGL. Моя первая версия, использующая ту же логику, что и версия DirectX (без текстурных массивов), добилась таких результатов:

Непрозрачные: 1.95 ms Прозрачные: 27.19 ms Всего: 29.14 ms Частота кадров: 34 fps

Это было гораздо медленнее для прозрачных данных. Это тот же самый код, который генерирует тот же самый список треугольников, занимающий столько же места, поэтому там точно такой же объем работы. Хотя я не копался в нем, я предполагаю, что есть некоторые дополнительные накладные расходы в Windows, чтобы добраться до вызовов OpenGL, и добавление более тысячи отдельных треугольников замедляет процесс.

Однако я не волновался, так как теперь собирался использовать текстурные массивы, которые бы сократили все отдельные прозрачные треугольники до одного вызова API. От этого выигрывают и непрозрачные данные, так как теперь они также являются единичным вызовом API, вместо 20+ отдельных буферов, которые я использовал. Версия с текстурным массивом достигла таких результатов:

Непрозрачные: 1.56 ms Прозрачные: 9.88 ms Всего: 11.44 ms Частота кадров: 87 fps

Почти все это время находится в моем коде, чтобы сгенерировать список прозрачных треугольников. Также, поймите, что это не типичный случай рисования для финальной игры. Код рисует огромный кусок размером 128 на 128, все в одном кадре. Реальная игра будет рендерить несколько маленьких кусочков и загружать и выгружать их по мере того, как вы перемещаетесь. Это всего лишь мой тест скорости.

Эта программа отлично работала под Windows 7 и Windows XP, что было хорошо. Но она не работала на моем ноутбуке под Windows 7 из-за различий между шейдерными компиляторами на на видеокартах NVidia и ATI.

Я писал свои шейдеры на основе "стандартных шейдеров", поставляемых с OpenGL SuperBible. В моем неведении я не знал, что это старые шейдеры версии 1.2, а не более новой версии 3.3. Я даже не объявлял версию в шейдере, так что получал значения по умолчанию под двумя разными компиляторами. Когда я добавил строку "#версия 330", поведение компиляторов изменилось. Они оба ненавидели мой код...

Шейдеры работают на моей главной настольной машине, у которой видеокарта NVidia. Изменения были тривиальными, так как я пока не делаю ничего интересного в своих шейдерах. Мне просто нужно было поменять имена некоторых ключевых слов и т.д. Опять же, все прошло отлично на моей машине с Windows XP, которая также оснащена дисплеем NVidia. На ноутбуке с дисплеем ATI шейдеры были скомпилированы чисто, но они не работали. Совсем. У меня появилось большое черное окно с чистым белым прямоугольником в верхней правой четверти экрана.

Ох.

Оказывается, по непонятным мне причинам, объявление координат текстуры как " in vec2 vTex0" ничего не делает на дисплее ATI. Оно должно быть "smooth in vec2 vTex0" или " centroid in vec2 vTex0". Под NVidia все три работают. Я думал, что "smooth" и "centroid" - это опции для изменения интерполяции координат текстуры ("smooth" дает лучшее перспективное преобразование текстуры), но я не думал, что они необходимы.

ATI также выдавал мне предупреждение о повторном декодировании встроенной переменной "gl_FragColor", в то время как NVidia выдала бы мне ошибку (и ошибку), если бы я этого не сделал. Так что у меня не было теплых пушистых чувств по поводу отладки настоящей игры, которую люди могли бы запускать на огромном количестве аппаратного обеспечения. Но поскольку все это хорошо работало на моих трех машинах с Windows, я перешел на следующую платформу.

Mac OS X

Я запустил свой редко используемый Hackintosh - десктоп Shuttle с видеокартой NVidia. Я скомпилировал пример OpenGL для Mac две недели назад, еще до того, как стал рассматривать OpenGL, так что я не ожидал никаких проблем. Я прочитал достаточно документации и учебника по XCode, среде разработки для Mac, чтобы начать.

Платформеннонезависимая часть моего кода худо-бедно скомпилировалась. У меня было несколько системных вызовов Windows, от которых нужно было избавиться, и несколько небольших вариаций в стандартной библиотеке Си, с которыми нужно было разобраться. К сожалению, код OpenGL выкидывал всевозможные ошибки. Поначалу я не воспринимал это всерьез, так как думал, что нужно просто найти нужный подключаемый файл, и он скомпилируется.

Под Windows вы запускаете старинную версию 1.1 OpenGL, которую поддерживает Windows. Затем, используя библиотеку под названием "glew", вы получаете настоящий интерфейс к более свежей версии OpenGL. Версия 3.3 была лучшей, которую поддерживает мое железо, так что это то, подо что я писал. Я ожидал такой же сделки под MacOS. В OpenGL SuperBible были главы о том, как заставить их код работать под MacOS, и все их примеры были про версию 3.3.

Но я просто не смог найти нужный include файл, независимо от того, что я пытался из книги. Поэтому я зашел на их сайт, который включал в себя эту маленькую заметку:

Итак, вот в чем дело. Когда мы только начинали эту книгу, мы думали, что немыслимо, чтобы Apple не имел реализации OpenGL 3.x для OS X к моменту отправки книги. Последней версией OpenGL является 4.2, и на сегодняшний день OS X 10.6.5 (Snow Leopard), самая продвинутая и сложная операционная система Apple, все еще поддерживает только OpenGL 2.1.
Да, Apple, вам должно быть стыдно. Я люблю свой Mac и никогда не вернусь к Windows... но, серьезно?

The cake is a lie.

На самом деле я зашел на сайт, чтобы скачать их исходный код для Windows, но не потрудился прочитать остальную часть страницы, где говорится о Mac OS X. Если бы это было так, я бы даже не пытался использовать OpenGL.

Я не знаю, что теперь делать. Я могу вернуть шейдеры к версии 1.2, которую поддерживает Mac. И я могу изменить код на C++, чтобы использовать версию 2.1 OpenGL везде, даже на Windows и Linux. В конце концов, весь смысл использования OpenGL заключался в том, чтобы иметь общий интерфейс на всех платформах. Тем не менее, мне не нравится идея изучать новое API, которое уже устарело, и использовать его только для совместимости.

Конечно, так как я не закончу этот проект еще несколько месяцев, я также могу просто подождать до следующего релиза MacOS (Lion), который выйдет позже в этом году, и надеяться, что он будет иметь поддержку 3.3. Даже использование OpenGL 3.3 в Windows имеет только преимущества - я могу написать шейдеры 3.3, которые работают как на Windows 7, так и на XP. Я не могу сделать ничего подобного с DirectX.

Полагаю, что нужно попробовать Linux и посмотреть, что я получу. Мой Linux box работает под управлением какой-то версии Ubuntu и не имеет отдельной видеокарты. Основываясь на моем опыте, каковы шансы, что в Linux будет хорошая поддержка OpenGL на интегрированном чипсете ATI?

Конечно, я мог бы сделать двойную загрузку Linux на одной из моих новых машин, но здесь нет хорошего выбора. Hackintosh невероятно хрупкий, и я не собираюсь опять с этим связываться после кошмара, когда я заставлял его работать. Машина с Windows XP - это аппаратное обеспечение 6 летней давности. Машина с Windows 7 в порядке, но мой опыт работы с обновлениями похож на что-то из этого xkcd cartoon. Установка Linux на ноутбук даст то же, что и на моем сервере - интегрированную графику ATI.

Полагаю, что я мог бы купить видеокарту NVidia и вставить ее в Linux-сервер. Или у меня есть видеокарта NVidia 7900 GS, которая может работать на этой машине. Кто-нибудь из вас знает, будет ли OpenGL 3.3 поддерживаться на этой карте под Linux?

Я еще не отказался от OpenGL, но мне противна вся эта ситуация. Я попробую еще разок в MacOS или Linux после того, как немного отойду.

Снова DirectX

Комментатор "kpt" упомянул, что я могу использовать "текстурный атлас" вместо текстурного массива для улучшения производительности в DX 9. Это не функция API, просто другое использование стандартных текстур. Вы объединяете все ваши маленькие текстуры в одну большую, а затем вызываете только ее части, когда рисуете треугольники. Это сработает, но тут есть две проблемы:

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

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

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

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

Так как я попал в большие неприятности, пытаясь изолировать DirectX / OpenGL интерфейсы от остального кода, и хотел выпустить какое-то демо на этой неделе, я пошел дальше и сделал новую DX версию, которая использует подход текстурного атласа. Вот ее результаты:

Непрозрачные: 1.62 ms Прозрачные: 11.73 ms Всего: 13.35 ms Частота кадров: 74 fps

Прозрачные данные, отрисованные с помощью текстурного атласа, немного медленнее, чем OpenGL, потому что мне приходится разворачивать все кубы 2x2x2 и больше в Octree на отдельные кубы для текстурирования. Код для проверки этого находится во внутреннем цикле создания прозрачного индексного списка.

Демо

Новое демо The Part 13 Demo. Я проводил так много экспериментов, что сломал многие функции. Для упрощения я удалил весь код, который не работал, из приведённых ниже исходных текстов. Это означает, что нет текстовых оверлеев для помощи и нет проверки на наличие помех.

UI вернулся туда, где он был во второй части. Для перемещения используйте клавиши WASD или стрелки курсора. Нажмите ESC для выхода из программы.

По умолчанию программа использует OpenGL. Для выбора DirectX отредактируйте файл "options.xml" в текстовом редакторе и установите атрибут "platform" в "DirectX9", или вернитесь к "OpenGL3.3".

Если программа упадет под OpenGL, то в каталоге демо вы найдете файл под названием "errors.txt".Пожалуйста, отправьте его мне адресу mgoodfel@sea-of-memes.com.

Исходники

Скачивайте архив The Part 13 Source с C++ кодом, дорожной картой к исходникам и каталогом сборки. Сюда входит исполняемая демо-версия и необходимые файлы.