Проста сонячна система, центром якої є ящик – РОЗРОБКА ІГОР ДЛЯ ОС ANDROID

Створимо невеликий приклад, дуже просту сонячну систему, центром якої буде скриньку Припустимо, є один ящик, розташований в точці (0, 0, -6) системи координат створюваного світу Навколо цього ящика-сонця на відстані, рівному 3 одиниці, ми хочемо помістити ящик-планету, що обертається навколо сонця Планета має бути менше сонця, виберемо для неї розмір 0,2 одиниці Навколо ящика-планети помістимо ящик-супутник Відстань між планетою і супутником дорівнюватиме 1 одиниці, а ящик-супутник буде зменшено до 0,1 одиниці Всі обєкти обертаються навколо їх відносних предків у площині xz, а також навколо власних осей у На рис 1014 показаний приблизний вигляд цієї моделі

Рис 1014 Наша сонячна система

Клас HierarchicalObject

Визначимо простий клас, який буде містити загальний обєкт сонячної системи з наступними властивостями: позиція щодо центру його предка кут повороту навколо предка кут повороту навколо своєї осі у масштаб список нащадків посилання на екземпляр класу Verti ces3, необхідний для отрисовки

Клас Hi erarchi cal Object повинен оновлювати свої кути повороту і кути повороту нащадків, а також малювати себе і всіх своїх нащадків Цей процес рекурсівен, оскільки кожен нащадок отрісовиваєт власних нащадків Ми будемо використовувати методи gl PushMatriх і gl PopMatri х для збереження перетворень, застосованих до предків, щоб їх нащадки могли переміщатися разом з ними Код цього класу показаний в лістингу 107

Лістинг 107 Клас HierarchicalObjectjava, подання обєкта усередині системи ящика

Перші три члени містять позицію обєкта щодо його предка (або відносно початку координат світу, якщо предка немає) Наступний член включає в себе масштаб обєкта Член rotati onY зберігає кут повороту обєкта навколо себе, а член rotati onParent – кут повороту навколо центру предка

Член hasParent надає інформацію про те, чи є у обєкта предок Якщо предка немає, до обєкту не застосовується поворот навколо предка Цей член створений для сонця нашої системи Нарешті, в класі є список нащадків, а також посилання на екземпляр класу Verti ces3, що містить мережу куба, яка буде використана для отрисовки кожного обєкта

Конструктор просто отримує екземпляр класу Vertices3, а також булеву змінну, визначальну, чи має обєкт предка

У методі update спочатку оновлюються члени rotationY і rotationParent Кожен обєкт буде повертатися на 45 ° в секунду навколо себе і на 20 ° в секунду навколо свого предка Цей метод буде також викликатися рекурсивно для кожного нащадка обєкта

Метод render є найцікавішим Перше, що в ньому відбувається, – поточна НД модельно-видової матриці, яка стане активною ззовні обєкта, поміщається глибше в стек Оскільки метод рекурсівен, таким чином збережуться всі перетворення предків

Далі до обєкта застосовуються всі перетворення, які повернуть його навколо предка і помістять його в світі відносно центру предка Памятайте, що перетворення застосовуються в зворотному порядку, тому на Насправді спочатку обєкт переміститься слідом за предком, а потім повернеться навколо нього Перетворення повороту застосовується тільки в тому випадку, якщо в обєкта є предок Ящик-сонце не має предка в створюваній системі, тому він не буде повертатися Ці перетворення відносні предка обєкта, вони також будуть застосовані і до нащадків обєкта Переміщення планети навколо сонця також пересуне закріплений за нею супутник Наступна дія – ВС знову переміщується глибше в стек До цього моменту вона містила перетворення предка, а також перетворення обєкта щодо предка Необхідно зберегти цю матрицю до тих пір, поки вона буде прикріплюватися до нащадків обєкта Обертання обєкта навколо себе і його масштабування до нащадків не застосовуються, тому ці перетворення застосовуються до копії НД (яка створюється при переміщенні НД вглиб стека)

Далі застосовуються перетворення повороту навколо себе і масштабування, а потім обєкт отрісовивается за допомогою мережі ящика, на яку в обєкті міститься посилання Подумаємо про те, що трапиться з вершинами простору моделей через вплив матриці, що є ВС Згадайте порядок застосування перетворень: від останнього до першого

Спочатку розмір ящика буде масштабований Далі він повернеться навколо своєї осі Ці два перетворення застосовуються до вершин у просторі моделей Потім вершини будуть паралельно перенесені щодо позиції предка Якщо обєкт не має предка, його вершини будуть паралельно перенесені в просторі світу Якщо обєкт має предка, вершини будуть перенесені в його просторі (він буде центром своєї системи) Обєкт також повернеться навколо предка, якщо він його має Якщо ви пройдете назад по ланцюгу рекурсії, то побачите, що також застосовуємо перетворення до предка обєкта і т д За допомогою цього механізму супутник спочатку переміститься в координатної системі предка, а потім в координатної системі сонця, еквівалентної простору миру

Як тільки поточний обєкт отрісовивается, нд виштовхується з стека, і нова НД містить тільки перетворення і поворот обєкта щодо свого предка Нам не хочеться, щоб до нащадка застосовувалися місцеві перетворення обєкта (наприклад, поворот по осі у і масштабування) Все, що залишається зробити, – рекурсивно перейти до нащадка

ПРИМІТКА

Позицію обєкта, репрезентованої класом HierarchicalObject, слід зберігати у вигляді вектора для більш простої роботи з ним Однак нам слід ще написати клас Vector3

Збираємо все воєдино

Використовуємо тільки що створений нами клас HierarchicalObject в підходящої програмі Для цього я просто скопіював весь код прикладу CubeTest, в якому також є метод createCube Його ми використовуємо повторно Я перейменував клас HierarchyTest, а також CubeScreen в HierarchyScreen Потрібно створити ієрархію обєктів і викликати методи HierarchicalObject Update і HierarchicalObject render в відповідних місцях програми У лістингу 108 наведені найважливіші фрагменти прикладу Hi erarchyTest

Лістинг 108 Фрагменти класу HierarchyTestJava: реалізація простий ієрархічної системи

В клас додався лише один новий член, який називається sun Він являє собою корінь створюваної ієрархії Оскільки всі інші обєкти зберігаються всередині обєкта sun у вигляді його нащадків, нам не потрібно зберігати його явно

У конструкторі инициализируется наша ієрархічна система Спочатку завантажується текстура і створюється мережа куба, яка буде використана всіма обєктами Далі створюється сонці У нього немає предка, воно знаходиться в точці (0, 0, -5) відносно початку системи координат створюваного світу (місця, де розташовується віртуальна камера) Далі створюється ящик-планета, що обертається навколо сонця Він знаходиться в точці (0, 0, 3) щодо сонця і має масштаб, рівний 0,2 Оскільки довжина грані ящика в просторі моделей дорівнює 1, після застосування коефіцієнта масштабу ящик буде відмалювали з гранню, довжина якої дорівнює 0,2 одиниці Важливий момент – планета додається як нащадка сонця Для супутника також буде здійснено щось схоже Він знаходиться в позиції (0, 0, 1) щодо планети і має масштаб, рівний 0,1 одиниці Він додається до планети в якості нащадка Результат ініціалізації ви можете побачити на рис 1014, що має таку ж систему координат

У методі update ми просто вказуємо сонцю оновитися Воно рекурсивно викличе ті ж методи для всіх своїх нащадків, які викличуть цей метод для своїх нащадків Це оновить кут повороту всіх обєктів ієрархії

Нарешті, розглянемо метод render Почнемо з простою ініціалізації вікна перегляду і очищення буферів кольору і глибини Крім того, инициализируется матриця перспективної проекції, а також одинична матриця завантажується в якості видовий матриці OpenGL ES Подальший виклик методу glTransl atef досить цікавий: це змістить сонячну систему вниз по осі у на 2 одиниці Таким чином ми зможемо подивитися на систему зверху Цю дію можна розглядати і як переміщення камери на 2 одиниці вгору Така інтерпретація є ключовою для вибору підходящої системи камер

Як тільки всі основні компоненти ініціалізовані, вирішуються тестування глибини і текстурування, виробляється привязка текстури та мережі куба, а сонцю дається вказівка ​​отрісовать себе Оскільки всі обєкти ієрархії використовують однакову текстуру і мережа, повязувати їх необхідно всього лише один раз Виклик цього методу Отріс сонце і всіх його нащадків рекурсивно, що було підкреслено в попередньому розділі Нарешті, відключаємо тестування глибини і текстурирование просто заради розваги На рис 1015 показаний результат роботи програми

Рис 1015 Наша сонячна система в дії

Відмінно, все працює так, як ми й очікували Наше сонце обертається тільки навколо себе Планета обертається навколо сонця на відстані в 3 одиниці, також обертається навколо себе, а її розміри в пять разів менше розмірів сонця Супутник обертається навколо планети, а також рухається разом з нею завдяки стеку матриць Він також має локальні перетворення у вигляді повороту навколо себе і масштабування

Клас HierarchicalObject є досить загальним, тому ви можете використовувати його для різних цілей Додайте більше планет і супутників або навіть супутників супутників Гарненько попрацюйте зі стеком матриць Ви зможете багато чого досягти завдяки великій кількості практики Вам необхідно візуалізувати у себе в голові результат застосування всіх перетворень

ПРИМІТКА

Не надто захоплюйтеся роботою з матричним стеком Його глибина обмежена зазвичай між 16 і 32 матрицями залежно від GPU і драйвера Чотири рівня ієрархії – це максимум, який мені коли-небудь доводилося використовувати в додатку

&nbsp

Проста система камер

В останньому прикладі ми побачили підказку, як можна реалізувати систему камер в 3D

Ми використовували метод gl Trans1atef, щоб перемістити весь світ вниз на дві одиниці по осі у Оскільки розташування камери фіксоване (вона знаходиться на початку координат і звернена уздовж негативною половини осі z), такий підхід створює враження того, що це камера була пересунуто на 2 одиниці Координати всіх обєктів по осі у і раніше рівні 0

Це дуже схоже на вираз Якщо гора не йде до Магомета, Магомет іде до гори Замість переміщення камери ми пересунули весь світ Припустимо, що камеру необхідно розташувати в позиції (10 4, 2) Все, що для цього потрібно, – використовувати метод glTranslatef наступним чином:

Якщо ж потрібно повернути камеру навколо осі у на 45 °, цей метод слід викликати саме так:

Можна поєднати ці два методи, як ми чинимо для нормальних обєктів:

Секрет полягає в тому, що аргументи методу перетворення інвертуються Згадаймо попередній приклад Ми знаємо, що справжня камера приречена перебувати на початку координат і дивитися в одну сторону Застосовуючи зворотні перетворення, ми змінюємо картинку, що відображається камерою Використання віртуальної камери, поверненою на 45 °, є рівнозначним застосуванню фіксованої камери і повороту світу на -45 ° Це ж вірно і для паралельного перенесення Віртуальна камера повинна бути поміщена в точку (10 4, 2) Але оскільки реальна камера завжди знаходиться на початку координат, нам потрібно лише перенести всі обєкти світу використовуючи інвертований вектор цієї позиції, рівний (-10 -4 -2)

Якщо ми змінимо наступні три рядки методу present попереднього прикладу:

– На ці чотири:

то отримаємо результат, показаний на рис 1016

За задумом наша камера тепер знаходиться в точці (0 3 0) і дивиться вниз на сцену під кутом -45 ° (аналогічно повороту камери на -45 ° навколо осі х) На рис 1017 показана сцена, яка відображається з нової точки

Можна визначити дуже просту камеру з чотирма атрибутами: позиція в просторі світу поворот навколо осі х – аналогічно нахилу голови вгору і вниз Про поворот навколо осі у – аналогічно повороту голови вліво і вправо Про поворот навколо осі z – аналогічно нахилу голови вліво і вправо

Рис 1016 Дивимося на світ зверху з точки (0 3 0)

Рис 1017 Розміщення і орієнтація камери

Грунтуючись на цих атрибутах, ми можемо використовувати методи OpenGL ES для створення матриці камери Така камера називається камерою повороту на кути Ейлера Безліч ігор жанру FPS використовують подібну камеру для емуляції повороту голови Зазвичай значення координати по осі z не змінюється, на відміну від координат по осях х та у Порядок, в якому застосовуються перетворення, дуже важливий В іграх жанру FPS спочатку виробляється поворот по осі х, а потім по осі у:

Така спрощена модель використовується в багатьох іграх Якби ми застосовували перетворення і по осі z, то змогли б спостерігати ефект, званий шарнірний замок (gimbal lock) Цей ефект скасує один з поворотів, грунтуючись на конкретної конфігурації

ПРИМІТКА

Пояснити феномен шарнірного замка на словах або навіть за допомогою зображень дуже складно Оскільки ми здійснюємо обертання тільки по осях х і у, проблем не виникає Щоб зрозуміти, що ж таке шарнірний замок, я раджу вам пошукати в Інтернеті відповідне відео Цю проблему не можна обійти за допомогою поворотів на кути Ейлера Її рішення дуже складно математично, тому воно не входить в цю у

Другий підхід до створення дуже простий системи камер – використання методу GLU glLookAtО

Як і метод GLUgluPerspectiveO, він помножить поточну активну матрицю на матрицю перетворення У цьому випадку такий матрицею є матриця камер, яка перетворює світ:

gl – це просто екземпляр класу GL10, який використовується для отрисовки

еуех, еуеу і eyez – визначають позицію камери в світі

centerx, centery і centerz – задають точку світу, на яку дивиться камера

upX, upY і jupZ – визначають так званий верхній вектор Уявіть, що він є стрілою, що виходить з верхівки вашої голови і вказує вгору Нахиліть голову вліво або вправо – і стріла буде вказувати в тому ж напрямку, що і верхівка вашої голови

Верхній вектор зазвичай встановлюється рівним (0 1 0), навіть якщо це і не зовсім вірно Метод gl uLookAt може заново нормалізувати даний вектор в більшості випадків На рис 1018 показана наша сцена, камера якої розташовується в точці (3 3 0) і дивиться на точку (0, 0, -5), як і дійсний верхній вектор

Ми можемо замінити код методу HierarchyScreenpresentO, який змінили раніше, наступним сніппетом:

Рис 1018 Камера знаходиться в позиції (3 3 0) і дивиться в точку (0, 0, -3)

Цього разу я також закоментувавши виклик методу sun update, тому ієрархія буде виглядати так, як і на рис 1018 На рис 1019 показаний результат використання камери

Рис 1019 Камера в дії

Цей вид камери відмінно підходить в тому випадку, коли ми хочемо слідувати за персонажем або необхідний більш якісний контроль за переглядом сцени при визначенні лише позиції камери і точки, в яку вона буде дивитися

Поки припинимо розмову про камерах У наступному розділі напишемо два простих класу для камери, що годиться для гри жанру FPS, і для камери, яка може слідувати за обєктом

Підводячи підсумок

Тепер ви знаєте основи програмування 3D-графіки за допомогою OpenGL ES Ви отримали інформацію, як ініціалізувати перспективне вікно перегляду, як визначити позиції вершин в трьох вимірах, а також про те, що таке z-буфер Крім того, ви дізналися, що z-буфер може бути як другом, так і ворогом, залежно від правильності його використання Ми створили наш перший 3D-обєкт: текстурований куб Виявилося, що це досить легко Нарешті, ми ще трохи поговорили про матрицях і перетвореннях, а також створили ієрархічну і дуже просту систему камер

Джерело: Mario Zechner / Маріо Цехнер, «Програмування ігор під Android», пров Єгор Сидорович, Євген зазноби, Видавництво «Пітер»

Схожі статті:


Сподобалася стаття? Ви можете залишити відгук або підписатися на RSS , щоб автоматично отримувати інформацію про нові статтях.

Коментарів поки що немає.

Ваш отзыв

Поділ на параграфи відбувається автоматично, адреса електронної пошти ніколи не буде опублікований, допустимий HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*

*