Игри5 мин четене

Как работят 3D игрите в браузъра: WebGL и three.js, обяснени просто

Преди години 3D игра означаваше инсталация от диск или голямо изтегляне. Днес можете да отворите връзка и след няколко секунди да карате камера над цял град с коли, светофари и смяна на деня и нощта. Ето какво се случва зад екрана — без формули, но и без излишно опростяване.

Видеокартата върши тежката работа

Всеки 3D обект на екрана е съставен от малки триъгълници. Сграда може да има стотици, а детайлна кола — хиляди. За всеки кадър някой трябва да изчисли къде попада всеки триъгълник, кои се виждат и какъв цвят има всеки пиксел. Процесорът (CPU) е добър в сложна логика, но прави сравнително малко неща едновременно. Видеокартата (GPU) е направена точно за обратното: хиляди прости изчисления паралелно.

Затова 3D игрите оставят на процесора правилата на играта — парите, трафика, кой обект се строи — а рисуването прехвърлят на видеокартата. Въпросът е как уеб страница да говори с видеокартата, без да ѝ дава опасен достъп до компютъра.

WebGL и WebGPU: мостът към видеокартата

Отговорът е WebGL — стандарт, с който JavaScript в страницата може да рисува с помощта на видеокартата в елемент <canvas>. WebGL 1.0 е публикуван през 2011 г., а WebGL 2 — през 2017 г. и днес се поддържа от всички масови браузъри, на компютър и на телефон.

Новото поколение е WebGPU. За първи път е пуснат в стабилна версия в Chrome 113 през 2023 г. и постепенно идва и в другите браузъри. Той е по-близо до начина, по който работят съвременните видеокарти, и позволява и изчисления, които не са рисуване. За повечето игри обаче WebGL все още е най-сигурният избор, защото работи почти навсякъде.

Браузърът стои между страницата и видеокартата: проверява заявките и не позволява на сайта да чете чужди данни. Затова 3D в браузъра е безопасно по същия начин, както и останалото съдържание на страницата.

three.js: да не пишем всичко от нулата

Директната работа с WebGL изисква много код дори за едно въртящо се кубче. Затова повечето проекти използват библиотека. Най-популярната е three.js, започната от Рикардо Кабельо (известен като mrdoob) през 2010 г. и поддържана от голяма общност.

three.js въвежда понятия, които се разбират интуитивно:

  • Сцена — светът, в който стоят всички обекти.
  • Камера — откъде и накъде гледаме. В градски строител това обикновено е камера отгоре под ъгъл.
  • Меш (mesh) — геометрия (триъгълниците) плюс материал (как изглежда повърхността).
  • Материали и светлини — дали повърхността е матова или лъскава, колко силно я осветява слънцето или уличната лампа.
  • Шейдъри — малки програми, които се изпълняват на видеокартата и изчисляват позицията и цвета на всяка точка. Материалите в three.js всъщност са готови шейдъри.
  • Рендерер — частта, която превръща сцената и камерата в картина на екрана.

Цикълът на кадрите и бюджетът от 16,7 ms

Играта не рисува една картина, а десетки в секунда. Браузърът предлага функцията requestAnimationFrame: „извикай ме преди следващото опресняване на екрана“. При всяко извикване играта обновява състоянието — колите се придвижват, слънцето се спуска — и рисува нов кадър.

При 60 кадъра в секунда за един кадър има около 16,7 милисекунди. В това време трябва да се сметне логиката, да се подготвят обектите и видеокартата да нарисува всичко. Ако работата отнеме повече, кадърът закъснява и картината започва да „накъсва“. Затова оптимизацията на 3D игрите е до голяма степен борба за милисекунди.

Добра практика е логиката да зависи от изминалото време, а не от броя кадри. Така кола, която се движи с 50 км/ч, се движи еднакво бързо и на мощен компютър, и на по-стар телефон — просто на телефона движението е с по-малко кадри.

Как се рисуват хиляди обекти

Всяка отделна заявка към видеокартата („нарисувай този обект с този материал“) се нарича draw call. Тя има собствена цена, независимо колко малък е обектът. Хиляди отделни коли и дървета означават хиляди заявки и бавна игра. Има няколко основни техники:

  • Инстанциране (instancing) — един и същ модел, например дърво или улична лампа, се рисува на много места с една заявка.
  • Ниво на детайлност (LOD) — далечните сгради се показват с по-прости модели, защото разликата не се вижда.
  • Отрязване (culling) — обектите извън полезрението на камерата изобщо не се изпращат за рисуване.
  • Сливане на геометрия — неподвижни обекти като улици и тротоари се събират в по-малко на брой големи мешове.

Текстурите — картинките върху повърхностите — заемат паметта на видеокартата. Текстура 4096 × 4096 изисква четири пъти повече памет от 2048 × 2048. На телефон паметта свършва бързо, затова се използват по-малки текстури и компресирани формати, които видеокартата може да чете директно.

Модели, зареждане и кеширане

Моделите на сгради, коли и машини обикновено се правят в програми като Blender и се записват във формат glTF (или двоичния му вариант .glb). Често го наричат „JPEG на 3D“: компактен е, съдържа геометрия, материали и анимации и се зарежда лесно в three.js.

Тъй като няма инсталация, всичко се изтегля по мрежата. За да не чака играчът, моделите се зареждат постепенно: първо най-нужното, после останалото, докато играта вече върви. Браузърът кешира изтеглените файлове, така че при второто отваряне те идват от диска. Играта може да бъде и PWA (прогресивно уеб приложение) — добавя се на началния екран и се отваря като приложение, без магазин.

Къде се пази напредъкът

Най-простото място за запис е localStorage — малко хранилище в браузъра на конкретното устройство. Удобно е, но ако изчистите данните на браузъра или смените устройството, записът остава там. Затова по-сериозните игри пазят напредъка и на сървър („в облака“), свързан с профил. Тогава можете да започнете на компютъра и да продължите на телефона.

Пример: градът в „Строителна империя“

Нашата игра „Строителна империя“ е изградена с three.js и работи в браузъра на компютър и телефон, включително като PWA. В нея виждате всички описани идеи на практика: градове с трафик и пешеходци, светофари, сгради, които растат етап по етап, и смяна на деня и нощта, при която светват прозорците и уличните лампи. Всяко от тези неща трябва да се побере в бюджета на кадъра — и затова голяма част от работата по такава игра е не само да се добави нещо ново, а да се направи така, че да върви гладко и на по-слаб телефон.

Ако ви интересува как се мисли икономиката в такава игра, вижте статията за дизайна на икономиката в градски строител.

Екипът на Темидасофт

Пишем за сайтове, софтуер и игри, които правим сами във Велинград.

За нас
Read in English