Бесплатная реклама

Автор: Джон Кармак «Carmack»

Опубликовано: 27.03.2011

Изменено: 27.03.2011

Постоянная ссылка

Комментарии [4]

Выступление Джона Кармака на QuakeCon 2004


Перевод выступления Джона Кармака на конференции QuakeCon 2004, где он рассказывает как сделаны разные технические вещи в Doom и Quake 3, что вызывает недовольство и как планируется дальше развивавать игровые технологии id Software.



Страницы: 1 2

QuakeCon: http://www.quakecon.org

Я собираюсь поговорить большей частью о графических технологиях и рассмотреть движок Doom 3. Также я расскажу что буду делать в дальнейшем, и поговорю немного о звуке и других технологиях.

Итак, решения, которые я принял для рендерера Doom 3, были приняты около четырех лет назад и они оказались неплохими, потому что я интересуюсь развитием железа и тем, что мы могли сделать в игре с его помощью. Но сейчас время двигаться вперед и оценить сегодняшнее положение вещей с современным железом, и каким оно скорее всего будет через несколько лет и делать новый движок уже исходя их этих оценок.

John Carmack - QuakeCon 2004

Недостатки Doom 3

Итак, с точки зрения графики в Doom 3 есть несколько недостатков.

Видимые швы

Первый из наиболее очевидных - это швы на головах героев, там, где в текстуре применен повтор с отражением. Это не совсем проблема движка, мы должны просто взять и потратить дополнительную текстурную память и не иметь текстурных швов на хорошо видимых участках, но, возможно, я сделаю что-нибудь с расчетом векторов касательного пространства, что слегка поправит ситуацию.

Расчет спекуляра

Еще одна из вещей, которую люди обсуждают - это то, что цвет кожи не выглядит похожим на настоящий цвет кожи. Частично это можно объяснить тем, что у нас только один уровень отражения света (specularity). Есть только одно значение коэффициента, которое мы применяем ко всему. Мы можем сделать пятно спекуляра ярче или темнее, но мы не можем сделать пятно спекуляра меньше или больше.

В основном это результат того, что изначально движок делался на основе возможностей блоков объединения регистров (register combiners) железа класса NV10/NV20. С тем что может железо поколения DX9 и старше, то есть железо класса NV30/R300, вообще нет причин как-либо ограничивать себя в показателях степени спекуляра. Мы, как ни странно, не используем степени вообще, нет последовательности из косинусов, возведенных в степень, как обычно. В действительности в Doom используется что-то вроде вырезающей функции (windowed function), которая делает смещение и возведение в квадрат, это приемлемо работало на старом железе с фиксированной функцией и было на самом деле чуть проще контролировать, потому что при этом был очень ограниченный спад освещенности. Тогда как в теории классическое затенение Фонга с косинусом, возведенным в степень, не покрывает полностью спад и вы получаете небольшое сложение по всей области и это чуть лучше, чем полное разделение.

Фрагментная программа на самом деле использует ссылочную таблицу текстуры (texture lookup table) для степени спекуляра и я просто сделал эту текстуру такой, что она точно совпадает с тем, что вычислялось на старом железе с фиксированной функцией, но можно легко заменить эту текстуру на что угодно. Все, что я сделал в новых проходах рендерера - это сделал эту текстуру двумерной, таким образом вся выборка спекуляра происходит с дополнительной текстурой, которая содержит в себе коэффициент отраженного света (specularity factor). То, что мы называем картами спекуляра в Doom 3 более известно под названием "карты блеска" ("gloss maps"), где они действуют лишь на интенсивность пятна спекуляра.

Но мы теперь также добавили в новую технологию, возможность изменять ширину пятна спекуляра. Появляется много интересных возможностей... Пятно, которое у нас есть в Doom, широковато для обычного пятна спекуляра, оно похоже на то, что получается на тусклом пластике; не особенно блестит, широкое, распространяющееся в стороны. Не получается ничего, что бы выглядело как по-настоящему хорошее пятно на металле, или что-либо похожего на блестящий пластик. А теперь можно добиться интересных эффектов, если поиграть со всем этим. Можно сделать еще шире или сильно уже и получить яркое маленькое точечное пятно.

Еще одна вещь с отраженным светом - это то, что вы можете наблюдать в некоторых случаях в Doom, когда у вас есть очень широкая треугольная поверхность или широкая поверхность с очень небольшим числом полигонов.

Doom использует интерполяцию половинного угла для вычисления спекуляра, опять потому что это все было разумным делать на железе с фиксированной функцией давным-давно. Я предпочитаю использовать вычисление настоящего угла отражения, что не требует никаких нелинейных вычислений на вершинах.

Все это означает, что если вы берете действительно большую квадратную комнату в Doom и делаете дырку в ее середине, у вас получается такое забавное деление на треугольники, а потом, по мере вашего движения по кругу, по кругу будет двигаться и яркий свет вместе с пятном спекуляра, и форма пятна будет слегка меняться в зависимости от того, где оно находится на треугольной поверхности, хотя оно и не должно меняться, исходя из позиции смотрящего и положения источника света. Это еще одна довольно-таки простая проблема. Путем расчета векторов отражения, вы получите правильное пятно вне зависимости от того, каким образом было произведено деление на треугольники.

Еще одна небольшая проблема, которую можно встретить в Doom, опять на больших плоских поверхностях со спекуляром - спекуляр зернистый.

В основном это из-за использования кубических карт окружения (cubic environment maps) для нормализации. Если это заменить на вычисления, то опять, только при ARB2 проходе, вы получаете пятно лучшего качества, но все еще немного не то... там получается две нормализации. Одну из них я заменил вычислениями, вторая все еще делается через выборку из текстуры. То есть есть возможность для небольшого улучшения, можно опять заменить выборку из текстуры математическими вычислениями.

Одна из вещей, которую вы наверняка заметили практически на всем, что использует сейчас карты нормалей, это если у вас есть пятна спекуляров (и это становится особенно заметным, когда вы добавляете маленькие пятна спекуляров) на них есть алиасинг... обычно люди думают об алиасинге только применительно а краям полигонов, то есть, если у вас есть тонкая ограда, вы получаете очевидный зазубренный пиксельный край на фоне, который освещен иначе. Аппаратный антиалиасинг хорошо с этим справляется, но по мере того как мы делаем все более сложные вещи внутри поверхностей, проявляются новые виды алиасинга, все они типа "алиасинг внутри поверхности", завязанные на подсчет реальных текстурных координат.

В играх, которые работают с картами нормалей, вычисления иногда приводят к тому, что пятно спекуляра ложится на интерполированную точку между одной картой и другой. То есть одна грань может смотреть вверх, а другая от вас и вправо, и в зависимости от того, где находится наблюдатель и где находятся его глаза, в некоторых ситуациях на таких точках или между ними может получиться очень яркое пятно спекуляра. Но Doom этим особенно не страдает, потому что пятна спекуляров в целом очень широкие, но по мере уменьшения, это пятно становится большей проблемой. Получается, что небольшие движения приводят к билинейной интерполяции (или к трилинейной) на поверхности. Интерполяция нужна, чтобы сгенерировать нормали, которые либо приближаются, либо удаляются от той точки, где должно быть реальное пятно спекуляра, и это приводит к появлению небольших мерцающих пятнышек на поверхности по мере того, как происходит движение в окрестностях точного пятна спекуляра, соответствующего вектору отражения.

Над чем идет работа сейчас

Итак, это то, над чем я сейчас работаю, над различными подходами, которыми можно это побороть.

Улучшение спекуляра

Первое направление, которое я рассматриваю - это анализировать реальные нормали поверхности вместе с коэффициентом отраженного света и изначально расширить пятно спекуляра, чтобы больше геометрии поступало тому, что может быть покрыто ядром фильтра. И это кажется весьма многообещающим, и работает хорошо. Один из недостатков - приходится держать вместе карты спекуляров и карты нормалей, вы не можете взять одну поверхность и положить на нее другую карту нормалей, не имя на ней подходящей карты спекуляра, так что эти карты становятся чем-то вроде нескольких каналов более сложной структуры данных.

Это также лишает возможности масштабировать и вращать их независимо, потому что опять это выглядит как текстура из нескольких каналов. Мы работаем с этим следующим образом. Вы можете посмотреть на данную поверхность, она имеет карту нормалей, карту диффузного освещения, карту спекуляра, карту отраженного света, карту свечения, карту подповерхности и все такое прочее. Они вроде как отдельные карты, но если вы начинаете делать анализ на нескольких уровнях, они становятся больше похожи на 14 каналов или 16 каналов одной текстуры. Это один из небольших моментов, относительно которых я до конца не уверен, что именно я буду делать, чтобы улучшить это внутри движка.

Еще одна вещь, которая оказалась дешевым и эффективным способом повышения качества - это сделать ренормализацию карты нормалей перед тем как делать все вычисления освещения.

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

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

Переход к буферам теней

Самое большое изменение, которое скорее всего случится в движке следующего поколения - это переход к буферам теней (shadow buffers) вместо теневых объемов (shadow volumes). Это было одно из тех больших ключевых стратегических решений, которые должны были быть сделаны в движке Doom´а на ранних этапах. У меня была, давно еще, версия кода, которая ренедрила и буферы теней, и теневые объемы, чтобы я мог сравнивать их производительность и качество изображения.

В то время было много размышлений над тем, каким же путем следует идти. Некоторые думали, что буферы теней могли бы быть лучшим выбором. Много поработав над этим, теперь совершенно ясно, что общая архитектура рендеринга не была бы жизнеспособной с буферами теней во времена Doom´а, чтобы покрыть весь целевой рынок.

То, что я делаю сейчас это, не на 100% ясно еще, будет ли это жизнеспособно на машинах следующего поколения, но у меня есть основания на это надеяться. Мы просто должны получить некоторую помощь от производителей видеокарт по некоторым вопросам, чтобы прояснить моменты связанные с производительностью, настолько, насколько это возможно.

Проблемы с буферами теней таковы – когда я имел возможность протестировать их на начальных стадиях разработки Doom, без фрагментных программ и без железа с поддержкой буферов теней, что впервые появилось на GeForce3, системах класса NV20, можно было с помощью альфа теста и с других таких хаков делать сравнение с буфером теней, и можно было делать несколько слоев, чтобы обойти тот момент, что у вас только 8 битная точности глубины, можно было сделать движок, которые бы с этим работал, но это выглядело очень плохо.

Все жалуются на грубые края при использовании стенсильных теней, но способ, которым делались теневые объемы раньше, тоже давал грубые края, они даже не были прямыми, вы получали эти ужасные кривые пикселизованные края, которые выглядели очень, очень плохо, даже на довольно высоких разрешениях. Так что, когда я сел работать над новой технологией, я поразмыслил... Причины, побудившие делать буферы теней вместо теневых объемов - это то, что с теневыми объемами приходится делать много работы на CPU, что делает Doom очень CPU-зависимым, гораздо больше, чем мне бы хотелось. И получается, что вам нужно генерировать координаты для каждой анимации на CPU, потому что вам нужно сделать для нее теневые объемы. И вам нужно сделать все эти вычисления даже для статических объектов, на которые падает движущийся свет и, конечно, для объектов, движущихся мимо неподвижного света. Всегда надо определять силуэты теней, генерировать новые индексы и вершины. Doom пытается работать с этими вещами с помощью вертексных программ. У нас может быть статический список вершин для теней и нужно просто генерировать новые индексы, базируясь на них... Но это все еще важный момент. Мы потратили довольно много времени на работу с силуэтами. Что касается буферов теней в новых версиях, над которыми я работаю... Есть несколько вещей, которые изменились со времен изначальной спецификации Doom´а. Один из них - у нас теперь есть фрагментные программы, так что мы можем делать довольно сложную фильтрацию, и это оказалось ключевым моментом.

Даже если вы берете построенное на железе процентно близкое фильтрование (PCF - percentage closer filtering) и вы ренедерите карты теней неприлично большого разрешения (2000х2000 или больше), они все равно не выглядят хорошо. В целом, легко сделать их выглядящими гораздо хуже, чем стенсильные теневые объемы, когда вы делаете только начальный уровне фильтрации на железе. Вы получаете все эти проблемы со сдвигами и проблемы с пиксельной крупой и все это не очень-то и хорошо. Однако, когда вы начинаете добавлять случайное дрожание (randomized jitter) в самплы (достаточно взять не так уж и много сэмплов, чтобы все выглядело пристойно), это полностью меняет картину. 4 рандомизированных сэмпла, возможно, будут нашей отправной точкой спецификации нормального вида на выходное качество для следующей игры. Это выглядит весьма неплохо. Там есть немного... Если взглянуть на широкие мягкие тени, там возникает небольшое дрожание пикселов, когда объекты перемещаются вокруг, но при рандомизации это выглядит гораздо лучше, чем построенное статически. Это достаточно хороший уровень, и самая хорошая вещь это то, что потому что вычисление сэмплов теней совершенно отделено от других аспектов движка рендеринга, вы можете перемешивать столько сэмплов, сколько захотите. В моих текущих изысканиях у меня есть версия из 0 сэмплов, это аппаратный PCF, для сравнения. С одним случайно зашумленным сэмплом, с четырьмя сэмплами - это что-то вроде точки отсчета, и версия из 16 сэмплов, которая может дать вам очень хорошие, высококачественные мягкие тени. Я возможно перемешаю и побольше, например 25 или 64 сэмплов, что скорее всего будет использовано для рендеринга офлайн, если люди захотят что-либо отрендерить и они не будут против, чтобы это работало со скорость несколько кадров в секунду. Вы можете получить качество теневых эффектов как в кино, просто меняйте количество сэмплов, с которыми работаете. Это оказывается очень близко к тому алгоритму, который Пиксар использовал во многих мультфильмах, основанных на Рендермене, это уже работает на сегодняшних CPU в реальном времени при маленьком количестве самплов.

Это очень воодушевляет, потому что в дополнении к мягким теням, которые являются модным словечком, на которое люди ориентируются... Хорошо, у вас есть линия тени на полу, будет ли при этом четкая разница между поверхностью внутри света и поверхностью внутри тени или у вас там приятные гладкие переходы, сначала затемнение (umbra), а потом высветление (penumbra)?

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

Сейчас, в Doom´е много вещей, которые являются своего рода ограничениями того, что технология делает хорошо, над чем мы работаем и вы на самом деле их не замечаете, потому что мы хорошо над ними работаем. Одна из важных вещей это то, что если включено обычное затенение на поверхностях, которые сильно искривлены с помощью карты нормалей, например персонажи, и в меньшей степени это трубы и тому подобные, получается переход от четкого света в четкую тень на краю силуэта, где нормали изгибаются вокруг силуэта и все еще должны быть прямо освещены; это дает вам очень неприятные условия освещения. Иногда дизайнеры под это подстраиваются, делая умеренно яркий свет, так что тени не очень резкие, но мы хотели сделать освещение лучше. Практически для всех персонажей не выставлен флаг самозатенения, что является хаком, который мы делаем в стенисильных буферах теней. Так вот такие герои с такими установками не будут отбрасывать тени сами на себя, и у вас не получится неприятного затенения силуэта, но они все еще отбрасывают тени на все остальное в мире.

Есть еще несколько вещей, которое это портит... Эти установки не уникальны для каждого героя, там сделано нечто вроде разделения всех объектов на две группы, "нет самозатенения" и "глобальная тень". Так вот, объекты, которые не самозатеняются, не бросают тени и на другие такие объекты и вы можете иногда это заметить, когда два монстра стоят рядом друг с другом, свет падает сбоку, они оба отбрасывают тени на пол, но они оба не самозатенены и вы не увидите тени от одного монстра на другом монстре.

Это основная проблема, которая нам мешает сделать драматический крупный план на персонажах с самозатенением, и это было одно из основных ограничений, в остальном мы могли сделать поверхности с освещением очень высокого качества. Так вот, буферы теней решают это очень очень красиво, с ними у вас свет может падать прямо на героя, и даже без амбиентного света вы получите мягкий силуэт, это как раз то, что нам нужно.

Так другие вещи с мягкими тенями таковы... У меня это включено прямо сейчас в моем тестовом движке, я могу переключаться между старым рендерером Doom´а и новым рендерером. Данные там практически одни и те же. Мягки тени предлагаются как большая новая фича, но в большинстве случаев, когда вы идете по Doom´у, переключение между мягкими тенями и обычными грубыми тенями в Doom´е... Там есть не так уж и много моментов, где разница заметна.

Если вы просто переключаетесь между ними, кто-нибудь немного вдалеке от монитора даже не заметит этого если только это не тот момент, когда есть объекты с режимом "без самозатенения", на них появятся тени, это единственная вещь, которую вы действительно заметите, когда вы переключаетесь между ними. Там есть пара сцен, где если смотреть гораздо ближе, это выглядит действительно хорошо, там на всем хорошие мягкие тени, но большей частью большой разницы нет.

Частично это из-за того, что дизайнеры знают, что не надо располагать объекты таким образом, чтобы грубые тени выглядели плохо, так что у них будет больше творческой свободы. Но основной выигрыш из этого всего это правильное самозатенение, избавление от проблем с силуэтом на главных персонажах и это иногда будет побыстрее, так как с CPU снимается задача вычисления теней. Однако, на данный момент, прямо сейчас, решение через буфер теней чуть медленнее, чем существующее решение через стенсильные тени.

Часть этого из-за API железа. Сейчас я использую p-buffer из OpenGL и интерфейс рендеринга в текстуру, это ПРОСТО КОШМАРНЫЙ интерфейс, он слишком многое наследует из плохих дизайнерских решений времен SGI, и у меня были дни, когда я был особенно близок к переходу на D3D, потому что API были просто ужасающе плохими. И ATI, и NVidia имеют свои предпочтительные направления по эффективному рендерингу в текстуру, потому что проблема с существующими API была не только из-за того, что это были убогие API, там еще была довольно сильный удар по производительности, потому что вам требовалось переключить контексты рендеринга (rendering context) в OpenGL, а для буферов теней это нечто, что случается по 100 раз на кадр, и сегодня это слишком большой удар по производительности.

Так вот, и ATI и NVidia имеют свои пути решения этого и как обычно они не могут прийти к соглашению по поводу того, что именно следует делать, и это просто глупо, такая мелочь. Я читал обе спецификации, я могу работать по любой из них, они обе делают свою работу, просто какие-то глупые искусственные проблемы, я долго переживал по поводу того, почему они не могут просто собраться вместе и принять одну из них. Я сейчас работаю с оборудованием NVidia и скорее всего я буду использовать их расширение.

Проблемы с железом сейчас таковы: у NV40 есть несколько вещей, которые делают разработку для меня проще. У него есть блендинг с плавающей точкой, что экономит мне несколько проходов для того, что я делаю... Нет, ну конечно есть пути для отступления, так как все, что мы делаем с блендингом мы может делать с еще одни проходом и еще одной копией текстуры, чтобы это все работало на железе уровня NV30 и R300. Это неплохо, и там неограниченное число инструкций на NV40... Бывают времена, когда я пишу большие фрагментные программы и удобно записывать туда все больше и больше. Но я хорошо знаю, мне в итоге придется разделить это на куски, которые смогут работать на железе класса R300.

Еще один момент, это производительность на буферах теней. По поводу этого многие люди сомневались насчет стенсильных теней: надо рендерить передние грани, задние грани, края силуэтов, а это такое увеличение количества полигонов. Действительно много лишних полигонов, но что не было сразу очевидно, что на всех тестовых случаях, которые у меня были до сих пор, буферы теней требуют больше отрисовки полигонов, чем стенсильные тени. Причина этого такова: во всех демках буферов теней, чтобы их сделать привлекательными с точки зрения производительности, всегда используется проективный свет с небольшой областью видимости.

Есть замечания, например как в книжке по Рендермену, где говорится: "попробуйте сделать свет, отбрасывающий тень от объектов как спотлайт (spotlight) на 20 градусов и используйте текстуру размером 2k x 2k и у вас получатся хорошо выглядящие тени". Проблем в том, что в играх 99+ процентов всех теней это тени от точечных источников (omnidirectional point lights) света. Чтобы отрендерить точечный источник света с буфером теней потребуется замыкающий полигон. Который проще всего сделать с помощью шести проекций на плоскости. Теперь что выходит. В любой момент, как только какой-либо объект пересекает этот бордюр, он должен быть отрендерен несколько раз. И опять, в типичной графической демке, где у вас ваза с фруктами на плоской поверхности, весь объект помещается в ограничивающую область и очевидно вам нужно только один лишний раз отренедрить эту геометрию, чтобы сделать буфер теней, а потом его использовать.

Опять же, однако, в реальной жизни, или как минимум в реальной игровой жизни, у нас много-много объектов, которые являются частью сцены, которые вместо того, чтобы целиком помещаться в область, ограниченную светом, многие объекты содержат свет целиком, когда вы смотрите на части комнаты, что означает, что вам нужно рендерить геометрию до шести раз. Даже когда она рендерится в среднем возможно дважды, все равно полигонов получается больше, чем со стенсильными тенями. Это все интересно с точки зрения производительности, но число полигонов на железе сейчас очень, очень высоко и только повышается, так что я не думаю, что это будет большой проблемой.

Другой фактор, связанный с этим, это то, что вы видите в программах офлайнового рендеринга, которые часто используют буферы теней: вам приходится делать трюк со сдвигом, чтобы все выглядело правильно. Есть два вида стандартных проблем с буферами теней, два вида артефактов. Когда сдвиг установлен слишком маленький, у вас получается "теневая сыпь" ("shadow acne"), получаются темные мазки теней на тех поверхностях, что освещены, потому что значения в сдвиге недостаточны для того, чтобы убрать тень с поверхности совсем. Когда у вас наложен зашумленный сэмпл, он дает более сглаженный вид с небольшим лишним шумом и это уже не ужасно, но это не то, чего хотелось бы.

Другой артефакт вы получите, если у вас есть слишком большой сдвиг. Тени сползут. Если у вас есть поверхность которая касается пола, то тень не начинается, скажем, прямо от пятки персонажа, а начинается в нескольких пикселах позади него, потому что так работает сдвиг. И это довольно неприятный артефакт, когда вы смотрите и видите скамейки и объекты типа них, а тень падает не точно от них.

Все осложнено несколькими вещами. Одна проблема - это буфер глубины. Обычный буфер глубины, он не линейный. Потому что он содержит проекцию перспективы или деформацию перспективы. И если у вас есть сдвиг, который корректен для чего-то, что прямо рядом с источником света, он на самом деле не корректен для чего-то, что очень далеко. Это довольно существенная проблема. С ней можно бороться: вместо того, чтобы использовать запись в буфер глубины, в настоящий буфер глубины, вы можете рендерить вашу фрагментную программу в альфа-канал, который содержит значения с плавающей точкой в линейном пространстве объекта и вы получаете правильные значения глубины по всему как надо.

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

Я видел подобные ситуации, я вдруг получал один пиксел, выпадающий из карты теней, он был освещен, хотя он был полностью внутри замкнутого меша персонажа. И это было лишь потому, что какой-то маленький полигончик повернулся практически ребром к свету, и значение коэффициента выбросило его за границу мира и через него стало можно видеть. Это проявится, когда у вас есть свет, который проецируется с большого расстояния и карта с довольно небольшим разрешением, вы увидите промелькивающие маленькие яркие искорки.

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

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

Еще один где-то интересный аспект взаимодействия с железом состоит в том, что можно включить 16 битный рендеринг глубины, это режим, который почти не используется на современных системах. Нам нравится наш 24 битный буферы глубины, потому что мы хотим рендерить большие открытые пространства, которые быстро заполняют 16 битный буфер, но 16 битные буферы могут быть очень полезны для буферов глубины. Они не только занимают меньше места даже когда они большие, но они должны рендериться отчасти быстрее и сравниваться быстрее. А большинство источников света не будут освещать огромные пространства.

Итак, есть несколько вещей, которые становятся сложнее с буферами теней. Есть проблемы со склеиванием вместе несколько планов, то есть, если вы делаете шесть отрисовок для граней куба, чтобы потом сделать точечный источник света, вы хотите, чтобы они соединились без швов, чтобы не было никаких дважды затененных или дважды освещенных поверхностей и вы не хотите иметь зашумленные сэмплы, заметно меняющие плоскостную ориентацию. Это заняло некоторое время, прежде чем было доведено до совершенства, но сейчас оно работает и вы не сможете заметить разницу.

Освещение открытых пространств становится более сложным с буферами теней. Если вы хотели сделать простую параллельную проекцию от солнца или луны на ваш мир, вам понадобится карта теней довольно-таки высокого разрешения, которая покроет все в вашем мире или по крайней мере все, что может быть видно. Даже если вы выберете очень большое значение, такое как 2000x2000 и у вас открытое пространство скромных размеров вы увидите, что тени, которые падают от деревьев и от маленьких объектов, выступающих над землей, будут очень размытыми и в квадратиках, потому что не хватает разрешения текстуры.

Есть какая-то работа, предлагающая "карты теней с перспективой" (perspective shadow mapping). Там используется деформация перспективы, чтобы получить большую детализацию для карты теней данного разрешения. Но я не думаю, что это решение можно использовать для игр, потому что всегда можно повернуться таким образом по направлению к свету, что деформация перспективы даст очень небольшой выигрыш или даже сделает все хуже, и вы получите еще большую пикселизацию.

Решение, которое я ищу для освещения открытых пространств, это что-то вроде мипмэппинга для буферов теней, где буфер теней размером 1k x 1k используется для, скажем, 2000 единиц рядом с вами и он обрезан таким образом, чтобы покрыть это пространство динамически. Потом вы масштабируете на степени двойки, до тех пор пока вы не закроете весь мир, что может потребовать 5 или 6 буферов теней, в зависимости от того, насколько велико ваше открытое пространство. Это не так уж и сложно и заканчивается рендерингом шести видов для одного точечного источника для открытого пространства. Я думаю это вполне решаемая проблема.

Есть довольно много компромиссов при использовании буферов теней. Например, очевидно, что раз вы используете кубические карты для буфера теней, вы рендерите ваши шесть видов для кубической карты а потом накладываете кубическую карту. Современное железо не очень хорошо с этим справляется, потому что вам приходится использовать одну из текстурных координат как значение для сравнения и вы не можете делать это сейчас напрямую, хотя есть несколько хаков для 2Д текстур, а кубическую карту можно раскатать в 2Д текстуру и работать с ней уже в таком виде.

Но вот что интересно, получается, что это не совсем то, чего бы вам хотелось. Чтобы сделать эффективный буфер теней в реальном игровом движке вам нужно менять разрешение этой карты теней все время. Если вы видите 50 источников света, то вы не можете рендерить буфер теней размером 2k x 2k для всего, особенно, если большинство источников света могут светить только на 50 пикселов.

Так вот, что я делаю, я динамически масштабирую все разрешения для каждого источника света, который будет отрисован, в зависимости от того, насколько он велик на экране, можно использовать другие параметры в эвристике, другую эвристику. Но потому что тот путь, что я использую для выбора областей, принимающих расчеты теней... я использую для них тесты стенсильного буфера, так что вся работа происходит со стенсильными буферами и за все алгоритмы оттуда приходится чем-то расплачиваться в новом движке, даже хотя мы не используем это напрямую для затенения. Но из-за способа, которым я выбираю области экрана, мне не требуются соединения, или даже текстуры степени двойки для буферов теней, потому что они будут ровно смасшатабированы от 2000 до 1900, 1800 и так далее, вместо скачков по степеням двойки от 2048 до 1024,и т.п. Это так же в итоге сохраняет значительное количество памяти. Посмотрите на большой буфер, размером 2k x 2k с буфером глубины в 24 бита, вы знаете, это 4 миллиона пикселов по 4 байта каждый. И если вы храните в нем полную кубическую карту, это хороший кусок вашей видеопамяти. Так что выгоднее рендерить одну сторону за раз, по крайней мере для источников света, которые близко.

В случае маленьких источников света, где не займет много места рендерить все прямо как кубическую карту, будет выигрыш по производительности. Довольно много 3Д железа на подходе, которое будет позволять рендерить кубическую карту в один проход. Я не сторонник этого. Я старался как мог убить эту идею на последнем Саммите по Графике Windows (Windows Graphics Summit). Это не сработало, все эти вещи прошли, и прозводители железа, я уверен, в итоге заставят все это работать правильно. Но я задаю вопрос о действительной пользе больших затрат на обработку геометрии, которые появятся с заменой всех отдельных нарезанных видов на 6 различных видов, с которыми можно работать одновременно.

Это все двигалось мыслью о том, что мы будем рендерить буферы теней, бросать всю геометрию за раз и железо будет это распределять по разным корзинам. А потом оказалось, что это не так уж и важно и и все это завязано на производительность, а такого уж большого выигрыша, на который люди надеялись, нет. Да и по железу получается дорого делать все это.

Так что построение теней это БОЛЬШОЙ вопрос. У меня оно работает, выглядит хорошо. Сейчас оно не умеет работать с требовательными ситуациями. У меня не сделано освещение открытых пространств. У меня нет правильной спецификации отдельных источников света, насколько сильно размыты края, например.

Размытие краев, получаемое с помощью буфера теней, это не настоящее затенение и высветление. Мягкая часть теней реального мира зависит от размера источника света, расположения окклюдатора (occluder) и расположения поверхности, на которой он находится. И получаются различные эффекты, такие как расширение мягкой тени. От точки пересечения с окклюдатором и поверхностью она становится все шире и шире вплоть до того, что маленькие окклюдаторы полностью поглощаются широкой распространившейся областью источника света. Вы не получите точно такие эффекты, но опять это стандартное качество для многих ренедереров фильмов, которые делаются годами и которые дают дизайнерам контроль над тем, что им нужно. Они могут сказать "Ну этот свет будет иметь большой угол и мы хотим получить более смазанные тени, тогда как вон тот, вон там, распространяется на такую большую область, мы его должны уменьшить, чтобы уменьшить шум" и там будет немного подпихиваний различных параметров.

Так что иногда будет больше хака на уровне источников света, чем когда было со стенсильными тенями, потому что стенсильные тени они такие, какие есть, они все делают с точностью до пиксела вне зависимости от геометрии, неважно где находится источник света. Будет еще много осуждающих возгласов вокруг этого.

 

Страницы: 1 2