Как сделать маску unity
Как сделать многоуровневую игру в Unity? Или игру, в которой игрок может перемещаться (телепортировать) между локациями?
Один из наиболее частых вариантов реализации заключается в создании для каждого уровня игры отдельной сцены. Итак, алгоритм создания такой игры следующий.
Шаг 1. Создать сцены для каждого уровня и пр. составляющих игры. Продумать понятную и гибкую систему идентификации файлов сцен
Например, сцены могут иметь следующие имена:
- StartScene – стартовая сцена игры. Это может быть сцена, в которой игрок знакомится с правилами игры, может изменить некоторые начальные настройки, выбрать персонажа и т.д.
- Layer1,Layer2,Layer3, … — сцены, соответствующие 1-му, 2-му, 3-му и т.д. уровням игры.
- EndGame – конечная сцена, которая загружается в финале игры.
Шаг 2. Продумать геймплей так, чтобы было понятно, когда завершается текущий уровень и при каких условиях может быть загружена сцена для следующего уровня или завершения игры
Например, следующий уровень может загружаться при следующих возможных условиях:
а) игрок набрал определённое количество баллов. Это условие имеет смысл проверять каждый кадр в методе Update();
б) игрок добрался до определенного места в игре. Например, пришёл к заданной двери. Соответственно на объекте двери необходимо поставить коллайдер, и при входе в этот коллайдер должна будет выполняться загрузка сцены;
Family Island — меню выбора островов для путешествий и приключений
Когда речь идёт не столько об уровнях игры, сколько о разных локациях, между которыми игрок имеет возможность перемещаться. Пример такой игры – Family Island – там игрок может путешествовать на различные острова.
Candy Crush Saga — карта игры с выбором уровней
Второй вариант геймплея с аналогичным функционалом – наличие в реализации отдельной сцены с картой игры. Кликая по определённым зонам-кнопкам этой игры, игрок загружает соответствующий уровень (при условии, что этот уровень для него открыт). Наиболее популярный пример такой игры – Candy Crush Saga и ей подобные.
Шаг 3. Написание функции (метода) загрузки соответствующей сцены.
Для загрузки сцен в движке Unity предусмотрен метод LoadScene (…) из класса SceneManager пространства имён UnityEngine.SceneManagement.
Это значит, что в классе (скрипте), в котором будет выполняться загрузка сцены с помощью указанного метода, должна быть прописана директива:
Далее, при вызове метода следует указывать и имя класса:
У данного метода есть несколько перегрузок (вариантов вызова с различными наборами параметров), подробнее о которых можно почитать в официальной документации Unity.
Наиболее простые способы вызова метода следующие.
Вариант 1 – с явным указанием имени загружаемой сцены в качестве параметра. Например:
Вариант 2 – с указанием индекса загружаемой сцены в качестве параметра. Например:
Индекс – это число-порядковый номер сцены, который автоматически присваивается в окне настроек Build Settings:
Окно настроек Build Settings
Один из возможных вариантов скрипта следующий:
Этот скрипт должен быть на объектах-дверях или телепортах. На них же должен стоять коллайдер-триггер.
Шаг 4. Заполнить раздел Scenes In Build в окне настроек Build Settings, внеся туда все сцены, которые необходимо будет загружать
Пример этого окна представлен выше. Чтобы его вызвать, используется главное меню, пункты File -> Build Settings...
Меню File -> Build Settings… Unity
Вышло обновление с 2D-фичами к движку Unity. Релиз носит экспериментальный характер. Об этом стало известно из официального блога Unity.
Обновление называется 2D Experimental Preview и включает 6 фичей.
9-Slice Sprites — инструмент, который позволяет масштабировать, растягивать и повторять одно и то же изображение без подготовки специальных ассетов. По замыслу авторов, фича поможет быстро создать, например, фон для игры.
Пример использования 9-Slice Sprites
Outline Editor — дополнение к редактору спрайтов (Sprite Editor). Позволяет автоматически выделять спрайты. Плюс, позволяет вручную изменять меш спрайта.
Пример использования Outline Editor
Sorting Group — дает возможность отдельно рендерить объекты, которые находятся на одном и том же слое (Sorting Layer).
Пример использования Sorting Group
Sprite Mask — позволяет накладывать на спрайты и сеты спрайтов общие маски (Global Masks), которые применяются на всю сцену, и маски для видимых объектов (Scoped Masks).
Пример использования Sprite Mask
Пример использования CapsuleCollider2D
Tile Map — фича для работы с группами тайлов. Ключевая особенность этой фичи — технология Tile Asset, которая позволяет прикреплять к тайлам префабы (особый тип ассетов, позволяющий хранить весь GameObject со всеми компонентами и значениями) и программируемые тайлы.
Пример использования Tile Map
Ваши уроки просто прекрасны! Можете посоветовать какую-нибудь документацию по описанию функций?
Anton Baidzionak
Спасибо за урок. Очень помогло. Делал через Амплифай, но там тоже всё это настраивается и тоже работает.
Дмитрий Bald Panther
очень полезная информация. спс
DeepBunnyHole
Как сделать подобное в HDRP проекте на объектах HDRPLit?
Василий Потапов
С шейдерами ещё не работал, но после таких видео прям вдохновение ловишь, спасибо
Denis Sv9zIsT
Супер полезная инфа!
что то я смотрю у тебя райдер синтаксис как то лучше подсвечивает шейдеров чем у меня, и интеллисинс в шейдере как будто не работает(((
плагин какой то или как)?
PaViGa
Такие каналы на вес золота. Жаль их очень тяжело найти. Спасибо!
Govda Mikhaylo
Большущее спасибо очень долго это искал)
Alex Straga
Хм. Я правильно понимаю что можно делать "дырки" в стене просвечивающие в месте пересечения? Если да, то нечто такое мне и нужно)
Правда остается проблема как дорисовать в стене стенки в месте нового "окна")
Only Mediator
Как я понял можно так проверить что один объект полностью перекрыт другим. И передать информацию в скрипт или получить из шэйдора скриптом?
Gregory Radovilskiy
Спасибо огромное! Есть у меня один ассет в котором таким или подобным образом некоторые объекты сцены отображаются, но так как в шейдерах я ничего не понимаю, никак не мог разобраться. Надо только проверить теперь так же ли в моем ассете эта задача решена.
Slava Lopalo
Лучше не использовать альфа смешивание, если нужно только записать в стенсил буфер.
И для этого не обязательно писать шейдер
Так красивше будет:
Pass
<
ColorMask 0
Stencil
<
Ref 1
Comp always
Pass replace
>
Vsevolod Metelsky
Отличное видео, спасибо.
Dmitry Timofeev
В кнопки UI модельки вписывали. Красатулички всякие.
Artem Rynkovoy
монументально полезная информация. ТУт ни прибавить ни убавить.Причем доступно.
Unity Navigator
Taras Klymenko
Недавно хотел сделать Маску для UI ,
Invert/Reverse Mask, потому что стандартная маска работает только на reverse, подойдет ли этот шейдер под UI?
Академические пейперы с кучей заумных формул никогда мне особо не давались, так что после пары прочтений я мало что понял. Общие принципы были понятны: каждый кадр генерируется карта высот с помощью Fast Fourier Transform, которая, как функция от времени, плавно меняет свою форму формируя реалистичную водную поверхность. Но как и что считать я не знал. Я потихоньку вникал в премудрости просчета FFT на шейдерах в D3D9, и мне в этом очень помог исходник со статьей где-то в дебрях интернета, который я битый час пытался отыскать, но безуспешно (к сожалению). Первый результат был получен (страшный как ядерная война):
Стартовые успехи порадовали, и начался перенос воды на Unity с его доработкой.
К воде в игре про морские битвы выдвигались несколько требований:
- Реалистичный внешний вид. Красивые как близкие так и дальние ракурсы, динамическая пена, скаттеринг и т. д.
- Поддержка различных погодных условий: штиль, шторм и промежуточные состояния. Смена времени суток.
- Физика плавучести кораблей по симулированной поверхности, плавучие объекты.
- Так как игра мультиплеерная, вода должна быть у всех участников боя одинаковая.
- Рисование по поверхности: нарисованные зоны полета ядер залпа, пена от попаданий ядер в воду.
Первый тип для тех квадов, которые не являются переходными на более низкую детализацию. Ни одна из сторон не имеет уменьшенное в 2 раза количество вершин. Второй тип для граничных, но не угловых квадов. Третий тип — угловые граничные квады. Финальный меш для воды строится поворотом и масштабированием этих трех видов мешей.
Вот так выглядит рендер с подсветкой разным цветом LOD уровней воды.
На первых кадрах видно соединение двух различных уровней детализации.
Видео как кадр заполняется водяными квадами:
Напомню, это все было давно (и неправда). Сейчас более оптимально и гибко можно сделать сразу на GPU (GPU Pro 5. Quadtrees on the GPU). И рисовать будет в один draw call, и тесселяцией можно поднять детализацию.
Позднее проект переехал на D3D11, но до апгрейда этой части рендера океана руки так и не дошли.
Одной анимированной текстурки мало. Виден тайлинг, недостаточно деталей на ближних планах. Берем описанный алгоритм и делаем не одну, а 3 fft-generated текстуры. Первая — крупные волны. Она задает основную форму волны и используется для физики. Вторая — средние волны. Ну и напоследок самые мелкие. 3 FFT генератора (4-й вариант это финальный микс):
Параметры слоев задаются независимо друг от друга, и полученные текстуры смешиваются в шейдере воды в финальную форму волны. Параллельно со смещениями генерируются и карты нормалей каждого слоя.
Так как необходимо было сделать не только красивую картинку, но и реалистичное поведение кораблей. А также учитывая то, что в игре должно присутствовать штормовое море (крупные волны), то еще одной задачей, которую требовалось решить, являлось обеспечение плавучести объектов на поверхности сгенерированного моря. Сперва я попытался сделать GPU readback текстуры волны. Но, так как быстро выяснилось, что всю физику морского боя необходимо делать на сервере, то и море, а точнее первый его слой который задает форму волны, необходимо считать также и на сервере (а на нем, скорее всего, нет быстрого и/или совместимого GPU), то было принято решение написать полную функциональную копию GPU FFT генератора, на CPU в виде native C++ плагина к Unity. Сам FFT алгоритм я не реализовывал и использовал готовый в библиотеке Intel Performance Primitives (IPP). А вот всю обвязку и постпроцессинг результатов был выполнен мной, с последующей оптимизацией на SSE и распараллеливанием по потокам. Сюда входила и подготовка массива данных для FFT каждый кадр, и финальное преобразование посчитанных значений в wave offset map.
Была еще одна интересная особенность алгоритма, которая исходила из требований к физике воды. Нужна была функция быстрого получения высоты волны в данной точке мира. Логично, ведь это и есть основа построения плавучести любого объекта. Но, так как на выходе FFT процессора у нас получалается offsetmap, а не heightmap, то обычная выборка из текстуры не давала нам высоту волны там где было необходимо. Для простоты рассмотрим 2D вариант:
Для формирования волны, тексели (текстурные элементы, показанные вертикальными линиями) содержат вектор (стрелки) который задает смещение вертекса плоского меша (синие точки) в направлении его финальной позиции (острие стрелки). Предположим мы возьмем эти данные и попробуем извлечь из нее высоту воды в интересующей нас точке. Например, нам надо узнать высоту в точке hB. Если мы возьмем вектор в текселе tB, то мы получим смещение в точку около hC, что может сильно отличаться от того что нам нужно. Вариантов решения этой проблемы два: при каждом запросе высоты проверять множество соседних текселей, пока не найдем тот, который имеет смещение в интересующую нас позицию. В нашем примере мы найдем тексель tA как содержащий наиболее близкое смещение. Но такой подход не назовешь быстрым. Сканирование радиуса текселей непонятно какого размера (а от того, штормовое море или спокойное, смещения могут сильно варьироваться) может занять продолжительное время.
Вот так это выглядит, если сделать визуализацию смещений с помощью векторов (красные — большое смещение, зеленый — малое):
Далее все просто. Для корабля задается плоскость условной ватерлинии. На ней определяется прямоугольная сетка точек-проб, которая задает места приложения выталкивающих из воды сил для корабля. Затем для каждой точки проверяем, под водой она или нет, используя water heightmap, описанную выше. Если точка под водой, то прикладываем вертикальную силу вверх к physics hull корпуса в этой точке, масштабированной расстоянием от точки до водной поверхности. Если над водой, то ничего не делаем, гравитация сделает все для нас. На самом деле там формулы немного сложнее (вся для тонкого тюнига поведения корабля), но основной принцип такой. На видео визуализации плавучести ниже, синие кубы — это места расположения проб, а линии от них вниз — это величина выталкивающей из воды силы.
На клиентской стороне нам необходима информация о форме волны для просчета попаданий ядер в волну и проигрывания систем частиц и пены. Просчет повреждений происходит на сервере и там также необходимо корректно определять, попало ли ядро в воду (волна может закрывать корабль, особенно в штормах). Тут уже необходимо делать heightmap tracing по аналогии как это делается в parallax mapping либо SSAO эффектах.
На видео выше визуализация маски пены. Первый и второй слои. Я модифицирую параметры генератора и результат виден на текстуре.
И видео немножко коряво настроенного штормового моря. Тут хорошо видна форма волны, возможности генератора и пена:
- Маркеры, визуализации зоны разлета ядер.
- Рисование пены в месте попадания ядер в воду.
- Пенный след за кораблем
- Выдавливание воды под кораблем, чтобы убрать эффект заливания волнами палубы и затопленного трюма.
Очевидный базовый вариант — проективное текстурирование. Оно и было реализовано. Но тут появились дополнительные требования. Ближние виды — мыло из-за недостаточного разрешения (можно увеличивать, но не бесконечно), и хочется чтобы далеко было видно эти проективные рисунки на воде. Где решается такая же задача? Правильно, в тенях (shadow map). Как она там решается? Правильно, Cascaded (Parallel Split) Shadow Maps. Возьмем и мы эту технологию на вооружение и применим к нашей задаче. Разбиваем фрустум камеры на N (3–4 обычно) сабфрустумов. Для каждого строим описывающий прямоугольник в горизонтальной плоскости. Для каждого такого прямоугольника строим orthographic projection матрицу и рисуем все интересующие объекты для каждой из N таких ortho камер. Каждая такая камера рисует в отдельную текстуру, а затем, в шейдере океана, мы их комбинируем в одну цельную проективную картинку.
Вот я положил на море большущую плоскость с текстурой флагов:
Вот то что содержится в сплитах:
D3D11 очень сильно развязывает руки во многих моментах. После перехода на него и Unity 5 я сделал FFT генератор на сompute шейдерах. Визуально ничего не поменялось, но стало чуточку быстрее. Перевод просчет текстуры отражений с отдельного полноценного рендера камеры на технологию Screen Space Planar Reflections дал неплохой буст производительности. Про оптимизацию water surface objects я писал выше, а до перевода mesh’а на GPU Quadtree руки так и не дошли.
Многое, возможно, можно было сделать оптимальнее и проще. Например, не городить огороды с CPU симулятором, а просто запустить GPU вариант на сервере с WARP (программным) d3d девайсом. Массивы данных там не очень большие.
Ну, в общем как-то так. В то время, как разработка начиналось, все это было современно и круто. Сейчас уже местами подустарело. Появилось больше доступных материалов, даже есть похожий аналог на github: Crest. В большинстве игр, где есть моря, используется похожий подход.
Читайте также: