Как исправить normal map в photoshop
Это пятая статья из цикла про ААА-пайплайн. Вот ссылки на все пять, выбирай ту, которая тебе нужна:
Эта статья поможет новичкам, которые хотят научиться делать запечку без артефактов. Ты узнаешь, что такое запечка, зачем она нужна и научишься переносить детализацию с high poly на low poly. Внимательное изучение статьи займет около 20 минут. Если возникнут вопросы — пиши в чат-бот (кнопка справа внизу). Там на связи живой менеджер :) Он поможет разобраться. Ну что, давай начнем!
Что такое запечка в 3D
Взглянем на low poly модель нашего студента.
Низкополигональная модель, созданная на этапе ретопологииМинимум полигонов и чистая сетка. Эта модель будет загружаться в игровой движок.
Есть ещё high poly модель с высокой детализацией и скульпт.
При помощи запечки мы переносим детали с high poly и скульпта на low poly модель. В итоге, в игровом движке будет легкая low poly модель с минимальным количеством полигонов, но выглядеть она будет так, будто на ней куча деталей:На low poly мы добавляем запеченные карты нормала и карту затенений. Это карты, которые обманывают поведение игрового света. Свет падает под определенным углом на модель и создает блик. В итоге нам кажется, что в модели много фасок, деталей и вырезов.
На этапе запечки наша задача — запечь 3 карты:
1) Normal map — карту неровностей
2) Ambient Occlusion (AO) — карту затенения
3) Color ID — цветные маски
Если добавим Normal map и AO на low poly модель — на ней появится детализация с high poly и скульпта. Благодаря Color ID модель легче разбить по материалам и текстурировать. Эти карты создают на основе развертки, которую мы делали этапом ранее. Помни, если есть ошибки на развертке или low poly модели — будет куча проблем с артефактами.
Как запекать карты
Пример low poly модели с включенным нормалом и без него
Новые полигоны не создаются, это лишь иллюзия формы:Из-за того, что игрок видит модель в игре на расстоянии, нам не нужно тратить несколько часов, чтобы убрать черные полоски на нормале:
Normal map создает иллюзию объема из-за трех карт в каналах текстуры: красной, зеленой, синей. Чтобы переключаться между каналами, откроем файл с нормалом в Photoshop и зайдем во вкладку Channels.
128х128х255 — нейтральный цвет нормала.
Если добавить полностью нейтральный нормал — особой разницы видно не будет. Модель будет шейдить так же, как обычная low poly.
В каком формате лучше хранить нормал?
После запечки часто приходится вносить изменения в нормал при помощи Фотошопа. Поэтому файл лучше сохранять в форматах Targa или TIF. При сохранении есть выбор, сохранять в 24 или 32 bit. Если есть Альфа-канал — сохраняем с 32 bit. Если Альфа-канала нет — в 24 bit.
Ambient occlusion (AO) — это карта затенения. Она показывает самые глубокие тени в объекте — в основном в углублениях и на пересечениях. Эту карту используют в игровых движках для создания корректного освещения и в текстурировании.
Например, без АО почти нереально сделать грязь. Но с картой АО мы легко сгенерируем маску углублений, чтобы забить их грязью.
По-умолчанию карта черно-белая, но на этапе текстурирования ее можно покрасить.
3. Карта Color ID
Во время текстурирования нам нужно быстро выделять геометрию, которую мы хотим затекстурить. Чтобы это сделать в один клик внутри Substance Painter, нужно запечь карту Color ID. Она поможет выделять большие куски модели. Это поможет легко затекстурить выбранную группу объектов.
С помощью Color ID красим модель в разные цвета
Чтобы создать карту Color ID, нужно покрасить high poly модель в разные цвета. Один цвет — это одна группа объектов разбитая по материалам. Например, все дерево на Color ID — оранжевое, вся кожа — розовая, ржавый металл — синий, шерсть — голубая, а новый металл — зеленый.
Color ID — не цвета будущей модели, эта карта нужна для разделения на разные материалы.
Много дополнительных карт для запечки есть в Marmoset, а еще там можно печь цвета и материалы с других моделей и текстур, чтобы не переделывать с нуля. Но сейчас гораздо проще печь дополнительные карты прямо в Substance Painter.
Список карт, которые можно запечь
Если ты интересовался какой софт лучше использовать для запечки — это не важно. Принцип запечки во всех программах одинаковый. Просто выбирай, что больше нравится: Maya, Blender, 3D Max, Modo или Cinema 4D.
Как сделать самую быструю в мире запечку?
Шаг 1: Открываем Marmoset.
Шаг 2: Загружаем low poly и high poly, добавляем их в одну группу запечки (Baker).
Шаг 3: Нажимаем кнопку «Bake».
Когда карта будет готова, открываем Maya, добавляем на low poly карту нормалей.
Получается такой результат:
Что делать, чтобы на модели не было артефактов
1. Правильно подготовить low poly к запечке
Для этого мы следим за шейдингом модели. Вот пример плохого и хорошего шейдинга:
Секрет хорошего шейдинга — в правильной работе с хардами и софтами:
- Если угол 90 градусов — ставим хард.
- Если угол меньше 90 градусов — ставим хард.
- Если угол больше 90 градусов — ставим софт. Даже если угол 91 градус, ставим софт.
2. Убирать зазоры между геометрией
Следим, чтобы не было дырок между геометрией:
В таких местах нужно слегка притопить геометрию внутрь другой
3. Триангулировать модель
Проверив всю low poly модель, обязательно включаем функцию триангуляции.
Если не триангулировать модель перед запечкой — в разном софте она будет смотреться по-разному.
Что учитывать на high poly?
Если high poly шейдит некрасиво — дорабатываем геометрию. С high poly вся детализация будет переноситься на low poly.
Следи, чтобы фаски не были тонкими, иначе они не запекутся. Вот пример хороших и тонких фасок:
Скошенная геометрия лучше печется на плоскости. А геометрия без скосов не печется совсем.
Крутой лайфхак в мире моделлеров — парящая геометрия.
Проверяем, совпадают ли high poly и low poly
High poly и low poly должны максимально совпадать. Вот пример, когда они не совпадают:
Чтобы увидеть места, где high poly и low poly не совпадают, покрасим high poly в яркий контрастный цвет, а low poly — в белый:Затем проверяем, совпадают ли фаски. Для этого назначаем на low poly бликующий материал и делаем его прозрачным.
Что делать перед тем, как начать запечку
Мы уже подготовили low poly, high poly и развертку к запечке. Но прежде чем нажимать волшебную кнопку, нужно выполнить еще три простых действия, которые помогут в дальнейшем.
Правильный нейминг сэкономит гору времени во время работы с группами запечки — лишний мусор не будет мешать при работе. Проверяем, совпадает ли нейминг внутри группы low poly с неймингом внутри high poly.
lowpoly -> barrel
sculpt -> zbrush_barrel
highpoly -> high_barrel
В Maya есть полезная функция File → Optimize Scene Size, которая удаляет из сцены мусор, который нигде не используется. Лишние слои, материалы и пустые группы.
Перед запечкой создаем отдельную папку «Bake» и сохраняем туда бэкап исходного файла до начала запечки — на всякий случай.
Подготовка сцены в Marmoset
Ставим более высокое разрешение
Прежде чем делать запечку, указываем какого размера будут карты. Ставим разрешение карт в 2 раза выше, чем будет у финальной модели. Так часто делают в продакшене, так как текстура в 2к уменьшенная до 1к и выглядит лучше, чем текстура, сделанная сразу в 1к.
Это четвёртая часть туториала о картах нормалей, но она независима от остальных частей и её можно читать отдельно.
Здесь я перечисляю проблемы карт нормалей, с которыми я сталкивался за годы работы, и некоторые решения, позволяющие их устранить.
Проблема: на рёбрах модели присутствуют «чёрные линии» или «вставки»
Такое происходит, когда у модели есть резкие рёбра (hard edges), поскольку вершины модели имеют нормали, полностью перпендикулярные поверхности полигона, из-за чего программа запекания может пропустить некоторые детали (оставляя на модели чёрные линии).
Решение: программы запекания карт нормалей учитывают эту проблему при создании карт нормалей и пытаются снизить её влияние, вычисляя немного больше информации за нормалями вершин, но чтобы сохранить её, им нужен зазор между UV-развёртками полигонов.
Здесь есть более подробное объяснение, но на практике правило довольно простое: когда на модели есть резкое ребро, нужно отделять в UV соединённые им грани.
Проблема: карта нормалей выглядит СОВЕРШЕННО неправильно, особенно под некоторыми углами
Эта проблема может возникать по множеству причин. Давайте обсудим некоторые из них:
-
Вы используете неправильное касательное пространство: нормали вашей lowpoly-модели, которые мы пытаемся модифицировать при помощи карты нормалей, могут вычисляться в программе запекания иначе, нежели в программе, использованной для рендеринга модели. Если эти вычисления отличаются, карта нормалей может выглядеть очень странно, особенно под некоторыми углами.
Также возможно, что вы используете в качестве карты нормалей касательного пространства карту нормалей мирового пространства. В таком случае убедитесь, что вы выполняете запекание карты нормалей касательного пространства, и используете её в этом качестве.
Проблема: как мне создать карту нормалей острого конуса?
Решение: вам это… не нужно. Не обязательно создавать карты нормалей для всего. Острый конус — классический пример этого, но существует множество других случаев, когда карты нормалей не являются решением.
Мы используем карты нормалей для изменения направления нормалей lowpoly-моделей. Иногда направление нормалей правильно и не требует никаких изменений, а иногда нормали lowpoly чрезвычайно повёрнуты (как в случае острого шипа) и детали из highpoly-модели неправильно сопоставляются с поверхностью lowpoly-модели. В таких случаях я просто удаляют детали карты нормалей при помощи такого цвета:
Этот цвет на 50% красный, на 50% зелёный и на 100% синий, и он не меняет направления нормалей карты нормалей касательного пространства, поэтому можно использовать его для удаления деталей в местах с неудачной проекцией.
Острый конус — это просто пример одного из случаев, когда карты нормалей могут не решить ваших проблем. Важно здесь помнить, что в некоторых случаях карта нормалей не является наилучшим решением, её возможности ограничены и мы не можем ожидать, что они будут вести себя так, как нам нужно, в любой ситуации. Иногда мы тратим много времени, пытаясь заставить работать карту нормалей, когда можно было бы просто добавить деталей в diffuse-текстуру или в lowpoly, а не пытаться передать деталь при помощи карты нормалей.
Проблема: детали на моей модели выглядят вывернутыми.
Это очень распространённая проблема, и её можно наблюдать во многих видеоиграх, даже AAA-уровня.
Как мы видели в этом туториале [перевод на Хабре], карты нормалей — это текстуры, использующие зелёный, красный и синий каналы для изменения способа отражения света от поверхности модели, когда он падает соответственно сбоку, сверху и спереди модели (помните, что это упрощённое объяснение и оно верно не на 100%).
Проблема в том, что некоторые приложения считают, что зелёный канал должен показывать модель как освещённую снизу, а другие считают, что он должен показывать модель как освещённую сверху. Иногда это называют «правостороннесть карты нормалей» (normal map right-handiness):
- OpenGL-приложения (правосторонние, положительный зелёный канал): Blender, Maya, Modo, Toolbag, Unity.
- DirectX-приложения (левосторонние, отрицательный зелёный канал): 3DStudio Max, CryEngine, Source Engine, Unreal Engine.
- Substance Painter может работать с обоими типами и экспортировать оба типа карт нормалей.
Проблема: некоторые части кажутся плоскими/в них отсутствуют какие-то детали
Представьте, что при запекании карт нормалей программа запекания испускает лучи из поверхности lowpoly-модели, следуя по нормалям lowpoly, пока лучи не пересекутся с highpoly-моделью и не повернутся. После этого программа запекания берёт эту информацию и сохраняет её в карту нормалей.
Эти испущенные лучи не должны двигаться бесконечно, потому что могут столкнуться с далёкой частью highpoly и повернуться неправильно, поэтому программа запекания ограничивает дальность испускания лучей и иногда лучи могут останавливаться прежде, чем успеют пересечься с highpoly. В таком случае мы теряем детали и карта нормалей имеет области плоского цвета.
Решение: зависит от того, как программа запекания позволяет управлять расстоянием запекания:
- Некоторые программы ищут детали только снаружи lowpoly и игнорируют то, что находится «внутри» lowpoly-модели (однако большинство современных программ запекания выполняет поиск в обоих направлениях). В таком случае нужно модифицировать модели так, чтобы lowpoly полностью находилась внутри highpoly.
- Другие программы, например Max, используют клетку (cage) — «экструдированную» версию lowpoly, которую можно изменять для точного управления границами процесса запекания.
- Другие программы позволяют задавать расстояние запекания числом (в Substance Painter это max frontal/rear distance).
Проблема: карта нормалей имеет искажённые детали
Это очень типичная проблема. Такое происходит, когда нормали lowpoly неправильно соответствуют деталям highpoly, поэтому кажутся наклонёнными (на самом деле, если смотреть на них с направления нормалей вершин, они соответствуют идеально). Такое обычно происходит, когда некоторые грани образуют очень острый угол.
Решение: я более подробно писал об этой теме в другом туториале [перевод на Хабре], но в целом решения бывают такими:
- Сгладьте острый угол, добавив фаску (bevel).
- Преобразуйте ребро острого угла в резкое ребро (hard edge)/разделите грани на разные группы сглаживания (smoothing group).
- Используйте настраиваемые нормали (custom normals)/весовые нормали (weighted normals).
Проблема: карта нормалей выглядит пикселизированной или содержит полосы
Earthquake (AKA бог карт нормалей) написал очень хорошее объяснение этой проблемы.
Если lowpoly и highpoly очень похожи, то бОльшая часть карты нормалей будет иметь один базовый цвет карты нормалей, а другими цвета будут в местах отличия lowpoly от highpoly.
Если ситуация обратная: lowpoly и highpoly очень отличаются, то карта нормалей будет иметь гораздо большее разнообразие цветов и начнут возникать градиенты:
Такие плавные градиенты вызывают проблемы, потому что для их представления нужно множество цветов, а самые распространённые способы сжатия текстур основаны на снижении общего количества цветов.
При наличии плавных градиентов мы можем замечать на модели полосы, потому что изображение не имеет достаточного количества цветов для представления такого небольшого изменения цвета.
Проблема: на отдельных частях модели заметны пиксели
Очевидным решением будет увеличение UV-«острова» (island) этой части модели или использование более крупных текстур, но давайте рассмотрим и менее очевидные решения:
-
Запекайте с удвоенным разрешением карты нормалей, а затем уменьшайте размер изображения: если вы используете текстуру 512x512, то запекайте карту нормалей с разрешением 1024x1024, а затем преобразуйте изображение в 512x512. Благодаря этому каждый пиксель окончательной текстуры будет получать информацию от четырёх пикселей, создавая своего рода «сглаживание» (antialiasing) и снижая пикселизацию. Это также справедливо и для других запечённых изображений; кроме того, стоит сохранять версии текстур высокого разрешения на случай, если позже вам захочется увеличить детали в некоторых областях.
При применении к модели симметрии направления нормалей могут измениться из-за того, что изменился способ соединения граней. Иногда это означает, что можно получить шов прямо по центру модели. Чтобы избежать этого, сделайте так, чтобы нормали lowpoly в самом центре были выровнены, и при необходимости настройте сглаживание.
Ещё одна возможная причина — триангуляция: при импорте моделей в игровой движок они всегда триангулируются и иногда этот процесс может изменить нормали lowpoly, а по диагоналям граней lowpoly могут появиться артефакты. Чтобы избежать этого, триангулируйте модель перед запеканием, запеките карту нормалей, а затем примените модификатор симметрии.
Кроме того, вы можете изучить небольшой туториал Earthquake, который помог мне немного больше понять нормали вершин и карты нормалей.
Дополнительную информацию о картах нормалей можно узнать из wiki сайта Polycount.
Альфа-канал играет немаловажную роль при создании текстур. В нём используются только градации серого. Запомнить как он работает очень просто: белый - да, чёрный - нет, серый - так себе, в зависимости от светлости. Найти его можно, разумеется, в свитке каналов - Channels. Вот он, как раз, в самом низу, так и называется Alpha 1
Больше одного альфа-канала для игровых текстур оставлять не нужно.
Для диффузной карты альфа-канал используется только в том случае, если мы хотим сделать часть текстуры прозрачной. В этом случае чёрным закрашиваем то, что хотим отрезать, серым - что будет полупрозрачным (редко используется), белым - всё остальное.
Что касается карты свечения - glow map (маркер _g в конце имени файла) и карты глянца - environment mask (маркер _m в конце имени файла), то им альфа-канал не нужен вообще, они сами себе являются альфа-каналом. Тут тот же принцип: белый светится или отражает, чёрный - нет. Для карты свечения возможно использование цветов, но существует масса нюансов, поэтому опустим.
И, наконец, карта нормалей - normal map, в подавляющем большинстве, просто обязана иметь грамотный альфа-канал, в противном случае, модель будет выглядеть как маслом намазанная. Белый альфа-канал есть смысл оставить только для драгоценных камней, чистого нового стекла и жидкостей. Всё остальное приглушаем. Обычная ткань и неполированное дерево - почти чёрный цвет альфа-канала.
Ну, вот мы и подобрались к самому интересному
Карта нормалей
Сделать сиё чудо можно несколькими способами. Некоторые требуют хорошего навыка моделирования 3х-мерных объектов и нам сейчас не подходят. К счастью, есть плагин от славных людей из NVidia для создания карт нормалей из любого изображения. Есть ещё потрясающая программа
Применим к текстуре NormalMapFilter (Filter -> NVIDIA Tools -> NormalMapFilter):
В разделе Height Generation настраивается общее отображение будущей карты нормалей.
Пункт Wrap для безшовных текстур лучше выключить, иначе появятся швы на стыках, для одиночных текстур - всё равно. Все 3 пункта Invert делают то, что и написано, но мне ни разу не понадобились, поэтому я ничего не буду писать про них.
Путём выбора значения sample в подразделе Filter Type выбирается, собственно, детализация.
Как видите, самый чёткий результат мы получаем устанавливая значение sample 4.
В поле Scale настраивается высота рельефа. Для сравнения:
Главный недостаток NormalMapFilter в том, что он не умеет различать мелкие и крупные детали текстуры. Поэтому мы можем получить либо детализированную карту с небольшим рельефом, либо высокий рельеф без мелких деталей.
Выходов из этой ситуации несколько.
1. Отредактировать непосредственно изображение, сделав максимально контрастными крупные детали и минимально контрастными мелкие. Иногда этого не избежать, но для не очень сложных текстур есть ещё пара хитростей.
Приведу пример на сделанной на коленке простой текстуре:
Попробуем применить к ней NormalMapFilter со значениями 4 samples и 30 scale (я хочу получить достаточный контраст):
И уже видны косяки - чересчур рельефное дерево при недостаточном рельефе борозд и кнопки. К тому же, кнопка обрела на своей поверхности абсолютно ненужные детали. Единственный путь к вменяемой карте нормалей для этой текстуры я вижу в редактировании изображения. Я перевела все элементы текстуры в градации серого, изменила их контрастность и яркость и добавила тёмные ореолы кнопке и бороздам, в первом случае - кнопка слегка утоплена, во втором - смягчаю контур борозд:
Применила фильтр с теми же самыми настройками:
Уже больше похоже на правду.
Затем, дублируем слой, применяем фильтр Blur -> Gaussian Blur с небольшим значением (я выбрала 2) и назначаем слою тип смешивания Overlay. Повторяем процедуру: дублируем дублированный слой (тот, который уже размыт), Gaussian Blur (можно нажать Ctrl+F и последний фильтр применится сам с последними настройками); дублируем, размываем и так много раз. Вот что у меня получилось при 10и дублированных слоях:
И мелкие детали видны и рельеф на месте. Осталось завершить процесс. Объединяем все слои в один, применяем NormalMapFilter изменив Average RGB на Normalize Only и переводим изображение в 8 Bits/Chanel:
3. Дублируем слой Background с текстурой, на слой Background применяем NormalMapFilter со значениями: 9х9 samples, 20 scale, Average RGB ( *1 ). Затем, на сдублированный слой применяем тот же NormalMapFilter, но со значениями: 4 samples, 3 scale, Average RGB, дублируем его ( *2 ), сливаем все слои и применяем NormalMapFilter изменив Average RGB на Normalize Only ( *3 ).
Осталось сделать адекватный альфа-канал и карту нормалей можно считать готовой к употреблению.
В данном уроке будут затронуты важные темы, касающиеся текстурных карт: способы создания бесшовной текстуры, коррекция цвета, создание Albedo, Normal Map, Specular и других карт. Описание и скриншоты будут приведены только для Photoshop, но по аналогии можно создать текстуры в Gimp и других редакторах. Урок в большей степени рассчитан на новичков, но некоторые методы могут показаться интересными и профессионалам этого дела.
Этап 1. Поиск текстуры.
1. Откройте текстуру в Photoshop. Для удобства мы поменяем размеры текстуры с 6000х4000 до 3000х2000.
2. Во вкладке Слои дважды нажмите на фон. Нажмите ОК в появившемся окне. После этого, выделив данный слой, нажмите Ctrl+J для создания дубликата слоя.
3. Выделив нижний слой, перейдите в Фильтр > Размытие > Среднее. (Русифицированный Фотошоп, перевести на английский не составит никаких проблем).
4. Перейдя на верхний слой, выберите режим наложения: Линейный свет. Непрозрачность выставите на 50%. После этого перейдите в Фильтр > Другое > Цветовой контраст. Выставите значение радиуса: 160 пикселей. Все значения нужно подбирать под каждую текстуру.
5. Также перейдите в Изображение > Коррекция > Цветовой фон/Насыщенность. Добейтесь идеального результата.
Сравните две получившиеся текстуры.
Этап 2. Создание бесшовной текстуры.
Процесс создания бесшовной текстуры сводится к следующему: из существующего изображения выделяется тот участок, который наилучшим образом будет смотреться при тайлинге. После этого при помощи сдвига выявляются все швы текстуры. И последнее - с использованием Штампа или Заполнения с учётом содержимого (Выделение + Shift+F5) удаляются швы.
1. Открываем текстуру в Photoshop. В нашем случае применим инструмент Кадрирование перспективы. Также сразу стоит почистить текстуру от ненужных элементов с помощью Штампа, как показано на картинке.
2. С помощью рамки выделите участок текстуры. По краям оставьте "пробел" между камнями.
3. Зайдите в Фильтр > Другое > Сдвиг. Сдвиньте текстуру на 1/2 по вертикали и горизонтали (ровно половина пикселей по ширине и высоте изображения)
4. Чтобы устранить появившиеся швы, используйте 2 инструмента: Штамп и Заполнить с учетом содержимого. Последнее не всегда помогает, всё зависит от самой текстуры. Инструмент штамп копирует выделенную область (Зажмите Alt и нажмите на нужный участок).
5. Посмотрите полученный результат.
Этап 3. Создание текстуры Albedo в 4 шага.
Альбедо - это текстура, которая содержит независимую информацию о цвете. Чтобы добиться правильного результата, нужно избавиться от теней на изображении. А сделать это очень просто:
1. Откройте бесшовную текстуру, полученную с предыдущего этапа. Дважды нажмите на слой фона, создайте Новый слой. Нажмите Ctrl+J для создания дубликата.
2. Выбрав верхний слой, используйте сочетание клавиш Ctrl+Shift+U для обесцвечивания изображения. Нажмите Ctrl+I для инвертирования цвета. Должно получиться следующее:
3. В параметрах наложения укажите Мягкий свет. Поиграйтесь с бегунком непрозрачности, если на выходе получилось слишком серое изображение.
4. Сравните два изображения. (На итоговом изображении осталось 2-3 темных участка, чего у вас получиться не должно)
Этап 4. Простой способ создания текстуры Specular.
1. Перейдите в Изображение > Коррекция > Цветовой тон/Насыщенность (Сtrl+U), выставите значение Насыщенности = -100.
2. Нажмите сочетание клавиш Ctrl+I для инвертирования цвета.
3. Перейдите в Изображение > Коррекция > Уровни. Настройте значения таким образом, чтобы темные области стали четкими и был виден явный переход между черными и белыми точками.
4. Настройте резкость текстуры, перейдя в Фильтр > Усиление Резкости > Умная резкость. Подберите нужные значения для необходимого результата.
Этап 5. Создание Normal Map.
На данный момент существует огромное количество софта, с помощью которого можно создать карту нормалей. Вот только малая часть: Quixel Suite, PixPlant, CrazyBump, AwesomeBump... Также можно скачать плагин Normal Map Filter для фотошопа отсюда.
После установки в папку с программой он будет доступен в Фильтр > Nvidia Tools > Normal Map Filter. Параметр Scale задаёт масштаб по высоте. Параметр Filter Type отвечает за детализированность.
Если вы знаете другие способы создания текстурных карт, то оставьте комментарий ниже. Или напишите в группу ВКонтакте.
Редакция Devgam
Благодарим наших читателей и подписчиков за проявленный интерес. Поделитесь постом в социальных сетях.
Читайте также: