TGViewer
Prefire iOS Prefire iOS @prefire_ios · 980 subscribers
Post #51 1.38K
❄️Новогоднее настроение на Metal❄️

В предыдущем посте было про интерективные снежинки ❄️ на SwiftUI. А что на счет тех же снежинок но на более низком уровне? Да, делаем тоже самое но на языке Metal Shading Language (MSL).

Опустим настройку работы с Metal. Посмотреть как это сделать, можно в репозитории.


Для начала вспомним логику движения снежинок. Кстати, логику оставим внутри swift кода, а саму отрисовку вынесем на шейдер.
Каждая снежинка 1 раз в кадр изменяет свою позицию:

snowflake.position.y += snowflake.velocity.y


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

if snowflake.position.y > screenSize.y {
snowflake.position.y = 0
snowflare.position.x = Float.random(in: 0…screenSize.x)
}

Все так, логика максимально простая.

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

Разберем шейдеры по кусочкам.

Будем использовать два шейдера:
Вершинный шейдер - отвечает за позицию x.y нашей снежинки
Фрагментный шейдер - отвечает за цвет пикселей снежинки, мы вернем просто белый цвет

Нам нужно добавить всю информацию из swift кода в Metal код. Эта информация в структуре Snowflake.

struct Snowflake {
float2 position;
float size;
};

Дальше эту информацию нужно преобразовать в данные вершинного шейдера:

// Данные для позиции и размеры шейдера
struct VertexOut {
float4 position [[position]];
float pointSize [[point_size]];
};


// Шейдер вершин. Здесь происходит преобразование swift данных в данные шейдера
vertex VertexOut vertex_main(const device Snowflake *snowflakes [[buffer(0)]],
constant float2 &screenSize[[buffer(1)]],
uint vertexID [[vertex_id]]) {
// Здесь происходит преобразование координат из SwiftUI в координаты Metal
float2 position = convert_to_metal_coordinates(snowflakes[vertexID].position, screenSize);

VertexOut out;
out.position = float4(position, 0, 1);
out.pointSize = snowflakes[vertexID].size;
return out;
}

В конце остается фрагментый шейдер. В нем мы закругляем снежинку и возвращаем белый цвет:

fragment float4 fragment_main(VertexOut fragData [[stage_in]],
float2 pointCoord [[point_coord]]) {
// Закругляем снежинку
if (length(pointCoord - float2(0.5)) > 0.5) {
discard_fragment();
}

return float4(0, 0, 0, 0);
}


Готово, шейдер полностью написан, запускаем и видим пархающие снежинки ❄️❄️❄️

А бонусом, этот шейдер можно конвертировать под OpenGL, DirectX и в целом запускать почти везде. Далее попробую сделать такое же приложение под Windows.

☃️ Скачать можно через brew:
brew install --cask barredewe/cask/snowfall

PS: Если интересен более подробный обзор, то дайте знать в комментариях

#blog
  • 🔥 24
  • 🎄 5
  • ☃ 3
  • 😱 1
More from @prefire_ios
  1. Sep 16, 2026☺️ Prefire в требованиях к вакансиям Где-то месяц назад поставил ежедневную задачу на Chat…
  2. Sep 5, 2026🧭 Podlodka iOS Crew: разработка с AI С 14 по 18 сентября пройдет новый сезон Podlodka iOS…
  3. Aug 26, 2026Кажется, мой кот начал жить своей жизнью. Сначала друзья просто закинули Mewmori в несколь…
  4. Aug 18, 2026Нахождение текста котом Mewmori в уникальных приложениях Что бы кот видел, я снимаю скринш…
  5. Aug 17, 2026Начал готовить к релизу ScreenCat - 🐈 Mewmori - Переименовал проект в Mewmori (типо memor…
  6. Aug 5, 2026Сделал систему скинов для котиков 🐈 В ScreenCat уже много скинов, и я прям сильно устал р…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →