Шейдер для волос туториального персонажа из Vikings: War of Clans
Не так давно мы опубликовали материал о тестировании Unity Cloth на мобильных устройствах. В другой статье на render.ru рассказали о том, как арт-отделу Plarium Krasnodar удалось сделать модель персонажа с высокой детализацией и при этом не перегрузить проект. Теперь давайте поговорим о работе над шейдером и анимацией для волос этой модели.
ТЗ
Перед командой Graphic Development стояли следующие задачи:
-
определить допустимый уровень детализации геометрии;
-
устранить угловатость модели и текстуры;
-
создать реалистичный блик;
-
придать прическе подвижности.
Сначала мы решили определить требования к модели.
Детализация геометрии
Особых требований к детализации геометрии выявлено не было (как обычно — чем меньше вершин, тем лучше). Для замера производительности мы брали тестовый незаскиненный исходник и с помощью 3D-пакета с использованием модификаторов Smooth увеличивали детализацию.
|
Детализация |
PlayerLoop (ms) mediana |
|
1396 вертексов |
33.15 |
|
4423 вертексов |
33.2 |
|
15537 вертексов |
33.1 |
|
58003 вертексов |
33.2 |
Показания взяты с устройства Android Samsung Galaxy Tab S2
Устранение угловатости
С волосами персонажа была очевидная проблема: шейдер вместе с текстурой создавал жесткие концы, а анизотропный блик подчеркивал выступающие друг за другом полигоны волос.
Из этого стали понятны требования к текстуре и модели:
— полигоны прядей не должны пересекаться там, где виден блик, — так он будет красиво ходить по волосам, не подчеркивая угловатость;
— верхние слои прядей волос должны быть более детализированными, чем нижние, чтобы создавать общую форму и эффект подвижности.
Затем мы принялись за текстуру. Чтобы кончики волос смотрелись лучше, требовалась коррекция альфа-канала.
Здесь выбор стоял между двумя вариантами:
-
первый — использовать жесткую обрезку cutout-шейдером (т. е. фильтровать альфа-канал по пороговому значению, получая полностью прозрачный или непрозрачный пиксель, без промежуточных областей);
-
второй — использовать мягкий transparent-шейдер, который работает плавнее, но более требователен к железу.

Мягкий шейдер делал всего лишь одну дополнительную операцию — читку буфера кадра (для смешивания текущего пикселя волос с уже имеющейся на экране картинкой), за счет чего и достигался плавный уход в прозрачность. К тому же занимаемая экранная площадь прически нашего персонажа и количество наложений были невелики — так что особой разницы в ресурсозатратности между шейдерами в нашем случае не оказалось. Однако с мягким шейдером волосы смотрелись лучше.
Но тут была одна загвоздка — камера отрисовывала изображение в текстуру. Поэтому для того, чтобы оно корректно обрезалось по альфе и волосы отображались на текстуре, требовался дополнительный проход, который бы эту альфу создавал.
В итоге был написан шейдер, содержащий в себе три прохода. Первый записывает правильный силуэт прически в альфу текстуры, вместе с объемом волос и их правильной обрезкой на кончиках. Второй рисует cutout-геометрию, а третий (transparent) — добавляет мягкие кончики.
Реалистичный блик
Чтобы волосы выглядели живыми, они должны блестеть. Для достижения такого эффекта мы рассматривали два варианта: анизотропный динамический блик, реагирующий на освещение, и статичный фейковый, который мог бы облегчить обработку шейдера.
Для создания статичного блика мы использовали технологию текстурирования Matcap — имитацию материала и окружения с помощью всего одного изображения.

Эта технология позволяет натягивать предзапеченное в текстуре освещение на 3D-модель для имитации освещения (теней, бликов, оттенков и т. д.). То есть мы могли наложить поверх текстуры волос нарисованный блик так, как нам удобно. Форму блика можно настраивать, но он никак не будет реагировать на смену освещения.
Визуальная разница между анизотропным и фейковым бликами:


Разница в шейдерном коде при обработке анизотропного и фейкового бликов:
|
Anisotrophic |
Matcap |
|
fixed4 frag (v2f i) : SV_Target float HdotN = dot(halfDir, i.normal); float diffuseSpecular = lerp(1.0, specTex.g, _SpecularPower); |
v2f vert (appdata v) fixed4 frag (v2f i) : SV_Target |
Визуальная разница между анизотропным и фейковым бликами в рамках сцены, где появлялась девушка, была слабо различима, да и угол, под которым ее видел игрок, менялся не сильно. Но первый вариант генерировал больше математических операций, поэтому мы выбрали второй.
Чтобы блик смотрелся органично и не создавал плоского эффекта, решили применить маску. Сначала мы пробовали вариант с картой нормали, но позже заменили ее менее тяжелой альфа-маской, которая давала похожий эффект.

Применение альфа-маски в коде:
fixed specDetail = tex2D(_MatcapTex, i.uv).b;
specDetail = pow(specDetail, _MatcapPow);
matcapSpec = matcapSpec * specDetail;

Анимация и цветокоррекция
За основу мы взяли обычную костную анимацию для прядей. А для создания дополнительной динамики решили использовать шевеление в вертексном шейдере.
Для цветовой коррекции применили запеченное освещение в виде коэффициентов, которое называется SHA, или сферические гармоники. Такой метод рендеринга может создавать высокореалистичное затенение с относительно небольшими ресурсозатратами. Его основой служат предварительно рассчитанные коэффициенты, и он отлично подходит для рассеянного освещения от окружения (например, засветов от неба). Этот же принцип использовался не только для волос, но и для самой модели персонажа.

Исходники:
|
Детализация геометрии |
2500 |
|
Количество текстур |
3 |
|
Разрешение текстуры 1 |
512×512 |
|
Разрешение текстуры 2 |
256×256 |
|
Разрешение текстуры 3 |
128×128 |
Шейдер:
|
Количество проходов |
3 |
|
Количество текстурных читок |
1 проход: 3 читки, 2 проход: 3 читки, |
|
Количество математических операций в вертексном шейдере |
1 проход: 54 math, 2 проход: 51 math, |
|
Количество математических операций во фрагментном шейдере |
1 проход: 11 math, 2 проход: 17 math, |
В получившемся шейдере нет ничего революционного — техники, которые применялись для его создания, используются во многих других проектах. Но именно благодаря совокупности этих техник мы добились нужного результата.
Почему после курсов по нейросетям люди всё равно не умеют ими пользоваться?
Главные игры 2001 года, изменившие индустрию навсегда: 5 легендарных проектов 25-летней давности
Genshin Impact 7.0 откроет Снежную 12 августа
Компьютер или консоль: вечный спор, который не смогла разрешить даже Steam Machine
Как радикальное упрощение геймплея принесло миллионы создателям нестандартного шутера
Топ дьяблоидов 2026 года в ожидании релиза Path of Exile 2
Если ссылки схлопываются, значит, это кому-то нужно
Сборка ПК для GTA 6 в 2026 году: мощно и недорого