2D-ПЕРЕТВОРЕННЯ: МАТРИЦЯ МОДЕЛЬ – ПРЕДСТАВЛЕННЯ – РОЗРОБКА ІГОР ДЛЯ ОС ANDROID

&nbsp

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

Простір світу і моделі

Щоб зрозуміти, як це працює, нам потрібно сприймати ортографической відображається конус трохи по-іншому Він розташовується в особливій системі координат, яка називається простором minа Це простір, куди в підсумку будуть потрапляти всі наші вершини

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

Це те, що ми зазвичай називаємо областю моделі, системою координат, всередині якої ми описуємо місце розташування вершин моделі На рис 719 показана ця концепція в 2D Це також вірно для 3D (просто додайте вісь z)

Рис 719 Опис нашої моделі в області моделі, повторне використання та візуалізація в різних місцях області світу

На рис 719 зображена одна модель, описана за допомогою екземпляра класу Vertices, наприклад, таким чином:

У даному контексті ми поки опустимо координати кольору і текстури Тепер, коли ми визуализируем цю модель без будь-яких подальших змін, вона буде розміщена на початку координат світу на кінцевому зображенні Якщо ми хочемо візуалізувати її в іншому місці, наприклад, щоб її центр був у точці (200 300) області світу, ми можемо повторно описати положення вершин наступним чином:

При наступному виклику verti ces draw модель буде візуалізована з центром в точці (200 300) Але так працювати трохи незручно, чи не так

&nbsp

Знову матриці

Памятайте, ми коротенько вже говорили про матрицях Ми обговорювали, як матриці можуть задавати такі трансформації, як переміщення, поворот і зміна розмірів Проекційна матриця, яку ми використовуємо для перенесення наших вершин на площину проекції, задає особливий тип перетворення: проекцію

Матриці мають визначальне значення при вирішенні нашої попередньої проблеми, допомагаючи впоратися з нею більш акуратно Замість того щоб вручну переміщати вершини, заново описуючи їх місце розташування, ми просто встановлюємо матрицю, яка кодує переміщення Оскільки матриця проекції OpenGL ES вже зайнята матрицею ортогональної проекції, яку ми визначили через glOrthof, ми будемо використовувати іншу матрицю OpenGL ES: матрицю Модель – уявлення Ось як можна візуалізувати нашу модель, переміщаючи її разом з початком координат в спостережуваному просторі:

Однак спочатку потрібно повідомити OpenGL ES, який матрицею ми хочемо управляти У нашому випадку це матриця Модель – уявлення, яка визначена константою GL10 GLMODELVIEW Потім ми перевіряємо, встановлена Чи одинична матриця в якості модельно-видовий Фактично ми просто Перезаписуємо все, що вже було, – просто очищаємо матрицю Зверніть увагу на виклик, описаний далі, – тут відбувається саме цікаве

Метод glTranslatef приймає три аргументи: переміщення по осях х у иг Оскільки ми хочемо, щоб початок координат моделі було переміщено в точку (200 300) спостережуваного простору миру, ми задаємо переміщення на 200 одиниць по осі х і переміщення на 300 одиниць по осі у Оскільки ми працюємо в 2D, просто ігноруємо вісь z і встановлюємо компонент переміщення рівним нулю Ми не описували z-координату для наших вершин, так що вона за замовчуванням буде дорівнює нулю Якщо додати до нуля нуль, все одно вийде нуль, так що наші вершини залишаться в площині ху

З цього моменту матриця Модель – уявлення OpenGL ES кодує переміщення на (200 300 0), яке буде застосоване до всіх вершин, що проходять через конвеєр OpenGL ES Якщо ви знову подивитеся на рис 74, то побачите, що OpenGL ES просто перемножить кожну вершину спочатку на матрицю Модель – уявлення, а потім застосує до вершин проекційну матрицю Досі матриця Модель – уявлення представляла собою одиничну матрицю (настройка OpenGL ES за замовчуванням) Отже, вона не впливала на наші вершини Наш невеликий виклик gl Trans atef спровокує ці зміни і перемістить всі вершини перед тим, як вони будуть спроектовані

Звичайно, все це робиться динамічно, а значення в екземплярі класу Vertices не змінюються взагалі Ми б помітили які-небудь постійні зміни в екземплярі класу Vertices, оскільки проекційна матриця вже б його змінила

Перший приклад з використанням переносу

Для чого нам потрібно перенесення Припустимо, ми хочемо візуалізувати 100 копій Боба в різних місцях світу Більше того, нам потрібно, щоб вони рухалися по екрану і змінювали напрямок кожен раз, коли зіткнуться з межами екрану (або, вірніше, межами нашої паралельної проекції конуса відображення, які збігаються з межами екрану) Це можна було б зробити за допомогою одного великого екземпляра класу Verti ces, який містить вершини 100 прямокутників – одного для кожного Боба – і перераховує місце розташування вершин для кожного кадру Простіше було б використовувати невеликий екземпляр класу Verti ces, що містить тільки один прямокутник (модель Боба) і застосовує його багато разів, переносячи його по матриці Модель – уявлення Опишемо нашу модель Боба:

Розмір кожного Боба – 32 х 32 одиниці Ми також асоціюємо його з текстурою (будемо використовувати bobrgb888png, щоб бачити межі кожного Боба)

Боб стає класом

Опишемо простий клас Bob, який відповідатиме за місце розташування Боба і його переміщення в поточному напрямку, грунтуючись на дельті часу, так само, як ми пересували містера Нома (єдина різниця полягає в тому, що ми більше не пересуваємося по сітці) Метод update буде стежити за тим, щоб Боб не вийшов за видимі межі У лістингу 712 показаний клас Bob

Лістинг 712 Bobjava

Кожен Боб поміщається в випадкове місце у створеному нами світі Всі Боби будуть спочатку рухатися в однаковому напрямку: 50 одиниць направо і 50 одиниць вгору в секунду (оскільки відбувається множення на deltaTlme) У методі update просто переміщаємо Боба в поточному напрямку, грунтуючись на часі, а потім перевіряємо, чи покинув він кордону конуса відображення Якщо покинув, міняємо напрямок і перевіряємо, чи знаходиться він як і раніше всередині конуса відображення

Тепер припустимо, що ми створюємо 100 Бобов наступним чином:

Для візуалізації кожного Боба робимо наступне (припустимо, ми вже очистили екран, встановили матрицю проекції і привязали текстуру):

Все досить просто, чи не так Для кожного Боба викликаємо його метод updateO, який буде переміщати його і перевіряти, чи залишився він у межах нашого маленького світу Потім завантажуємо одиничну матрицю в модельно-видову матрицю OpenGL ES, щоб у нас завжди було чисте стан Потім використовуємо поточні х-і у-координати Боба у виклику glTransltef Коли ми потім визуализируем модель Боба в наступному виклику, всі вершини будуть перенесені щодо поточного місця розташування Боба – саме цього ми й домагалися

Всі разом

Зробимо загальний приклад (лістинг 713) Лістинг 713 BobTestjava 100 Moving Bobs

Наш клас BobScreen містить текстуру Texture (завантажену з bobrbg888 Png), екземпляр класу Vertices, який містить модель Боба (простий текстурований прямокутник) і масив екземплярів класу Боб Ми також визначаємо константу NUMB0BS, щоб можна було змінювати кількість Бобов на екрані

Конструктор просто завантажує текстуру і модель і приписує константу NUM B0BS екземплярам класу Bob

У методі update Боби оновлюються Ми також перевіряємо, очищені чи буфери подій вводу

У методі render очищаємо екран, встановлюємо проекційну матрицю, активуємо текстурирование і привязуємо текстуру Боба Останні два рядки відповідають за візуалізацію кожного екземпляра класу Bob Оскільки OpenGL ES запамятовує їх стану, нам потрібно встановлювати активну матрицю тільки один раз (у цьому випадку ми будемо змінювати матрицю Модель – подання до решти коду) Потім ми проходимо по всім бобам, встановлюємо матрицю Модель – уявлення, грунтуючись на поточному положенні Боба, і визуализируем модель, яка буде автоматично зміщена по матриці Модель – уявлення

Ось і все Найкраще те, що ми знову використовували патерн MVC, який вже відомий нам з роботи з Містером номом Він дійсно дуже зручний при програмуванні ігор Логічна сторона Боба повністю відокремлена від його зовнішнього вигляду, що вельми непогано, так як ми можемо легко замінити його вид чимось поскладніше На рис 720 показаний результат роботи нашої програми після декількох секунд роботи

Рис 720 Дуже багато Бобов

Але на цьому цікавинки з перетвореннями не закінчуються Памятайте, кілька сторінок назад я згадував, що ми ще поговоримо про обертання і масштабування

Інші перетворення

Крім методу gl Trans 1 atef OpenGL ES також пропонує два інших методу для перетворень: glRotatefO і glScalefO

Обертання

Ось сигнатура методу glRotatef:

Перший параметр – це кут у градусах, на який ми хочемо повернути вершини Але що ж означають інші параметри

Коли ми щось повертаємо, робимо це з якої-небудь осі Що таке вісь Ми вже знаємо три осі: х, у і z Ми можемо висловити ці три осі у вигляді векторів Позитивна вісь х буде описуватися як (1 0 0), позитивна вісь у – (0 1 0), а позитивна вісь z – (0, 0, 1) Як ви можете бачити, вектор фактично кодує напрямок, в нашому випадку в 3D-просторі Напрямок Боба – це теж вектор, але в 2D-просторі Вектори також кодують місце розташування, наприклад місце Боба в двомірному просторі

Щоб описати вісь, по якій будемо повертати модель Боба, потрібно повернутися до 3D-простору На рис 721 показана модель Боба (з накладеною текстурою для орієнтації), як вона описана в 3D за допомогою попереднього коду

Рис 721 Боб в 3D

Оскільки ми не описали z-координати для вершин Боба, він знаходиться в х у-просторі нашого 3D-світу, який фактично є простором моделі Якщо ми захочемо повернути Боба, можемо зробити це по будь-якої осі (х, у, z) або навіть по якимось неймовірним осях, наприклад з координатами (0,75 0,75 0,75) Проте у випадку з нашим графічним програмуванням у двох вимірах доцільно обертати Боба в площині ху Отже, ми будемо використовувати позитивну вісь z, яка може бути описана як (0, 0, 1) як осі обертання Поворот проходитиме проти годинникової стрілки по j осі z Виклик glRotatef призведе до того, що вершини моделі Боба будуть повернені так, як це показано на рис 722:

Рис 722 Боб, повернений по осі z на 45 °

Масштабування

Ми також можемо змінити розміри Боба за допомогою glScalef наступним чином:

Виходячи з початкової позиції Боба, ми отримаємо орієнтацію, як на рис 723

Рис 723 Боб, розміри якого змінені в 2 рази по осі х і в 0,5 рази по осі у

Поєднання перетворень

Ми можемо поєднувати ефекти безлічі матриць, перемножая їх, щоб отримати нову матрицю Фактично все це роблять методи glTransl atef, glScalefO, gl Rotatef nglOrthof О Вони множать поточну активну матрицю навременную матрицю, яку створюють Внутрішньосистемний, грунтуючись на параметрах, які ми їм передаємо Зєднаємо поворот і зміна розмірів Боба:

У результаті модель Боба буде виглядати, як на рис 724 (памятаєте, ми як і раніше в просторі моделі)

Рис 724 Боб, спочатку змінений у розмірі, а потім повернений

Що трапиться, якщо ми застосуємо зміни в іншому порядку:

На рис 725 показаний результат

Рис 725 Боб, спочатку повернений, а потім змінений в розмірах

Ого, це не той Боб, до якого ми звикли Що ж тут сталося Виходячи з коду, логічно припустити, що рис 724 і 725 виглядатимуть однаково У першому фрагменті ми спочатку виробляємо поворот, а потім змінюємо розміри Боба, правильно

Ні, неправильно Порядок, в якому перетворення застосовуються до моделі, відповідає порядку, в якому OpenGLES перемножує матриці Остання матриця, на яку ми множимо поточну активну матрицю, буде першою, яка буде застосована до вершин

Якщо ми хочемо змінити розмір, повернути і перенести Боба саме в такому порядку, нам потрібно викликати методи наступним чином:

Змінимо цикл в нашому методі BobScreenpresents ось так:

Результат буде виглядати, як на рис 726

Рис 726 Сто Бобов, змінених в розмірі, повернутих і переміщених (у такому порядку)

Коли я тільки починав працювати з OpenGL, я постійно плутав порядок операцій з матрицями Щоб запамятати, як це правильно робити, я винайшов мнемонічне слово ПООПЕП: останнім описаний, перший застосований (Так, мені є ще над чим працювати в мнемонике)

Найпростіший спосіб навчитися правильно працювати з модельно-видовими перетвореннями – використовувати їх якомога частіше Я пропоную вам взяти вихідний файл BobTest java і трохи по змінювати внутрішній цикл для того, щоб подивитися різні ефекти

Зверніть увагу, що для візуалізації кожної моделі ви можете описати стільки змін, скільки захочете Додайте повороти, переміщення і зміни розмірів Пограйте

Після розгляду цього прикладу ми тепер знаємо практично все, що потрібно, про OpenGL ES для написання ігор 2D Чи ні

Джерело: 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>

*

*