Об'єктно-орієнтований OpenGL


12

Я деякий час використовую OpenGL і прочитав велику кількість навчальних посібників. Крім того, що багато з них все ще використовують фіксований конвеєр, вони зазвичай кидають усі ініціалізації, зміни стану та малювання в один вихідний файл. Це добре для обмеженого обсягу підручника, але мені важко розробити, як його масштабувати до повної гри.

Як розділити використання OpenGL між файлами? Концептуально я бачу переваги наявності, скажімо, класу візуалізації, який суто виводить речі на екран, але як працюватимуть такі елементи, як шейдери та світильники? Чи слід мати окремі заняття для речей, таких як світильники та шейдери?


1
Існують ігри з відкритим кодом, а також більші підручники, які мають більше коду. Перегляньте деякі з них і подивіться, як організовано код.
MichaelHouse

Ви новачок, коли справа стосується рендерингу двигунів?
Самаурса

На це питання неможливо відповісти без деякого звуження сфери застосування. Тільки що ви намагаєтесь побудувати? Яка гра, яку графіку вона має тощо?
Нікол Болас

1
@Sullivan: "Я думав, що подібні поняття застосовуватимуться майже до будь-якої гри". Вони ні. Якщо ви попросите мене зробити Tetris, я не збираюся заважати робити великий шар обгортки або щось навколо OpenGL. Просто використовуйте його безпосередньо. Якщо ви попросите мене зробити щось на зразок Mass Effect, тоді нам знадобиться кілька шарів абстракції навколо нашої системи візуалізації. Кидання двигуна Unreal у Tetris використовує рушницю для полювання на мух; це робить завдання набагато важчим, ніж просто ручне кодування його безпосередньо. Ви повинні будувати лише настільки велику і складну систему, скільки вам потрібно , і не більшу.
Ніколь Болас

1
@Sullivan: Єдина складність, яку має на увазі ваше запитання, полягає в тому, де ви говорите про розділення на кілька файлів. Що я б робив навіть у тетрісі. І між Tetris і Unreal двигуном існує багато рівнів складності. Отже знову: про кого ви питаєте?
Нікол Болас

Відповіді:


6

Я думаю, що OO OpenGL не є таким необхідним. Це інакше, коли ви говорите про шейдер, модель тощо.

В основному, ви б спершу зробили ініціалізацію гри / двигуна (та інші речі). Потім ви завантажуєте текстури, моделі та шейдери в оперативну пам’ять (якщо потрібно) та об'єкти буфера, а також завантажуєте / компілюєте шейдери. Після цього ви, у своїй структурі даних або класі шейдерів, моделі, маєте ідентифікатори int ідентифікаторів шейдерів, моделей та буферних текстурних об'єктів.

Я думаю, що більшість двигунів мають компоненти двигуна, і кожен з них має певні інтерфейси. Усі двигуни, які я розглядав, мають деякі компоненти, такі як Renderer або SceneManager або обидва (залежить від складності гри / двигуна). Тоді ви можете мати клас OpenGLRenderer та / або DXRenderer, які реалізують інтерфейс Renderer. Тоді якщо у вас є SceneManager і Renderer, ви можете виконати деякі з наступних дій:

  • Траверса SceneManager і відправити кожен об'єкт Renderer для надання
  • Інкапсуляція верхній корпус в деякому SceneManager методі
  • Надіслати SceneManager для видеонаблюдения так він обробляє його

Візуалізатор, ймовірно, викличе функцію малювання об'єкта, яка викликала б функцію малювання кожної сітки, яка складається з, а сітка прив'язує об'єкт текстури, зв'язує шейдер, викликає функцію малювання OpenGL, а потім використовує шейдери, текстури та об'єкти буфера даних об'єктів.

ПРИМІТКА. Це лише приклад, ви повинні вивчити SceneManager більш детально та проаналізувати ваш приклад використання, щоб побачити, який варіант найкращої реалізації

Звичайно, у вас є інші компоненти двигуна, такі як MemoryManager , ResourceLoader тощо, які б забезпечили використання як відео, так і оперативної пам'яті, щоб вони могли завантажувати / вивантажувати певні моделі / шейдери / текстури за необхідності. Концепції для цього включають кешування пам’яті, відображення пам’яті тощо тощо. Існує багато деталей та понять про кожен компонент.

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

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


Це відповідь, яку я начебто шукав. Однак, коли ви говорите «… завантажуйте текстури, моделі та шейдери в оперативну пам’ять (при необхідності) та об’єкти буфера та завантажуйте / компілюйте шейдери ...» повертає мене до мого початкового питання; чи слід використовувати об’єкти для інкапсуляції таких речей, як моделі та шейдери?
Салліван

об'єкт - це примірник класу, і "ви повинні повністю ними користуватися".
edin-m

Вибачте, я мав намір запитати "як я повинен використовувати об'єкти". Моє ліжко.
Салліван

Ну, це залежить від вашого дизайну класу. Деякий базовий приклад був би інтуїтивно зрозумілим, щось на зразок: object3d (class) має сітки (class); кожна сітка має матеріал (клас); кожен матеріал має текстуру (може бути класу, або просто id) та шейдер (клас). Але читаючи про кожен компонент, ви побачите різні, але однакові підходи до створення SceneManager, Renderer, MemoryManager (все це може бути однокласним чи декількома, успадкованими тощо тощо). На цю тему написано десятки книг (архітектура ігрового двигуна), і щоб детально відповісти на запитання, можна було написати її.
edin-m

Я думаю, що це найкраща відповідь, яку я збираюся отримати. Дякую за допомогу :)
Салліван

2

У OpenGL вже є деякі поняття "Object".

Наприклад, що-небудь з ідентифікатором може бути перетворено як об'єкт (Є також речі, спеціально названі "Об'єкти"). Буфери, текстури, об'єкти буферних вершин, об'єкти масиву вершин, об'єкти буферних кадрів тощо. З невеликою роботою можна обгорнути заняття навколо них. Це також дає простий спосіб повернутися до старих застарілих функцій OpenGL, якщо ваш контекст не підтримує розширення. Наприклад, VertexBufferObject може повернутися до використання glBegin (), glVertex3f () тощо.

Вам може знадобитися кілька способів відійти від традиційних концепцій OpenGL, наприклад, ви, ймовірно, хочете зберігати метадані про буфери в буферних об'єктах. Наприклад, якщо буфер зберігає вершини. Який формат вершин (тобто положення, нормали, текстові слова тощо). Які примітиви він використовує (GL_TRIANGLES, GL_TRIANGLESTRIP тощо), інформацію про розміри (скільки поплавків зберігається, скільки трикутників вони представляють тощо). Просто для того, щоб було легко підключити їх до команд малювання масивів.

Рекомендую подивитися на OGLplus . Це зв'язки C ++ для OpenGL.

Також glxx , але це лише для завантаження розширення.

На додаток до обгортання API OpenGL, вам слід поглянути на створення трохи більш високого рівня, який будується над ним.

Наприклад, клас менеджера матеріалів, який відповідає за всі ваші шейдери, завантаження та використання їх. Також було б відповідально за передачу їм властивостей. Таким чином ви можете просто зателефонувати: Materials.usePhong (); material.setTexture (деякийтекст); material.setColor (). Це дозволяє передбачити більшу гнучкість, оскільки ви можете використовувати нові речі, такі як спільні об’єкти буфера, щоб мати лише 1 великий буфер, що містить усі властивості, якими користуються ваші шейдери в 1 блоці, але якщо його не підтримується, ви повертаєтесь до завантаження до кожної програми шейдерів. Ви можете мати один великий монолітний шейдер і мінятись між різними моделями шейдерів, використовуючи рівномірні підпрограми, якщо він підтримується або ви можете перейти до використання безлічі різних невеликих шейдерів.

Ви також можете подивитися на те, що витрачається на технічні характеристики GLSL для написання коду шейдера. Наприклад, #include був би надзвичайно корисним та дуже простим у застосуванні у вашому коді завантаження шейдерів (для нього також є розширення ARB ). Ви також можете генерувати код на льоту, базуючись на тому, які розширення підтримуються, наприклад, використовуйте спільний обмундирований об’єкт або поверніться до використання звичайної форми.

Нарешті, вам потрібен API конвеєра вищого рівня, який виконує такі дії, як графіки сцен, спецефекти (розмиття, світіння), речі, для яких потрібні багаторазові переходи, такі як тіні, освітлення тощо. А потім на додаток до ігрового API, який не має нічого спільного з графічним API, а лише має справу з об'єктами у світі.


2
"Я рекомендую вам переглянути OGLplus. Це прив'язки C ++ для OpenGL." Я б рекомендував проти цього. Я люблю RAII, але цілком не підходить для більшості об’єктів OpenGL. Об'єкти OpenGL асоціюються з глобальною конструкцією: контекстом OpenGL. Таким чином, ви не зможете створити ці об’єкти C ++, поки у вас не виникне контекст, і ви не зможете видалити ці об'єкти, якщо контекст уже знищений. Також це дає ілюзію, що ви можете змінювати об'єкти, не змінюючи глобального стану. Це брехня (якщо ви не використовуєте EXT_DSA).
Нікол Болас

@NicolBolas: Не можу я перевірити, чи є контекст, і лише потім ініціалізувати? Чи, можливо, дозволяють лише менеджерам створювати об'єкти, для яких потрібен контекст OpenGL? --- btw, чудовий набір навчальних посібників (посилання у вашому профілі)! Я чомусь ніколи не натрапляв на них під час пошуку OpenGL / Graphics.
Самаурса

@Samaursa: Для чого? Якщо у вас є менеджер об’єктів OpenGL, то ... вам не потрібно, щоб об’єкти піклувалися про себе; менеджер може це зробити за них. І якщо ви ініціалізуєте їх лише тоді, коли існує контекст, що станеться, якщо ви спробуєте використати об'єкт, який був неправильно ініціалізований? Це просто створює слабкість у вашій кодовій базі. Це також не змінює нічого, про що я говорив про здатність змінювати ці об'єкти, не торкаючись глобального стану.
Нікол Болас

@NicolBolas: "Ви б не змогли створити ці об'єкти C ++, доки у вас не виникне контекст" ... чи це інакше, ніж використання голих конструкцій OpenGL? На моїх очах oglplus::Contextклас робить цю залежність дуже помітною - чи це буде проблема? Я вірю, що це допоможе новим користувачам OpenGL уникнути багатьох проблем.
xtofl

1

У сучасному OpenGL ви можете майже повністю відокремити відтворений об'єкт один від одного, використовуючи різні програми vaos і shader. І навіть реалізацію одного об’єкта можна розділити на багато шарів абстракції.

Наприклад, якщо ви хочете реалізувати рельєф місцевості, ви можете визначити TerrainMesh, конструктор якого створює вершини та індекси для місцевості, і встановлює їх у масиви масивів, і - якщо ви надаєте йому положення атрибутів, - він шейдер перекладає ваші дані. Він також повинен знати, як його візуалізувати, і слід подбати про те, щоб відновити всі зміни контексту, які він зробив для налаштування візуалізації. Цей клас сам не повинен нічого знати про програму шейдера, яка збирається її надати, і не повинна нічого знати про будь-які інші об'єкти в сцені. Вище цього класу можна визначити Terrain, який знає код шейдера, і його завдання полягає у створенні зв’язку між шейдером та TerrainMesh. Це повинно означати отримання атрибутів та рівномірних позицій та завантаження текстур тощо. Цей клас не повинен нічого знати про те, як реалізується місцевість, який алгоритм LoD він використовує, він просто відповідальний за затінення місцевості. Вище можна визначити такі функції, які не є OpenGL, такими як behivour та виявлення зіткнень тощо.

До речі, навіть незважаючи на те, що OpenGL призначений для низькорівневого використання, ви все одно можете створювати незалежні шари абстракції, які дозволять масштабувати масштабність до величини гри Unreal. Але кількість шарів, які ви бажаєте / потребуєте, дійсно залежить від розміру програми, яку ви хочете.

Але не брешіть собі з приводу цього розміру, не намагайтеся імітувати об’єктну модель Unity у лінійному додатку 10 к., Результат буде повною катастрофою. Будуйте шари поступово, лише збільшуйте кількість шарів абстракції, коли це потрібно.


0

ioDoom3 - це, мабуть, прекрасна відправна точка, оскільки ви можете покластися на Carmack, щоб дотримуватися чудової практики кодування. Крім того, я вважаю, що він не використовує Megatexturing в Doom3, тому він є відносно прямим вперед як рендерінг.


6
"як ви можете покластися на Carmack, щоб дотримуватися чудової практики кодування" О, людина, це добре. Carmack дотримується чудової практики кодування C ++. Це бунт! О, ти не жартував. Гм ... ви коли-небудь насправді переглядали його код? Він програміст на С і так він думає. Що добре для C, але питання стосується C ++ .
Нікол Болас

Я родом із C, тому його код має для мене багато сенсу: P і так, я витратив трохи часу, працюючи на іграх на основі землетрусів.
chrisvarnz
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.