sharpc (sharpc) wrote,
sharpc
sharpc

Categories:
  • Music:

Искусство обмана

Это немного причесанная версия моего рассказа по аське про особенности геймдева. Везде, где можно было соврать для красного словца, я так и делал :)

Мой коллега правил адский баг в сетевой игре Splinter Cell Conviction. Следует сделать небольшое отступление и рассказать, как сейчас пишутся все сетевые игры. Считают одно и то же детерминировано на разных машинах, подавая в движок на обоих ввод от обоих машин. Если в игре происходит лаг, то детерминировано откатывают движок на какое-то число шагов и подают снова все данные, как будто лага не было. В процессе игры, чтобы убедиться, что все считается, как положено и никто не читерит, считаются хэш-суммы от состояния мира и сравниваются. Если отличаются, происходит рассинхронизация, и игра прекращается.

В итоге и архитектура любой современной игры диктуется как раз сетевой частью. То есть, например, необходимо строгое разделение на ввод, интерпретацию ввода и движок, потому что интерпретация ввода пересылается по сети. Опять же, движок должен версионировать все объекты, чтобы иметь возможность откатиться, иначе возможна ситуация, когда присылает ему другой хост «я на 100500-м фрейме тебе в голову выстрелил», а тот уже 9000 фреймов посчитал без учета этого.

Так вот, в Conviction происходила рассинхронизация. И оказалось, что в геймплее в некоторых местах используется генератор случайных чисел. Если ГСЧ инициализирован одинаковым seedом, то он всегда выдает одну и ту же последовательность, следовательно, процесс детерминирован и рассинхронизации никогда не будет. Вот только на маке в качестве компилятора использовался gcc, а у него другой ГСЧ, который с тем же seedом выдает другую последовательность :) Пришлось совершить много магии, чтобы понять, как восстановить детерминизм во всех случаях.

Детерминизм должен работать на машинах с разными компиляторами, разными процессорами. Самое веселое начинается, когда double-арифметика чуть-чуть отличается. Это сложно не заметить, выскакивает, что хэши состояний движка не совпали и игре каюк, но очень сложно отладить. Поэтому из-за проблем с вещественными числами их часто моделируют fixed-point арифметикой, в предположении, что целые числа-то наверняка везде работают одинаково. Вот только корни и синусы считать в целых числах не очень удобно, так и появляются всякие fast inverse square root от Кармака :) Мы будто говорим, что нас не волнует, что это не совсем та функция, она близка и считается быстро и детерминировано. Особенно забавно, когда это что-то заметно нарушает, скажем, считаем мы какую-нибудь касательную, а она из-за этих хитрых псевдокорней вообще ничего не касается. Или синус чего-нибудь считаешь, а он больше 1 :)

Помимо этого есть алгоритмы компенсации причинности :) Допустим, игроку выстрелили в голову, пройдя через открытую на одном хосте дверь, при том, что на своем хосте он ее уже закрыл. И надо как-то это скомпенсировать. В чью-то пользу рассудить? В пользу выстрела? Оказывается, зависит от геймдизайна. Если игра киберспортивная, то в пользу сильнейшего игрока, если фановая, то в пользу слабейшего :) Известный геймдевелопер Борис Баткин рассказывал в блоге о разработке баскетбола: сильный игрок при честном ГСЧ очень быстро уходит в отрыв в счете, играть становится неинтересно. Подкрутили ГСЧ и сильные игроки стали жаловаться, что игра подыгрывает слабым. В итоге они сделали, наконец, модель такую, что игроки вроде чувствуют, что их где-то надурили, но где именно — понять не могут :)

У вас еще не возникло желания заняться геймдевом? :) Он такой весь неожиданный, ВНЕЗАПНЫЙ. Часто думаешь, что какая-то задача чисто техническая, смотришь — опа, а не получается, никак, не укладывается по времени или еще по чему, или по сети не получится такое передавать без лага. И вдруг понимаешь, что можно просто обмануть пользователя или сделать частью геймдизайна.

Вообще немного ирреальное ощущение создается, когда впервые смотришь на отрисовываемый уровень с отвязанной камерой. Бегаешь внутри — замечательно, все как настоящее! Отвязываешь камеру — опа, да этот дом просто нарисован на плоскости. Опа, от этого коридора, по которому я только что прошел, осталась только одна стеночка. Опа, здесь были кустики, а теперь только топорный лод. Фигасе, у этого камня нет обратной стороны, и правда, я ведь никогда не заходил за него. В рот мне ноги, этот великолепный водопад — три полигона со скролящейся текстурой. До сих пор помню свое удивление, когда увидел вайрфрейм очень красивой заставки конквикшна, где дымок так красиво вьется вокруг дырок от выстрелов. Я видел эти мелкие пляшущие пылинки и думал, ого, сколько же их тут. Оказалось, что это хитрым образом плясали 4 полигона с текстурой.


Я дом, я не хочу стоять на земле. Я хочу светить окнами верхних этажей на горизонте.

Меня поражало, как здорово сделано освещение. То есть не просто тупая тень, а место, куда меньше света отражается, темнее, что-то типа global illumination. Это ж изрядно надо рейтрейсить, чтобы такого добиться, думал я, а как вот они просекают это отражение от той стены? Оказалось, что это предрассчитанные текстуры global illumination и при реалтаймовом рендеринге ничего не считалось :) Или: обалдеть, как же классно пляшут блики огня на стене! Текстура :) Или: ого, как круто стенка дырявится от пуль. А это декали с параллакс мэппингом, да еще и наложенные по паттерну, а не туда, куда они на самом деле легли, ведь ты ж не успеваешь заметить, где именно летела пуля :)

Геймдев это искусство компромисса между наглостью обмана мешка с мясом и сложностью программирования. Думаешь, что этот враг настоящий и дьявольски умен и хитер? А у него раунд-робин из трех тупых действий. И ты бы, наверно, заметил это, если бы он перед этим в кинематографическом ролике не затулил какую-нибудь суровую штуку. Другими словами, происходит именно обман восприятия. Ты бы мог выявить алгоритм, если бы не был запутан другими составляющими игры. Вот еще забавный момент. Почему я считаю Кейт Арчер из NOLF1 намного более настоящей, чем в NOLF2, хотя в ней раз в 10 меньше полигонов? Потому что там постоянно есть вставки, где она общается с начальством и подкалывает его :)


Слева — настоящая Кейт!

А иногда ты допускаешь багу и тогда эффект становится вообще загадочным :) Скажем, ты начинаешь замечать обман! Он всегда тут был, так и задумано, но теперь ты его почему-то видишь. Самое жесткое, когда она не вылетает, и вроде все правильно, просто ты почему-то не был введен им в заблуждение. Смотришь на картинку и думаешь — что-то тут не то. А потом: вот оно что, тут же в том дальнем зеркале картинка перевернутая! Потому что в опенгле координаты от −1 до 1, а в директиксе от 0 до 1! Потому что на самом деле это не зеркало. Это сцена, отрендеренная в текстуру с точки зрения за зеркалом, и если текстуру наложить не с теми координатами, картинка будет перевернутая. Получается эдакий мир Зазеркалья, где все страньше и страньше. Оп — и в зеркале отражение перевернутое. Или НЕ ЗЕРКАЛЬНОЕ. Представь, подходишь ты к настоящему зеркалу и чувствуешь, что что-то не то :) А отражение-то не зеркальное :) Есть какая-то ошибка в коде, она не влияет на работоспособность, на логику, вообще ни на что не влияет. Просто обман становится чуть менее убедительным.

Самое стремное, конечно, это когда делаешь что-то, а все равно кажется, что получается плохо. Особенно это характерно для воды :) Как воду не сделай, если нет правдоподобного окружения, ты в нее не поверишь. Поставил в скайбокс какую-нибудь жатую-пережатую картинку — обалдеть, как настоящая! Аналогично с металлами. Глаза не верят в металлы, в которых ничего не отражается, поэтому на мечи накладывают сильно упрощенную текстуру с небом и землей, иначе же они выглядят пластиковыми. Трава тоже редкая жесть. Обычно это тупо биллборды с полупрозрачной текстурой, текстура для подальше и полигоны только для той травы, по которой топает герой. Потому что глаз определяет, брехня эта трава или нет, по тому, как она реагирует на его действия. Если ветер подул — неизвестно, как он подул, может именно так она и будет качаться. А если наступил, то трава должна примяться. Вот и получается 100500 полигонов на квадратный метр травы вокруг героя и 10 полигонов на всю остальную.


Угадай, где текстура, а где куча полигонов?

При первой встрече с внутренностями компьютерных игр часто происходит суровый культурный шок. Мы привыкли, что то, что мы видим, везде примерно одинаковое. Зайдем с другой стороны — оно не исчезнет. Травинка рядом такая же по размеру, как и травинка вдалеке, и если к ней подойдем — на ощупь будет такая же. Что на дереве уйма листиков. Что почти все предметы отражают свет, в том числе и на другие предметы. В играх все не так, и это плющит еще круче, чем «Матрица» вместе с «Тринадцатым этажом». Потому что это Реальность, созданная с минимальными затратами труда, исключительно для того, чтобы тебя обмануть.

Любое искусство заставляет нас верить во что-то выдуманное, скажем, исключительное впечатление оставляет история создания «Властелина Колец» (гигантские миниатюры, двигающиеся столы, две копии Хоббитона, MASSIVE), но именно в геймдеве конфликт между ограниченными способностями воздействия и реалистичностью обмана становится наиболее заметен. Я так думаю, что вампиры Уоттса не смогут заниматься геймдевом :))
Tags: игры, программирование
Subscribe
  • Post a new comment

    Error

    default userpic

    Your IP address will be recorded 

    When you submit the form an invisible reCAPTCHA check will be performed.
    You must follow the Privacy Policy and Google Terms of use.
  • 19 comments