Как сделать мягкие тени в юнити

Добавил пользователь Владимир З.
Обновлено: 05.10.2024

Unity: Введение в шейдеры

Вы когда-нибудь задумывались о шейдерах в Unity? В этом уроке вы узнаете, что такое шейдеры, как отображать цвета вершин и как выполнять анимацию в шейдерах.

Unity оказывает большую помощь разработчикам игр, в том числе предлагает шейдеры, чтобы упростить создание сложных визуальных эффектов и анимации. Вы можете продвинуться довольно далеко, просто разбираясь со стандартными шейдерами, которые поставляются с Unity. Однако вы можете улучшить визуальные эффекты в своих проектах, написав собственные шейдеры.

В этом руководстве вы узнаете:

  • Что такое шейдеры.
  • Как отображать цвета вершин.
  • Как анимировать в шейдерах.

В примере проекта используется Unity 2019.3, хотя все, что описано в этом руководстве, должно работать и в более старых версиях.

Примечание. Это урок среднего уровня сложности, предполагающий, что вы уже знаете основы работы с Unity. Если вы новичок в Unity, начните с урока Введение в Unity: начало работы.

Что такое шейдеры?

Компьютерная графика, особенно 3D-графика, использует множество различных видов информации для построения визуальных элементов: сетки, текстуры, источники света и так далее. Эта информация передается графическому оборудованию, которое затем обрабатывает изображение и выводит его на экран.

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

Как компьютеры визуализируют графику

Понимание типов шейдеров

Технически, отдельный шейдер не выводит изображение целиком и не всегда выполняет рендеринг. Скорее, существуют разные типы шейдеров, которые делают разные вещи.

Основным типом является пиксельный шейдер, названный по той очевидной причине, что он выводит пиксель. Другой распространенный термин — это фрагментный шейдер, поскольку каждый пиксель является фрагментом полного изображения.

Фрагментные шейдеры выводят цвет одного пикселя, который вычисляется на основе положения этого пикселя на многоугольнике. Программа запускается снова и снова, в основном параллельно, для генерации всех пикселей всех полигонов, обрабатываемых этим шейдером. Действительно, возможность одновременной обработки большего количества пикселей является важной частью того, как видеокарты ускоряют графику.

Есть также вершинные шейдеры, которые вы используете для вычисления положения вершин на изображении. Хотя входные данные представлены в трех измерениях, компьютеру необходимо определить, где появляются вершины в двух измерениях, прежде чем он сможет отобразить пиксели.

Вы можете добиться некоторых интересных визуальных эффектов, манипулируя данными, выводимыми с помощью вершинных шейдеров, но мы не будем рассматривать это в уроке.

Вычислительные шейдеры на самом деле ничего не обрабатывают, а представляют собой просто программы, работающие на видеооборудовании. Эти шейдеры являются недавним нововведением — более старое видеооборудование может даже не поддерживать их.

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

Unity представляет еще один вид шейдеров — шейдер поверхности. Это шейдеры, которые выполняют расчеты освещения за вас, и вам нужно только написать код — помните, шейдер — это программа, — для обработки других свойств поверхности, таких как цвет и текстура.

Поверхностные шейдеры на самом деле являются фрагментными и вершинными шейдерами, но Unity генерирует код для обработки освещения. Это удобно, поскольку расчеты освещения очень сложны и часто стандартизируются для множества различных шейдеров.

И наконец, графические данные сообщают видеокарте, какой шейдер использовать с материалами. Когда вы будете изучать материалы, вы увидите меню вверху. Это меню выбирает, какой шейдер назначить материалу. Таким образом, когда графическое оборудование визуализирует многоугольник, оно запускает шейдер материала этого многоугольника.

Выбор из меню Shader окна Inspector в Unity

Хорошо, достаточно объяснений. Пришло время написать шейдеры!

Написание пользовательского шейдера

Если вы еще этого не сделали, откройте начальный проект, затем откройте RW / Scenes / SampleScene. Вы увидите заранее построенную сцену необитаемого острова с позиционированными моделями, которым назначены материалы.

Сцена песчанного острова в начале создания шейдеров в Unity

Существующая сцена не выглядит ужасной, но вы можете улучшить ее, по крайней мере, двумя способами: остров имеет твердые квадратные края, а вода полностью статична.

Вы можете решить обе проблемы с помощью пользовательских шейдеров. Однако, прежде чем решать эти проблемы, вам необходимо понять, как создавать шейдеры.

Для начала создайте ассет Surface Shader в папке Shaders, щелкнув правой кнопкой мыши и выбрав Create > Shader > Standard Surface Shader. Назовите его MyFirstShader.

Перейдите в папку Materials, выберите cartoon-sand и щелкните раскрывающийся список Shader в верхней части Inspector. Выберите Custom > MyFirstShader, чтобы переключить материал на этот шейдер.

Выбор MyFirstShader в качестве шейдера для песчанного материала в Unity

Пока что ничего особенного в сцене не изменится, потому что вы не изменили код шейдера по умолчанию. Тем не менее, материал песка на острове теперь использует ваш собственный шейдер, а не стандартный шейдер, встроенный в Unity.

Рассмотрение шаблона по умолчанию для настраиваемого шейдера

Дважды нажмите на ассет Shader, чтобы открыть его в редакторе кода, и изучите код.

Шейдер состоит из различных разделов внутри основного блока кода шейдера.

Весь код находится внутри блока шейдера в фигурных скобках с именем Custom/MyFirstShader. Эта запись просто сообщает Unity, что показывать при просмотре меню шейдеров материала. Глядя на разные блоки кода…

Properties

В блоке Properties вверху вы объявляете различные определяемые пользователем свойства. Это значения, которые вы можете редактировать в инспекторе при выборе материала.

Подробное рассмотрение одной строки: сначала вы видите имя переменной, используемое в коде. Затем в круглых скобках вы определяете имя, которое будет отображаться в инспекторе. Также в круглых скобках указывается тип свойства: цвет, двухмерная текстура или диапазон чисел. Наконец, после знака = вы присваиваете свойству значение по умолчанию.

Блок SubShader

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

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

Блок CGPROGRAM

Эти строчки кода декларируют несколько важных аспектов, которым нужно следовать. Во-первых, они указывают, что следующий код использует язык Cg. Для написания шейдеров существует несколько разных языков программирования. До этого момента все использовалось на языке Unity, ShaderLab.

surf — это название основной функции затенения, представленной ниже. Standard объявляет желаемую модель освещения — другие модели освещения включают Lambert и Blinn-Phong, но стандартное физическое освещение выглядит лучше всего. fullforwardshadows активирует динамические тени для этого шейдера.

Переменная свойства MainTex

Эта строчка объявляет переменную, соответствующую одному из свойств. Хотя это кажется немного избыточным, вы должны объявить здесь переменную, чтобы код Cg использовал это свойство.

Эти переменные могут быть одного из нескольких типов, включая sampler2D для изображения текстуры и fixed / half / float для чисел. Эти три числа являются числами возрастающей точности, и вы должны использовать наименьшую точность, которая работает.

Числовые значения могут иметь номер суффикса для создания вектора. Например, fixed4 обозначает четыре числа. Вы получаете доступ к значениям в векторе с помощью свойств .xyzw или .rgba.

Например, c.rgb в коде шейдера извлекает первые три числа из fixed4 , вызываемого c .

Вы должны объявить все свойства как переменные в коде Cg. Вы можете увидеть другие имена свойств чуть позже в уроке. Почему в коде шаблона Unity они написаны отдельно друг от друга, а не в один единый список, остается загадкой, но это также не имеет особого значения.

Вводные данные и переменные свойства

Этот блок кода объявляет структуру данных с именем Input и перечисляет в ней значения. Единственными входными значениями в коде шаблона являются UV-координаты основной текстуры, но есть несколько входных значений, к которым шейдеры могут получить доступ. Графические данные передадут объявленные здесь входные значения в шейдер.

Главная функция шейдера

Вы заметите, что структура вывода имеет такие параметры, как .Metallic и .Smoothness , которые вы устанавливаете с помощью свойств шейдера.

Единственная строка в surf , которая не является прямым присвоением номера входа выходному значению, — это fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color ; .

Unity предоставляет tex2D для поиска цвета в текстуре по заданной координате. При написании фрагментного шейдера необходимо явно включить библиотеку шейдеров Unity, но шейдеры поверхности включают библиотеку автоматически.

FallBack шейдер

После кода Cg вы объявляете резервный шейдер, хотя он и не требуется. Это указывает Unity использовать резервный шейдер, если графическое оборудование не может запускать какие-либо пользовательские субшейдеры, обычно потому, что это старая видеокарта, которая не поддерживает функции шейдера.

Хорошо, теперь, когда вы понимаете структуру кода шейдера, пора заняться визуальными настройками, указанными в начале кода шейдера.

Добавление цвета вершин в шейдер поверхности

Сейчас вы можете довольно четко видеть края сетки, но кажется, что настоящие пляжи переходят в цвет воды.

Есть много способов добиться этого в игре, но в одном простом подходе используется цвет вершин.

Координаты текстуры являются обычным дополнением, при этом координаты (обозначенные буквами UV вместо XY) предоставляют числа, которые вы используете при работе с текстурами. Что ж, цвет — это еще один вариант, предоставляющий числа, которые вы используете при расчете цветового вывода шейдера.

Например, если вы присвоите вершине красный цвет, то многоугольник, использующий эту вершину, будет иметь красный оттенок. Более того, если вершины многоугольника имеют разные цвета, то эти цвета интерполируются по граням многоугольника.

Цвета, интерполированные на грань треугольника

Этому островному мешу уже назначены цвета вершин, но вы не можете их видеть, потому что стандартный шейдер Unity не обрабатывает цвета вершин.

В частности, вершины под водой имеют более темный оттенок, а остальные вершины острова белые. Эти цвета создали бы приятный градиент по краю пляжа, если бы они были видны, поэтому ваша следующая задача — написать собственный шейдер, который обрабатывает цвет вершин.

Создание пользовательского шейдера для цвета вершин

Создайте новый шейдер поверхности и назовите его LitVertexColor. Установите материалу cartoon-sand этот шейдер как используемый, а затем откройте ресурс шейдера, чтобы отредактировать код.

Вам нужно всего лишь сделать два небольших дополнения для цвета вершины. Сначала добавьте в структуру Input следующий код:

Далее включите vcolor в расчет цвета, который происходит в surf :

И это все! Сохраните шейдер и вернитесь в сцену Unity. После компиляции шейдера вы увидите, как края острова сливаются под водой.

Сцена песчанного острова со смешанными краями

Анимация текстуры воды

Теперь песок выглядит намного привлекательнее! Между тем, вы обнаружили еще одну проблему, заключающуюся в том, что вода полностью статична.

Вы можете изменить это с помощью другого настраиваемого шейдера, хотя на этот раз вам не нужно освещение. Помните, что поверхностные шейдеры обрабатывают освещение за вас, поэтому на этот раз вы не будете создавать поверхностные шейдеры.

Создание неосвещенного шейдера

Вместо этого создайте Unlit Shader с помощью контекстного меню: Create > Shader > Unlit Shader.

Назовите новый ассет шейдер CartoonWater и откройте его в редакторе кода.

Первым делом обновите имя шейдера в самом верху.

Имя по умолчанию для этого шейдера — "Unlit / CartoonWater" . Изменение этого имени на "Custom / CartoonWater" упрощает поиск ваших пользовательских шейдеров в меню.

Затем добавьте некоторые дополнительные свойства для шейдера воды. Новый блок Properties должен выглядеть так:

По умолчанию Unlit Shader имеет только одно свойство текстуры _MainTex , поэтому вы добавили дополнительные свойства для управления как непрозрачностью воды, так и тем, как анимируется текстура поверхности.

Затем обновите раздел Tags и сразу после строки LOD 100 добавьте несколько новых параметров:

Теги по умолчанию предполагают непрозрачный материал, поэтому вы добавили и настроили некоторые флаги для поддержки прозрачности. В частности, обратите внимание, что отключение ZWrite означает, что вода не будет закрывать другие объекты в буфере глубины, в то время как вы устанавливаете Blend для использования альфа-значений.

Теперь обратите внимание на раздел CGPROGRAM с его набором директив pragma .

Поверхностные шейдеры получают эти библиотеки автоматически, когда вы генерируете их код, но вам необходимо явно включить их для вершинных и фрагментных шейдеров.

unity варит полезные инструменты шейдеров

UnityCG.cginc include в Unity содержит предопределенные переменные и вспомогательные функции.

Теперь взгляните на включенные структуры:

На этот раз есть две входные структуры вместо одной входной структуры для поверхностного шейдера. Вы вводите первую структуру в вершинный шейдер, который выводит вторую структуру. Эти выходные данные вершинного шейдера затем поступают на вход фрагментного шейдера.

Чуть ниже sampler2D _MainTex; В строке основного кода Cg добавьте следующие новые свойства:

Как и в предыдущем Surface Shader, вы должны объявить все свойства как переменные в Cg-коде. Вы будете использовать эти свойства, чтобы изменить текстуру и анимировать ее в основной функции шейдера.

Теперь в основной функции фрагмента шейдера, прямо вверху (над комментарием кода // sample the texture добавьте:

Эти две строки кода — основа анимированного водного эффекта. Этот код смещает UV-координаты, которые он получает, причем величина смещения изменяется со временем.

В результате получается волнообразная анимация текстуры. Между тем, обе строки кода делают по сути одно и то же, но в разных направлениях. Вы поймете и то, и другое, если подробно разберете одну строку.

Сначала код вызывает функцию тригонометрии, синус или косинус, так что значение будет меняться на повторяющейся волне. _AnimTiling масштабирует переданное число. Как следует из названия, _AnimTiling управляет мозаикой эффекта — в данном случае, воздействуя на частоту синусоидальной волны.

Затем вы добавляете время к переданному числу, заставляя возвращаемое значение перемещаться по синусоиде с течением времени. Код библиотеки из более раннего включает переменную, которая отслеживает время.

_Time — это вектор из четырех чисел, при этом четыре значения представляют собой время, масштабированное для удобства в различной степени. Вот почему в коде используется _Time.y , а не просто _Time ; y — второе число в векторе.

Наконец, вы умножаете все на _AnimScale , свойство, которое контролирует, насколько сильным будет эффект. Чем больше масштаб, тем больше волнистость.

Наконец, чуть выше return col; в строке кода функции frag добавьте:

Здесь код просто устанавливает альфа-значение для свойства _Opacity . Обязательно сделайте это после выборки текстуры; в противном случае текстура перезапишет альфа-значение.

Теперь, когда вы написали свой шейдер, вы можете назначить его материалу cartoon-water.

По умолчанию поверхность воды не будет анимирована в режиме просмотра Scene, но будет отображаться в режиме просмотра Game, когда вы нажмете Play.

Куда двигаться дальше?

Теперь вы знаете основы написания собственных шейдеров в Unity! Конечно, есть еще много чего, что стоит изучить, и хороший ресурс для изучения — это руководство по шейдерам Unity.

Помните ту удобную функцию шейдера, которую вы использовали ранее? Что ж, если вам интересно, какие вспомогательные функции доступны с этим включением, вы можете проверить их здесь.

Если вам интересно узнать о шейдерах с помощью Unity, ознакомьтесь с нашим другим руководством по Shader Graph в Unity здесь.

Надеюсь, вам понравился этот урок! Если у вас есть какие-либо вопросы, комментарии или предложения, не стесняйтесь оставлять их в комментариях.

Каков наилучший подход к реализации мягкой тени вокруг контура изображения UI Unity? Я хочу добиться эффекта ниже:

desired-soft-shadow

Мой текущий подход заключается в том, чтобы вручную добавить теневое изображение за основным изображением. Например, см. Ниже скриншоты:

button-with-soft-shadow

scene-heirarchy

shadow-inspector

Тем не менее, я нахожу этот подход утомительным и беспорядочным с точки зрения рабочего процесса, потому что я должен вручную добавить этот теней GameObject в свою иерархию GameObject каждый раз, когда я хочу добавить мягкую тень к UI Image.

Хотя я думаю, что можно немного улучшить этот текущий рабочий процесс, есть ли лучший подход?

Обратите внимание, что я также пробовал встроенный компонент эффекта "Тень" Unity:

built-in-drop-shadow

Это тень, а не мягкий теневой эффект, который я ищу.

Но я думаю, что этот подход показывает идеальный рабочий процесс, где он так же просто, как добавление теневого компонента в GameObject с изображением.

Приветствую всех друзья! В прошлой статье я рассказал о настройках экрана заставки в окне настроек проекта. Сегодня мы продолжим говорить о настройках проекта, и на очереди у нас вкладка качества.

Unity позволяет вам установить уровень графического качества, которую он визуализирует. Важно понимать, что более качественная визуализация влечет за собой снижение частоты кадров. Поэтому для мобильных устройств я советую понизить качество графики, так как игрокам вряд ли понравится красивая, но жутко тормозящая игра. Чтобы попасть в настройки качества графики перейдите по пути Edit/Project Settings и выберите вкладку Quality . Данная вкладка разделена на 2 блока: в верху отображается матрица качества, а под ней настройки для выбранного уровня качества.

Unity дает возможность именовать заданные настройки качества как вам захочется для удобства использования. Строки матрицы позволяют выбрать вам, к какой из различных платформ относится каждый уровень качества. Строка по умолчанию в нижней части матрицы не является уровнем качества сама по себе, а скорее устанавливает уровень качества по умолчанию, используемый для каждой платформы (зеленый флажок в столбце обозначает уровень, выбранный в данный момент для этой платформы). Unity поставляется с шестью предварительно включенными уровнями качества, но вы можете добавить свои собственные уровни.

Чтобы удалить нежелательный уровень качества, используйте значок мусорной корзины (самый правый столбец).

Чтобы выбрать уровень качества для редактирования, нажмите на его название в матрице. Его определения отображаются на панели под настройками, и вы можете изменить любые необходимые вам настройки:

Чтобы определить новый уровень качества, нажмите кнопку добавить уровень качества ( Add Quality Level ) и введите имя нового уровня в поле свойства Name .

Затем вы можете выбрать, какие из параметров качества, описанных в следующих разделах, необходимо обновить или установить:

Rendering.

  • Pixel Light Count – установите максимальное количество Pixel Light для прямого рендеринга ( Forward Rendering ).
  • Texture Quality - выберите, следует ли отображать текстуры с максимальным разрешением или с малой долей этого разрешения (более низкое разрешение имеет меньшие затраты на обработку).
  • AnisotropicTextures - выберите, если и как Unity использует анизотропные текстуры.
  • AntiAliasing - выберите уровень сглаживания, который использует Unity.
  • Soft Particles - включите эту опцию, чтобы использовать мягкое смешивание для частиц.
  • RealtimeReflectionProbes - включите этот параметр для обновления Reflection Probes во время игры.
  • Billboards Face CameraPosition - включите эту опцию для принудительного использования Billboards чтобы повернуть их лицом к камере во время рендеринга. Это дает лучшее, более реалистичное изображение, но более дорогое для визуализации.
  • ResolutionScalingFixedDPIFactor - уменьшает разрешение экрана устройства ниже его собственного разрешения.
  • Texture Streaming - включите эту опцию, чтобы использовать потоковую передачу текстур. Если вы не планируете использовать потоковую передачу текстур, отключите эту функцию, чтобы избежать каких-либо накладных расходов на процессор.
  1. Add All Cameras - включите этот флажок, чтобы сделать вычисление потоковых текстур в Unity ( calculate Texture Streaming ) для всех активных камер в проекте. Эта функция включена по умолчанию. Это самый быстрый способ перенести существующий проект в состояние потоковой передачи текстур. Если вы хотите исключить конкретную камеру, добавьте к ней компонент контроллера потоковой передачи ( StreamingController ), а затем отключите его. Если это свойство отключено, Unity вычисляет потоковую передачу текстур только для игровых объектов с помощью компонентов StreamingController . Используйте его для управления потоковой передачей текстур вручную.
  2. Memory Budget - установите общий объем памяти, который вы хотите назначить всем загруженным текстурам (в МБ). Когда емкость заполнена, Unity отбрасывает MIP -карты, которые он не использует,чтобы освободить место для тех, кто ему нужен. Бюджет памяти по умолчанию составляет 512 МБ. Потоковые текстуры выбирают самый маленький уровень MIP -Карты, чтобы попытаться достичь бюджета памяти. Unity всегда загружает не потоковые текстуры в полном разрешении, даже если это превышает бюджет. Бюджет памяти включает в себя не потоковые текстуры. Например, если ваш бюджет составляет 100 МБ и у вас есть 90 МБ непотоковых текстур, система потоковой передачи текстур пытается разместить все потоковые текстуры в оставшихся 10 МБ. Если это не удается, он загружает MIP -карты с более низким разрешением. Unity отдает приоритет максимальному снижению уровня по сравнению с бюджетом памяти. Система потоковой передачи текстур никогда не отбрасывает больше MIP -карт, чем максимальное уменьшение уровня, даже если отсутствие уменьшения приводит к тому, что объем памяти превышает бюджет потоковой передачи текстур.
  3. Renderers Per Frame - позволяет управлять накладными расходами на обработку ЦП для основного потока и связанных с ним заданий. Этот параметр равен 512 по умолчанию (то есть обработка 512 визуализаторов сетки на кадр). Более низкие значения сокращают время обработки, но увеличивают задержки при загрузке MIP -карт Unity.
  4. Max Level Reduction - установите максимальное количество MIP -карт, которые система потоковой передачи текстур может отбросить, если система потоковой передачи текстур достигнет бюджета памяти. Это значение по умолчанию равно 2 (что означает, что система отбрасывает не более двух MIP -карт). Система потоковой передачи текстур никогда не отбрасывает больше MIP -карт, чем это значение, даже если отсутствие сокращения приводит к тому, что объем памяти превышает бюджет потоковой передачи текстур. Это значение также является уровнем mipmap , который система потоковой передачи текстур изначально загружает при запуске. Например, когда это значение равно 2, Unity пропускает две самые высокие MIP -карты при первой загрузке.
  5. Max IO Requests - установите максимальное количество запросов ввода-вывода текстурных файлов из системы потоковой передачи текстур, которые активны в любой момент времени. По умолчанию это значение равно 1024. Это значение по умолчанию установлено достаточно высоко, чтобы предотвратить любую пробку в системе file IO за пределами того, что уже активно из-за конвейера асинхронной загрузки или самой файловой системы. Если содержание текстуры сцены изменяется значительно и быстро, система может попытаться загрузить больше текстурных MIP -карт, чем может поддерживать file IO . Снижение этого значения уменьшает пропускную способность ввода-вывода, генерируемую системой потоковой передачи текстур. Результатом является более быстрое реагирование на изменение требований mipmap .

Anti-aliasing.

Сглаживание улучшает внешний вид ребер полигонов, поэтому они не "зазубрены", а сглажены на экране. Однако он берет на себя затраты на производительность видеокарты и использует больше видеопамяти (хотя на ЦП это не влияет). Уровень сглаживания определяет, насколько гладкими являются ребра полигона (и сколько видеопамяти он потребляет).

Доброго времени суток всем. Сегодня речь пойдет о том, как сделать освещение в 2D игре, при использовании движка Unity3D. На самом деле тема не новая, можно даже сказать, что устаревшая. Но мы решили привнести в эту тему свое решение.

Это решение имело реальное применение в нашей игре DeepOnes

Техническое задание:

Реализовать подводное освещение для кораллов, главного игрока и других элементов уровня. Реализовать так, чтоб на игровой сцене были видны только подсвеченные объекты, а все, на что не попадает свет должно скрываться во тьме.

Когда перед нами стала задача сделать 2D освещения для DeepOnes мы обратился к уже существующим решениям. И спустя некоторое время мы имели в арсенале несколько подходов.

Давайте их рассмотрим по конкретней.

Решение с использованием SpotLight и затемнением материала спрайтов.

Если решение не подошло для наших задач, то это не значит, что оно не подойдет для Ваших. По этому, мы распишем как его реализовать.

  1. Создаем новый материал.
  2. Выставляем ему шейдер Sprites>Diffuse.
  3. Добавляем на сцену нужный вам спрайт.
  4. В компоненте Sprite Renderer выставляем в Material наш свежесозданный материал.
  5. Создаем SpotLight(модно и PointLight, но на него криво ставятся световые текстуры(light cookie).
  6. Выравниваем свет относительно нашего спрайта.
  7. В компоненте Transform>Position света значение Z ставим -10(ну или больше).
  8. Настраиваем цвет, интенсивность, длину света(если надо).

Результат которого можно добиться:

Такой результат нас не устраивал, поэтому двигаемся к следующему способу.

Использование плагина 2D Volumetric Lights

После недолгих поисков, мы наткнулись на вот этот плагин. Как мы можем заметить это уже новый уровень в реализации 2D освещения.

Конечно смотрится очень красиво. Плагин не сложен в использовании. Но при работе мы столкнулись с тем, что слишком много освещения на сцене заставляют проседать fps, а в 2d платформере это недопустимо. Так что оставим этот плагин на полочке симпатичных ассетов.

И наконец-то гвоздь программы - собственное решение

И так , что же мы использовали для реализации такого света.

  1. Создаем слой Light. Помечаем все объекты на которых должен быть источник света. Например, на персонаже это будет выглядеть именно так.
  1. 2 скрипта. Которые должны висеть на 2D камере.

SpritelightPostRffrct и LightController

Скрипт SpritelightPostRffrct отвечает непосредственно за освещение. Скрипт LightController отвечает за включение/выключение света на определенных уровнях.

Шейдеры в Unity: введение в тему от Cyanilux

Привет! Это небольшое введение в тему шейдеров, что это такое и как они используются при рендере графики в Unity.

Что такое меш?

Прежде чем перейти конкретно к шейдерам, важно сначала получить базовое представление о том, что такое меш.

Меш содержит данные для 3D-модели, состоящие из вершин и того, как те соединяются в треугольники. Каждый треугольник состоит из 3 вершин, но каждая вершина может быть общей для нескольких треугольников (поэтому количество вершин не всегда будет втрое больше, чем треугольников).

Даже такая, казалось бы, простая фигура, как куб, должна быть разбита на треугольники.

Пример кубического меша, состоящего из 12 треугольников. В Blender (ПО для 3D-моделирования) это 8 вершин, однако при импорте в Unity цифра может измениться в зависимости от того, являются ли данные для каждой вершины одинаковыми у общих вершин.

  • Положение в 3D пространстве (пространстве объектов, поэтому (0,0,0) стоит в начале меша).
  • UV, также известные как Текстурные Координаты, поскольку они чаще всего используются для наложения текстуры на модель. Обычно бывают координаты Vector2 (два значения с плавающей точкой, каждая ось помечена как xy или uv), но настоящие UV каналы могут быть Vector4 и содержать для передачи данных до 4 чисел с плавающей точкой. Смотрите Mesh.SetUVs.
  • Нормали (Направления, используемые для шейдинга. Некоторые программы моделирования (например, Blender) могут дополнительно использовать для определения порядка поворота вершин, который показывает в какую сторону смотрит грань. Во время рендеринга в шейдере можно отбросить переднюю или заднюю сторону грани).
  • Касательные (Направления перпендикулярные нормалям, которые огибают поверхность сетки вдоль горизонтальных координат текстуры (uv.x). Используются для построения Пространства Касательных, которое необходимо в таких разновидностях шейдинга как Normal/Bump Mapping)
  • Цвета вершин (Цвет, который задан каждой вершине).

Две вершины могут занимать одинаковое положение в 3D пространстве, но если не совпадают другие относящиеся к ним данные, в вершинных данных для них будет две отдельных записи.

Шейдеры в Unity обычно пишут так, чтобы было по возможности больше смежных вершин.

Пример кубических мешей. Оба имеют по 12 треугольников, но у левого 24 вершины, а у правого 8.

Достаточно распространено, когда модель имеет равномерное затенение (flat shading), а не плавное (smooth shading) как на изображении выше. Равномерное затенение увеличит количество вершин, потому что нормали вершин у разных граней должны указывать в разных направлениях. (Этого может не случиться в самой программе моделирования, но произойдет при экспорте в Unity). Для плавного затенения используется среднее значение направлений, поэтому вершины можно использовать как общие, при условии, что остальные данные также совпадают!

Что такое шейдер?

Вершинный шейдер запускается для каждой вершины в меше и отвечает за преобразование трехмерных положений вершин (в пространстве объектов) в положения пространства отсечения (Геометрия отсекает невидимые камерой части объектов. Есть несколько дополнительных шагов, чтобы превратить это в положение на 2D экране. Надеюсь, я восполню пробелы в одном из следующих постов). Также он должен передавать из меша данные, которые потребуются для вычислений на этапе фрагментного шейдера (UV, нормали и т.д.).

В таких инструментах, как Shader Graph, все это обычно делается за нас, но важно понимать, что здесь происходит два отдельных этапа. В новых версиях есть Master Stack, чтобы четче разделить эти этапы. Он предоставляет нам порт Vertex Position, чтобы переопределить положение в пространстве объектов, прежде чем оно будет преобразовано в пространство отсечения, например, для Vertex Displacement. Мы также можем переопределить нормали и касательные, которые передаются на этап фрагментного шейдера, но Shader Graph обработает порты автоматически, если оставить поля пустыми.

Для каждого треугольника и вершины в этом треугольнике положения пространства отсечения, переданные из стадии вершин, используются для создания фрагментов — потенциальных пикселей на 2D-экране. Все данные для каждой вершины, переданные во фрагментный шейдер, также интерполируются по треугольнику. Вот почему у каждой вершины может быть указан один цвет, но треугольник получится градиентно окрашенным. (То же самое происходит с UV, что позволяет правильно наложить текстуру, а не просто брать цвет как один пиксель для каждой вершины)

Треугольник с интерполированной раскраской.

В некоторых случаях бывает нужно отменить/отбросить пиксель из рендера (например, по alpha).

Код шейдера

Шейдеры в Unity написаны на HLSL (High Level Shading Language), хотя обычно вы увидите, что его называют CG. Особенно, если имеете дело со встроенным конвейером (Built-in Render Pipeline).

Вы всегда увидите этот шейдерный код между тегами CGPROGRAM / HLSLPROGRAM и ENDCG / ENDHLSL. (А еще можете увидеть CGINCLUDE / HLSLINCLUDE, который включает код в каждый проход шейдера).

Шейдеры для URP / HDRP всегда должны использовать HLSL-версии этих тегов, так как CG-теги включают некоторые дополнительные файлы, которые не нужны этим конвейерам. В противном случае это приведет к ошибке из-за переопределения в библиотеках шейдеров.

Технически Shaderlab имеет несколько устаревших способов создания шейдеров с фиксированными функциями, что означает отсутствие в надобности CG/HLSL PROGRAM, но я бы не стал беспокоиться об их изучении, поскольку программирование шейдеров намного полезнее.

В качестве альтернативы существуют редакторы шейдеров на основе нодов, такие как Shader Graph (официальный, доступен для URP или HDRP), Amplify Shader Editor (работает во всех конвейерах, но не бесплатный) и Shader Forge (больше не поддерживается, работает только в старых версиях Unity).

Проходы шейдера

Обычно шейдеры включают основной этап, который либо не имеет тега LightMode, либо использует один из таких тегов как UniversalForward (URP), ForwardBase (Built-in Pipeline) или Forward (HDRP), если шейдер предназначен для использования в прямом, а не в отложенном рендеринге (я немного объясню это в следующем разделе).

Читайте также: