Вода: самый сложный шейдер в игре про лесоруба

14 сен 2026 · 6 мин · 💬 1

В игре про лесоруба вода нужна по сюжету меньше всего: топор не тонет, бревно плывёт само. Но без ручья у пня сцена не лес, а огород. И вот тут начинается дороговизна: вода — единственный объект в лесу, который обязан быть одновременно зеркалом, линзой и пеной.

Почему вода такая дорогая

Обычный камень просто отражает свет по нормали. Вода же требует четырёх чудес одновременно:

  1. Отражение. Поверхность ручья показывает небо, берега, деревья. Честный способ — рендер сцены второй раз с зеркальной камеры. То есть каждый кадр удваивает расход на то, что игрок видит в полоске высотой 200 пикселей.
  2. Преломление. Бродя вброд, игрок видит дно смещённым. Это ещё один проход по сцене позади воды плюс искажение UV волной.
  3. Пена (foam). Вода у берега и на гребнях волн белит. Берётся из глубины (distance to shore) и высоты волны — обе величины надо где-то достать.
  4. Каустики. Зайчики света на дне. Настоящие — это фотонная карта, пересчитанная или запечённая.

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

Дешёвые подходы, которые работают

Хорошая новость: игрок смотрит под ноги, а не в поверхность ручья. Значит, можно врать смело:

  • Planar reflection вместо кубической. Одна зеркальная камера, да и ту рендерим в половину разрешения и через кадр. Мозг игрока не заметит, глаз — тем более.
  • Отражение неба — процедурное. Градиент + пара облаков из шейдера, никаких карт. Берега в отражении часто вообще не рисуют: под острым углом взгляда их скрывает маска Fresnel.
  • Преломление — одной текстурной выборкой. Берём уже отрендеренный кадр экрана (grab pass), сдвигаем UV синусоидой. Дно «дрожит» — этого хватает.
  • Foam без distance field. Высота волны из вершинного шейдера + мягкая граница по глубине воды. Две строки кода, 80% эффекта.
  • Каустики — анимированная текстура. Одна запечённая карта шумов, проецируется на дно, крутится. Выглядит на 90% как настоящая, стоит 0%.

Чего нельзя экономить

Одно в воде принципиально: волна должна двигаться. Стоячая гладкая плоскость с отражением выглядит как лакированный пол. Вершинный шейдер с двумя наложением синусоид разной частоты — это 15 строк кода и половина правдоподобия всего озера. Свет, туман, каустики — всё это вторично; движение воды первично.

Второй необсуждаемый пункт — стык воды и берега. Именно там игрок меряет глазами: если пена не ложится на кочки и корни, магия рушится. Ради чистой линии foam я перерисовывал маску берега трижды и ещё раз проверил коллизию бревна: бревно должно всплывать ровно там, где пена.

В итоге вода в моей игре — это grab-pass, две синусоиды, градиент неба и запечённые каустики. Ни одного настоящего отражения. Лесоруб доволен: топор блестит, ручья журчит, FPS не просел. А шейдер воды я всё-таки допишу — однажды, когда надоест врать.

Комментарии (1)

Форма для гостей комментариев пока не принимается — писать можно автору (expeot@outlook.com) или через владельца блога. Все записи выше настоящие, никто их не модерирует молча.