ITCS - Разработка компьютерных игр. Часть 2 - РАЗРАБОТКА КОМПЬЮТЕРНЫХ ИГР
Сегодня: Четверг, 08.12.2016, 01:11 (МСК)| Здравствуйте, Гость| Мой профиль | Регистрация | Вход | RSS

Что такое matte painting?

Спецэффекты в Cinema4D

Blu-ray приводы для ПК

Наушники. Как выбирать?

Программы — виртуальные гитаристы
Главная » РАЗРАБОТКА КОМПЬЮТЕРНЫХ ИГР

Разработка компьютерных игр. Часть 2

26.07.2010
Как стало ясно из прошлого материала серии, основными кирпичиками или строительными блоками трехмерных миров и объектов являются вершины. Смещая предметы в пространстве, мы, прежде всего, изменяем положение вершин, и все вычисления производятся вокруг них. Поэтому сегодня настало время поговорить о том, что же такое представляет из себя Direct3D, а также вы поймете, как устроены другие низкоуровневые графические движки. А после с большим успехом и легкостью продолжим наше вхождение в мир разработки.

Игры можно по праву считать очень сложными приложениями, требующими огромных трудовых затрат и усилий при создании. К сожалению, а может, и к счастью, еще не придуман тот универсальный конструктор, который позволит клепать Starcraft’ы, Spore и Doom’ы, и превратить производство в обыкновенную штамповку, для обучения которой нужно будет готовить обычных операторов. Все дело в том, что технологии не стоят на месте, и чем они сложнее, тем лучше результаты. 
Как говорится во множестве литературы, библиотеки типа OpenGL и DirectX позволяют избавить программистов от большого пласта рутинной работы. Это правда. По существу, они являются некоей надстройкой, через которую программисты общаются с аппаратным обеспечением и, мало того, предоставляют инструментарий для создания виртуальных игровых миров.  


Несколько слов об OpenGL


OpenGL по своей концепции содержит некоторое концептуальное отличие от DirectX, причем имеет под собой гораздо более глубокую историю, ведущуюся еще от разработчиков Silicon Graphics, и, в принципе, ни для кого не секрет, что раньше большая часть трехмерной анимации делалась именно на этих компьютерах. OpenGL расшифровывается как Open Graphic Library, то есть открытая графическая библиотека, которая может пополняться за счет различных фирм и отдельных разработчиков при условии соответствия определенному стандарту и прохождения тестов. Она достаточно интересна как в рассмотрении, так и в применении. Заложенные процедуры имеют все ключевые возможности, а именно, работу с растровой и векторной графикой, двух- и трехмерным моделированием, текстуризацией, созданием сцен, управлением освещения и движения камер. Также есть весь необходимый набор эффектов, таких как, например, прозрачность, туман, смешивание цветов и т.п. Она стоит несколько ближе к пакетам 3D-моделирования, потому как может генерировать трехмерные поверхности (сферы, многогранники), позволяет использовать кривые Безье и B-сплайны (NURBS-сплайны). Основной единицей информации для программиста, использующего OpenGL, является вершина, и нет строгой привязки к примитивам, что мы можем наблюдать в Direct3D. То есть, он самостоятельно может указывать параметры соединения вершин: линиями, собирать их в различные многоугольники, их последующая триангуляция может производиться в автоматическом режиме либо с помощью специальных команд. Среди плюсов OpenGL стоит отметить надежность, практическую независимость от платформ и аппаратной части ПК (это немного спорно), стабильность отображения полученного результата на разных компьютерах (это называется переносимостью), а самый большой плюс — это быстрая инициализация и сравнительная простота разработки в ее рамках. Минус — медлительность, и на самом деле уже достаточно слабая распространенность именно в геймдеве, хотя из разработчиков игр у OpenGL до сих пор остается множество приверженцев, даже среди высшей касты. Хотя медлительность для современных игр — это очень плохая характеристика. 
Команды в OpenGL можно условно разделить на две части: одни применяются для создания объектов, другие — для управления отображением оных на экране. Набор базовых команд OpenGL включает примерно 300, причем в WinAPI вы можете получить доступ к ним из разных языков программирования, например, не только С, но и Delphi, и Fortran. Кстати, именно последний указывает на то, почему OpenGL так полюбился в рамках систем автоматического проектирования (САПР) в том числе.
OpenGL оснащен специальной библиотекой утилит (GLU), команды которой дополняют базовые функции OpenGL, и благодаря ей можно работать с теми же кривыми Безье и так далее. Есть и еще дополнительные библиотеки, например, AUX, которая позволяет обрабатывать события, обеспечивать вывод стандартных трехмерных объектов, управлять окнами, двойной буферизацией. 
То есть, по существу, OpenGL — это универсальное и мощное средство в умелых руках. Хотя у DirectX в определенном смысле есть некоторое неоспоримое преимущество. Говоря об аппаратной независимости OpenGL, мы немного слукавили, поскольку она подразумевает уровень включения (и соответственно поддержки) драйверов основного оборудования. Разработчики DirectX, а это никто иной как Microsoft, в этом случае пошли по другому пути, а именно, они подогнули производителей видеокарт под себя. 
Смотрим…     


Direct3D


Как уже было сказано, Direct3D — это низкоуровневый API (Application Programming Interface, интерфейс прикладного программирования), который стоит непосредственно между программистом и аппаратным обеспечением, то есть, графическим устройством с его возможностями. Сама идея DirectX возникла неспроста. Тот, кто играл в компьютерные игры (кстати, очень много из которых было создано на базе OpenGL) в середине 90-х прошлого столетия, могут вам рассказать, что при запуске игры нужно было обязательно зайти в Setup и выбрать драйвера аудио и видео устройств. Причем, если таковых не было в списке, то играли без звука и т.п. Технология DirectX стала неким посредником между разработчиками ПО и производителями «железа», введя ключевую аббревиатуру HAL, о которой мы подробно поговорим позже. Соответственно, это сильно упростило ситуацию. То есть, производители комплектующих стали ориентироваться на стандарты, предлагаемые DirectX, «подгоняя» под них свое оборудование, а разработчиков перестали волновать вопросы совместимости с каждым отдельным устройством.
Direct3D — это лишь часть технологии DirectX, которая отвечает за отображение трехмерной графики с выходом на аппаратные ускорители. 
Цепь следования взаимосвязей можно указать так: Приложение -> Direct3D -> HAL -> Аппаратная часть (видеокарта). Теперь наступило время узнать, что такое HAL и для чего он нужен? 

HAL

HAL — это уровень абстрагирования Direct3D от оборудования (Hardware Abstraction Layer). По существу, главный уровень взаимодействия с «железом».
Direct3D требует от видеокарты выполнения определенных команд и операций, предусмотренных в рамках его (а не карты) возможностей. Но он не может выходить напрямую к ресурсам аппаратуры, и это было бы бессмысленно. Ведь не секрет, что каждая видеокарта имеет свой набор поддерживаемых функций, собственные алгоритмы для выполнения той или иной задачи. Так вот, все возможности видеокарты встраиваются производителями в HAL, или, говоря простым языком, «прописываются» там («прописываются» от слова «прописка»).  
Немного не понятно? ОК. Например, Direct3D необходимы возможности очистки экрана, она просматривает HAL и если там «кто-то прописан» в разделе очистки экрана, то происходит исполнение. Но какое? По алгоритмам, заложенным производителями видеокарты. То есть, здесь царство Direct3D уже не действует. Причем у одних та же очистка экрана может происходить по одному алгоритму, у других иначе, быстрее или медленнее — это уже Direct3D не касается. Это сравнимо с тем, что вы приходите в ЖЭС и обращаетесь в кабинет паспортиста. Если в нем есть человек, то вы отдаете ему паспорт, и он уже работает как может (качество его работы от вас не зависит). Если же в кабинете никого нет, то уж… увольте. Причем вы не можете самостоятельно сделать за него его работу, да у вас и нет полномочий внедряться во внутреннюю структуру кабинета. 
Если есть возможности, которые предлагает Direct3D, но они не поддерживаются устройством («не прописаны» в HAL), то возникает ошибка, за исключением, пожалуй, только нескольких немногих случаев, например, обработки вершин. Она может выполняться и программно. То есть, происходит переключение. 
Каждой возможности, предусмотренной в Direct3D, соответствует член данных или бит в структуре D3DCAPS9. Вы можете найти их полный список в документации к SDK. При инициализации экземпляра структуры D3DCAPS9 производится сверка с возможностями аппаратуры на конкретном компьютере, другими словами, того видеоадаптера, который установлен. 
Давайте покодируем, это весело! Например, проверим, может ли наше железо осуществить аппаратную обработку вершин. В документации по SDK находим, что это бит D3DDEVCAPS_HWTRANSFORMANDLIGHT  в  члене  данных  D3DCAPS9::DevCaps. ОК, поехали. 
Для начала инициализируем экземпляр D3DCAPS9:

HRESULT IDirect3D9::GetDeviceCaps(
UINT Adapter, 
D3DDEVTYPE DeviceType, 
D3DCAPS9 *pCaps
); 

В данном фрагменте кода Adapter указывает на физический видеоадаптер, который мы хотим проверить; DeviceType задает тип устройства, пока мы будем подразумевать аппаратное, а не программное, т.е. D3DDEVTYPE_HAL (об этом подробнее чуть позже); pCaps возвращает инициализированную строку с необходимым описанием возможностей видеокарты. 
Далее мы приступаем непосредственно к проверке и вносим информацию о возможностях первичного адаптера в структуру D3DCAPS9. Простым языком мы извлекаем данные согласно тому, что написано выше:

D3DCAPS9 caps;  
d3d9->GetDeviceCaps(
D3DADAPTER_DEFAULT, 
deviceType,   
&caps);

В этом фрагменте D3DADAPTER_DEFAULT означает непосредственно первичный видеоадаптер; deviceType задает тип устройства и строчка &caps возвращает заполненную структуру D3DCAPS9. Далее мы назначаем булеву переменную:

bool supportHWProc;

… и делаем проверку:

if(caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT)  {      
supportHWProc = true;  
}  

Аппаратная поддержка обработки вершин есть или...

else  
{
supportHWProc = false;
}

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


REF


Если есть возможности, которые реализуются только в некоторых видеокартах, а в арсенале разработчика такого оборудование не имеется, то тогда он использует ему на замену REF (reference rasterizer — вспомогательный растеризатор). Речь идет о программной эмуляции реализации возможностей Direct3D, которые на самом деле должны производиться аппаратно. Нужно это, прежде всего, для того, чтобы работа не останавливалась из-за отсутствия оборудования, то есть писать и проверять код можно и без оного с помощью REF. Отдельно стоит отметить, что это виртуальное устройство есть только в арсенале разработчика, пользователям оно не доступно. Кстати, работает очень медленно, это вам могут доказать те, кто использовал REF, например, эмулируя шейдеры и так далее. 
В предыдущем коде мы использовали перечисление D3DDEVTYPE, в рамках которого задавался тип устройства. Так вот, константа, соответствующая аппаратному типу называется D3DDEVTYPE_HAL, программному — D3DDEVTYPE_REF.
Что касается обработки вершин, вернее, поддерживает ли устройство на аппаратном уровне обработку преобразований и расчет освещения, как мы уже говорили, Direct3D позволяет включать программную эмуляцию и для пользователей. Для этого есть два идентификатора, а именно, D3DDEVCAPS_HWTRANSFORMANDLIGHT, который мы использовали в предыдущем коде для того, чтобы узнать, есть аппаратная поддержка или нет, и D3DCREATE_SOFTWARE_VERTEXPROCESSING. Эти константы являются предопределенными. В данном случае я не буду говорить тривиальные вещи о том, что аппаратная намного выгоднее и почему.


COM


О Component Object Model (модели компонентных объектов) можно рассказывать много и долго. Например, я однажды подшутил над моим знакомым, подарив ему книгу с тремя большими буквами «COM» на обложке, сначала он обрадовался, а потом оказалось, что это художественная литература, а в названии подразумевалась рыба-сом (Или это был справочник? Не помню. Вряд ли, пород сомов не так много). А если серьезно, то речь идет не об объектно-ориентированных моделях, кои у всех на слуху, а о компонентно-ориентированных (или даже интерфейсно-ориентированных). Как говорится, давайте дружить домами! 
Что такое COM многим известно, с другой стороны начинающим было рекомендовано самостоятельно изучить эту тему… но что-то мне подсказывает... Дело в том, что о COM-написано очень много разного, и чаще всего достаточно запутанно. Многие авторы идут в исторические дебри от структурного и объектно-ориентированного программирования, а потом обрыв… и уже описывают IUnknown. Для примера я открыл одну весомую книгу по программированию, так там писавший человек сам запутался в рассуждениях. Можно сказать, завис на фразе: «судя по всему, интерфейс является направляющим механизмом для получения необходимых методов. Но реализовано это весьма хитро».
Итак, попробуем объяснить просто. Не так давно, а скорее уже давно, Microsoft предложила свою собственную технологию связывания и встраивания документов OLE. Она позволяла приложению содержать и управлять документами, которые были созданы другими приложениями, как своими собственными. В итоге мы получали некий общий комбинированный документ и могли воспринимать как единую сущность. Это немного отличается от объектно-ориентированного представления. Поэтому параллельно приведу пример с разветвленной банковской системой. По существу она не зависит от каждого отдельного устройства, принимающего, например, платежи по кредитным картам, ПО, которое в нем функционирует и т.п. То есть, это устройство подразумевает некий отдельный объект, задача которого — выдавать данные и воспринимать команды. То есть, общение с ним происходит только на интерфейсном уровне. Соответственно оно должно быть встроено в общую систему и взаимосвязано с ней. Допустим, произошла поломка устройства, оно заменяется на другое, можно от другого производителя и с другой внутренней структурой, самое главное, чтобы оно было встраиваемо и выдавало нужный результат.
Сама аббревиатура OLE не продержалась как таковая и вскоре была заменена на более емкую COM. Существует два понятия, а именно, COM-объект и COM-интерфейс. Интерфейсом можно считать то соединительное звено, которое дается управляющему приложению для доступа непосредственно к COM-объекту. COM-объект — это компонент, являющийся конкретным экземпляром COM-класса, он может содержать множество функций, доступ к которым возможен через интерфейсы. COM-класс определяет интерфейсы и методы компонента. При создании компонента для его инициализации вызывается объект класса, после чего его интерфейсы предоставляются управляющему приложению. 
:) Теперь простыми словами. Вернемся к примеру с банковской сетью. Допустим, вы устанавливаете новое устройство по приему платежей по кредитным картам. Оно должно инициализироваться как устройство определенного типа и предоставить доступ ко всем необходимым ресурсам, то есть, производимым операциям.
Но как определить, что устройство подключено, готово к взаимодействию и предоставляет определенные возможности? Для этого предусмотрен специальный механизм опроса, выраженной в интерфейсе IUnknown («unknown» в переводе «неизвестный»), включение которого является обязательным для всех COM-объектов. Он содержит три метода: запроса и идентификации интерфейса QueryInterface(), увеличения счетчика ссылок AddRef(), уменьшения счетчика ссылок и освобождения занимаемой объектом памяти, если счетчик равен нулю. По существу, AddRef и Release управляют продолжительностью существования объекта, он существует, пока используется.
Благодаря технологии COM Direct3D может использоваться независимо от языков программирования и быть совместимым с предыдущими версиями. На самом деле это удобное решение. Единственное, что стоит отметить отдельно: для эффективного использования DirectX углубленного изучения технологии COM не требуется, мало того, ссылки на СОМ-объект идут практически как на интерфейс, и по существу он воспринимается как класс С++. Правда, с одним ограничением, ведь, не стоит забывать об IUnknown, от которого COM-интерфейсы наследуют функциональность. Поэтому к ним нельзя применять ключевое слово из С++ new и удалять оператором delete (вместо оного вызывается метод Release). Также, как вы смогли понять, управление памятью COM-объекты осуществляют самостоятельно. 
Для обозначения COM-интерфейсов в коде в начале используется заглавная «I», например, IDirect3DSurface9 либо же IDirect3D9, как в нашем листинге. 


Перепечатка материалов или их фрагментов возможна только с согласия автора.






Всего комментариев: 0
Добавлять комментарии могут только зарегистрированные пользователи.
[ Регистрация | Вход ]
Ассоциация боевых роботов
Рекомендуем...
Новости

Разделы

Опросы

Какой язык программирования вы считаете наиболее актуальным сегодня?
Всего ответов: 308

Друзья

3D-кино






Найти на сайте:








Об авторе       Контакты      Вопрос-ответ        Хостинг от uCoz