Showing posts with label OpenGL. Show all posts
Showing posts with label OpenGL. Show all posts

28/04/2020

Web (3): Daft Jong — простая игра на JS/WebGL

В этой заметке я представляю простейшую версию (обкаточную реализацию) игры типа «пасьянс», а именно — трёхмерную разновидность известного MahJong'а (его пасьянсной вариации). Хотя, скорее, у меня смесь головоломки и пасьянса.

Технологии надо описывать, а в игру — играть. Поиграть вы можете, пройдя по ссылке внизу. А здесь я вкратце опишу какие технологии я применял и какие решения принимал. Игра написана на WebGL, с использованием Three.js. Цель игры — разобрать куб, попарно убирая одинаковые фишки (кубики).

Правила
«Правилами» я здесь называю пары узоров, так как именно по ним пользователь играет. Поскольку выбирать фишки нужно попарно, перед созданием объектов на сцене, нужно составить какую-то структуру, содержащую (описывающую) эти правила и гарантирующую «сходимость» головоломки. Для этого реализован алгоритм, создающий такую структуру, учитывающий выбранный размер головоломки, и потом, уже по этой структуре генерируется сама головоломка, её представление — соответствие расположения «правил» в пространстве с узорами.

Отрисовка фишек
В этой игре 35, или уже более, разных «правил». Узоры на фишках я решил отрисовать алгоритмом. Во-первых, потому что рисование такого количества картинок руками у меня заняло бы больше времени (а это не входило в мои планы), а написав алгоритмы отрисовки нескольких примитивных элементов, основанных на линиях и кругах, я смог их комбинировать и получить большое количество «правил». И, на данный момент, ещё не все комбинации употреблены. Во-вторых, генерация узоров на стороне клиента даёт ещё три бонуса. Первый серьёзный — возможность изменения картинок на лету. Пока реализовано только изменение цветов. Но можно реализовать случайную генерацию узоров, что не позволит игрокам «привыкнуть» к «правилам». Второй бонус заключается в возможности контролировать качество графики на стороне клиента, играя размером текстуры и соотношением логического пикселя экрана к аппаратному — DPR. Эту возможность, я может быть использую в реализации алгоритма адаптивного подбора нагрузки на CPU/GPU. Третий бонус, по началу не столь важный — трафик. Но если «правил» — разных цветов и комбинаций, будет больше, то исключение ожидания загрузки картинок с сервера будет более желательно, а рисовать руками придётся ещё больше и скучнее.

Выбор объектов
Так как в игре нужно разбирать головоломку, выбирая попарно фишки, технически нам нужен механизм выбора объектов на экране. Два подхода к решению этой задачи я описывал в статье Web (1): RayCasting vs GPU Color Picking (на примере Three.js). Для этого приложения я выбрал метод трассировки лучом (RayCasting) потому что объектов на сцене немного, а прозрачность текстур не используется.

NB
У меня игра лучше всего работает на телефонах — хоть и греет устройство и батарею расходует, но играется идеально гладко. На всех моих компьютерах — Linux Netbook, MacBook и даже большой Linux на Core i7 c nVidia GPU, работает гораздо хуже — компьютеры шумят, греются, а игра сильно тормозит. А в Safari на MacOS вообще едва дышит, так как аппаратная OpenGL не используется, якобы для экономии батареи.

P.S.
В игре так же реализована несложная система авторизации, её я здесь не описываю. Про это будет отдельная статья.

Ссылка на игру: Daft Jong

Как играть: выбираете один элемент, он выделяется, ищете второй такой же, выбираете его, выбранные фишки удаляются с экрана. Таким образом надо разобрать весь куб. В конце выводится время, за которое вы разложили игру и количество ошибочных ходов (попыток выбрать неодинаковые кубики). На мобильных устройствах вращение куба осуществляется одним пальцем, приближение/отдаление — жестом двумя пальцами. На больших системах куб вращается движением мыши с зажатой правой кнопкой, а приближение/отдаление— колесом мыши.


18/02/2020

Web (1): RayCasting vs GPU Color Picking (на примере Three.js)

В определённый момент, перед разработчиком графических приложений с использованием OpenGL/WebGL встаёт задача взаимодействия пользователя с объектами. Будь то элементы двухмерного интерфейса (частный случай трёхмерного пространства) или объекты трёхмерной сцены, существует два подхода к решению этой задачи. Первый заключается в поиске объекта, на который указывает мышь математическим (тригонометрическим) расчётом.  Второй — поиск объекта по цвету пикселя, на который пользователь указал мышью. Первый кажется логичным, понятным и красивым, второй — на первый взгляд кажется странным, но у обоих методов есть свои плюсы и минусы и свои области применения.

В этой статье мы рассмотрим два метода выбора объекта на сцене (OpenGL/WebGL на примере Three.js) — RayCasting и GPU Color Pick.

RayCasting — это технология определения пересечения луча с объектом. При определении выбранного объекта — объекта, на который навели мышь, например, выбирается первый объект, с которым произошло пересечение. На самом деле собираются все объекты, с которыми пересёкся луч, а уже мы используем только первый. RayCasting работает на стороне CPU, то есть, не задействует специфические вычислительные мощности GPU. 

В Three.js для этих целей имеется уже разработанный объект THREE.Raycaster. Пользоваться им достаточно просто, в примере, которым я завершу эту статью, этот метод будет представлен. Описывать его механику смысла не вижу — это обычная тригонометрия.

У RayCasting’а есть два минуса:

  1. Он работает медленнее, так как работает на CPU, и в случае, когда у нас много объектов, это может быть очень тяжёлой задачей для центрального процессора. А в современной графике с использованием актуальных методов создания карт (т.н. сцен) количество объектов может быть очень большим.
  2. Он не учитывает факторы текстуры — прозрачность, и просто «выбирает» объекты, которые встречаются лучу (в нашем случае — выбор объекта мышью, луч рассчитывается от камеры), то есть работает исключительно геометрия (математика).

Технология GPU Color Pick заключается в следующем. При создании сцены, все объекты дублируются в другую сцену, обычно называемую PickingScene и связываются некоторыми ID реальных объектов с цветами объектов в PickingScene. Для исключения излишней нагрузки на GPU, PickingScene, как правило, делается очень маленькой (выходной буфер рендеринга очень маленькой площади, это в некоторой степени сокращает время на рендеринг). В нашем случае, по наведению мыши, вызывается функция поиска объекта в PickingScene и затем выбирается ID объекта в реальной сцене. В силу того, что технология GPU Color Pick работает по цвету, она лишена второго минуса RayCasting’а — мы можем использовать альфа-канал в текстурах объектов. Это значит, что мы можем дать пользователю возможность «выбирать» объекты стоящие «за», сквозь «прозрачные» области стоящих «перед». В силу того, что технология GPU Color Pick работает на GPU, а он, в свою очередь очень «заточен» под такие задачи, эта технология работает гораздо быстрее и почти полностью разгружает CPU (на нём остаётся лишь задача соотнести цвета и ID объектов).

У GPU Color Pick (как ни странно) есть два минуса:

  1. Мы не можем получить координаты места «встречи» указателя (здесь это не луч и не вектор) и объекта — только сам объект, так как объект выбирается не геометрией, а цветом.
  2. Подгружается GPU. Это хорошо тем, что разгружается CPU, но может быть плохо, если вычислительные мощности GPU для нас критичны. Плюс, в момент процесса самого Picking’а, нам надо ждать на CPU пока GPU выполнит задачу поиска объекта по цвету.


Все эти технологии, конечно же применяются и на Bare WebGL и на чистом OpenGL.

Чтобы поиграться (работает без Web-сервера):

git clone https://gitlab.com/daftsoft/gpu-color-pick-vs-raycasting