
Как чит рисует технику в War Thunder: проходы рендера и окраска по видимости
Подсветка техники выглядит как простая заливка цветом. На деле за один кадр отрисовка проходит три раза, и каждый проход решает свою задачу. Разберём, как это устроено и почему сделано именно так.
Что должно получиться
Хочется сразу трёх вещей: видеть силуэт машины сквозь дым и листву, отличать видимую часть от скрытой за укрытием, и при этом не получить плоское цветное пятно, по которому невозможно понять, куда эта машина повёрнута.
Три требования — три прохода.
Проход первый: глубина мира
Сначала рисуется то, что может закрыть технику: рельеф и строения. Рисуется без пиксельного шейдера вообще — нужна только глубина, цвет никуда не идёт. Это самый быстрый путь растеризации из существующих.
Строения приходят инстансами: одна геометрия, много матриц. Матрица инстанса подаётся вторым потоком вершин — три строки 3×4, перенос в w, ровно так, как их хранит движок игры. Тысяча одинаковых зданий стоит одного вызова отрисовки.
Глубина пишется в обратном Z: чем больше значение, тем ближе объект. Такая раскладка распределяет точность float заметно ровнее по дальности — на больших дистанциях это перестаёт быть теорией.
Проход второй: тела моделей
Теперь сама техника. Здесь пишется цвет, глубина и, попутно, бит трафарета группы: каждой группе подсветки выделяется один бит из восьми. Маска записи настроена так, что проход трогает только свой бит и не портит чужие.
Зачем бит: по нему третий проход поймёт, где проходит граница силуэта, — и не нужно ни рисовать модель второй раз увеличенной, ни держать отдельную текстуру под маску.
Отдельный случай — прозрачная заливка. Если видимый фрагмент нечем красить, его нужно выбросить: иначе он запишет глубину и вырежет собой модели, нарисованные следом. Но вместе с фрагментом пропал бы и бит трафарета, а обводка нужна и у прозрачной модели. Поэтому при прозрачной заливке силуэт собирается отдельным проходом — без цвета и без глубины, только трафарет.
Проход третий: обводка
Обводка считается один раз на весь кадр, сразу для всех восьми групп. Шейдер для каждого пикселя смотрит на соседей в радиусе заданной толщины: если у соседа бит группы стоит, а у центрального пикселя нет — центральный лежит на кромке силуэта и красится цветом этой группы.
Один проход вместо восьми — это разница между «работает» и «просаживает кадры», когда на экране полсотни машин.
Видно или не видно: тест по глубине
Самое полезное на практике. Второй проход для каждого пикселя сравнивает глубину модели с глубиной мира из первого прохода:
глубина модели < глубина мира − ε → пиксель скрыт
Эпсилон здесь не для красоты: без небольшого запаса общие грани начинают затенять сами себя, и по модели идёт рябь.
Ключевой момент: сравнение попиксельное, а не по машинам целиком. У одного и того же танка башня, торчащая из-за гребня, красится одним цветом, а корпус за гребнем — другим. Видно ровно то, что действительно видно, а граница между цветами показывает, где проходит укрытие.
Проход обводки читает обе глубины, поэтому и контур делится: скрытая часть силуэта получает свой цвет, а не теряется.
Откуда берётся объём
Плоская заливка превращает технику в цветной прямоугольник. Чтобы читались грани, нужна нормаль — а нормалей во входных данных нет.
Их и не нужно. Нормаль треугольника собирается прямо в пиксельном шейдере из экранных производных вектора взгляда: производная по x и по y дают два вектора в плоскости грани, их векторное произведение — нормаль. Она постоянна в пределах треугольника, отсюда характерный гранёный вид.
Двухтоновый градиент
Дальше нормаль идёт в тон:
fres = 1 − N·V
factor = saturate(0,30 · N.y + 0,25 + fres² · 0,65)
Первое слагаемое разводит верх и низ: обращённые вверх грани светлее. Второе — базовый сдвиг. Третье — френель: чем острее угол между нормалью и взглядом, тем ярче, отсюда свечение по кромке силуэта.
Готовый множитель смешивает два тона: нижний — базовый цвет, притушенный до 0,55, верхний — базовый цвет, подмешанный к белому на те же 0,55. Источников света в сцене нет вовсе, а объём читается.
Подложка: почему нужен предпроход глубины
Есть режим, где подсветка кладётся под уже нарисованное — модель проступает как подложка. Тут возникает тонкость: при таком смешивании итог в пикселе определяет первый же попавший фрагмент, а порядок деталей в модели произвольный. Без подготовки наружу вылезала бы внутренняя геометрия — катки сквозь борт.
Решение: сначала проход только по глубине, который оставляет ближайшую поверхность, и лишь затем цвет — по совпадению с этой глубиной. Заодно на предпроходе собирается силуэт для обводки.
Что это даёт
Попиксельная проверка видимости — это не украшение, а информация: сразу видно, простреливается цель или сидит за гребнем, и сколько её торчит наружу. Гранёная закраска сохраняет ракурс, то есть сразу понятно, каким бортом машина повёрнута и куда смотрит башня.
Цвета, толщина обводки и раздельные цвета для видимой и скрытой части настраиваются отдельно — см. описание чита для War Thunder. Как считается точка упреждения, разобрано в статье про расчёт упреждения.
Разборы по другим играм: баллистика в PUBG, скорость пули в Rust, сглаживание прицела в Apex Legends.