Вода: самый сложный шейдер в игре про лесоруба
В игре про лесоруба вода нужна по сюжету меньше всего: топор не тонет, бревно плывёт само. Но без ручья у пня сцена не лес, а огород. И вот тут начинается дороговизна: вода — единственный объект в лесу, который обязан быть одновременно зеркалом, линзой и пеной.
Почему вода такая дорогая
Обычный камень просто отражает свет по нормали. Вода же требует четырёх чудес одновременно:
- Отражение. Поверхность ручья показывает небо, берега, деревья. Честный способ — рендер сцены второй раз с зеркальной камеры. То есть каждый кадр удваивает расход на то, что игрок видит в полоске высотой 200 пикселей.
- Преломление. Бродя вброд, игрок видит дно смещённым. Это ещё один проход по сцене позади воды плюс искажение UV волной.
- Пена (foam). Вода у берега и на гребнях волн белит. Берётся из глубины (distance to shore) и высоты волны — обе величины надо где-то достать.
- Каустики. Зайчики света на дне. Настоящие — это фотонная карта, пересчитанная или запечённая.
Каждый пункт по отдельности — вечер работы. Вместе — неделя, и всё это ради того, чтобы игрок пробежал мимо.
Дешёвые подходы, которые работают
Хорошая новость: игрок смотрит под ноги, а не в поверхность ручья. Значит, можно врать смело:
- Planar reflection вместо кубической. Одна зеркальная камера, да и ту рендерим в половину разрешения и через кадр. Мозг игрока не заметит, глаз — тем более.
- Отражение неба — процедурное. Градиент + пара облаков из шейдера, никаких карт. Берега в отражении часто вообще не рисуют: под острым углом взгляда их скрывает маска Fresnel.
- Преломление — одной текстурной выборкой. Берём уже отрендеренный кадр экрана (grab pass), сдвигаем UV синусоидой. Дно «дрожит» — этого хватает.
- Foam без distance field. Высота волны из вершинного шейдера + мягкая граница по глубине воды. Две строки кода, 80% эффекта.
- Каустики — анимированная текстура. Одна запечённая карта шумов, проецируется на дно, крутится. Выглядит на 90% как настоящая, стоит 0%.
Чего нельзя экономить
Одно в воде принципиально: волна должна двигаться. Стоячая гладкая плоскость с отражением выглядит как лакированный пол. Вершинный шейдер с двумя наложением синусоид разной частоты — это 15 строк кода и половина правдоподобия всего озера. Свет, туман, каустики — всё это вторично; движение воды первично.
Второй необсуждаемый пункт — стык воды и берега. Именно там игрок меряет глазами: если пена не ложится на кочки и корни, магия рушится. Ради чистой линии foam я перерисовывал маску берега трижды и ещё раз проверил коллизию бревна: бревно должно всплывать ровно там, где пена.
В итоге вода в моей игре — это grab-pass, две синусоиды, градиент неба и запечённые каустики. Ни одного настоящего отражения. Лесоруб доволен: топор блестит, ручья журчит, FPS не просел. А шейдер воды я всё-таки допишу — однажды, когда надоест врать.
Комментарии (1)
Caustics проекцией на пол бассейна — гениально дёшево. Взял без стеснения.
Форма для гостей комментариев пока не принимается — писать можно автору (expeot@outlook.com) или через владельца блога. Все записи выше настоящие, никто их не модерирует молча.