Привет!
Часть 1
Часть 2
Часть 3
Часть 4
Часть 5.1
Интермеццо
Часть 5.2
Сегодня мы обойдемся без долгих вступлений, ибо материала очень много. Этот пост вновь будет посвящен теории, а в следующем мы перейдем уже к практическим примерам.
При этом, я прошу вас быть очень внимательными ко всему написанному, т.к. абсолютно все в этом посте плотно взаимосвязано. И любая последующая информация основывается на предыдущей. Поехали.
Для начала давайте разберемся с одним из основных понятий, которое нам пригодится.
Тексель. Большинство из вас о нем слышало. Я даже думаю, что многие знают, что это.
"Чем больше тексель, тем лучше текстура" - именно на этом утверждении, с которым я в общем и целом не могу не согласиться, большинство и останавливается, не углубляясь в область применения данного термина.
Давайте прежде всего дадим определение текселя. Тексель - это пиксель в текстуре трехмерного объекта. Чем он отличается от пикселя? Тем, что при выводе изображения один пиксель на текстуре может занимать несколько пикселей на мониторе, и, таким образом, тексель не равен пикселю итогового изображения. Но, если говорить о текстуре меша, то тексель - это пиксель в том понимании, в котором мы его знаем. Теперь разберемся еще с одной вещью. В индустрии 3D небрежным словом "тексель" привыкли называть не сам тексель, а плотность текселей на текстуре. А плотность текселя - это, в свою очередь, количество текселей на единицу реального размера объекта. Для понимания смотрим на скриншот:
Если сторона квадрата равна 1 см, то плотность текселя будет равна 5 пикселям на 1 см. Думаю многие из вас (особенно те, кто работает в PS) встречали обозначение ppi. Так вот ppi - это ни что иное как pixel per inch, т.е. пискель на дюйм.
Разобравшись с терминологией, начинаем разбираться с тем, зачем нам нужен тексель. А нужен он нам для того, чтобы объекты в игре не только смогли быть красивыми, но при этом еще и создавали впечатление единого мира, а не собранной из различных сторов кучей мусора.
Прежде чем приступать к производству ассетов, любой разработчик определяет средний тексель объектов в игре. Чаще всего все ассеты разделяются на категории по принципу того, как с ними будет взаимодействовать игрок и как близко они смогут оказаться к камере. Каждой из этих категорий будет назначена эталонная плотность текселя. Например, в шутере от первого лица плотность текселя на оружии будет выше, чем, например, у врагов или окружения. А вот в RTS типа StarCraft тексель будет более-менее равномерным для всех объектов.
Определить эталонный тексель для своей игры вы можете, просто поэкспериментировав с различным текселем на объектах из разных категорий. Создаете простой меш, делаете тексель максимальным, накладываете простую, но разнообразную текстуру, и затем постепенно начинаете уменьшать тексель в поисках оптимального с точки зрения качества и оптимизации варианта.
Стоит уделить внимание основному правилу, касающемуся плотности текселя:
На мониторе игрока плотность текселя должна быть равномерной.
Для понимания этого правила давайте разберем пример:
На первом скриншоте тексель всех объектов в сцене абсолютно одинаковый. На втором тексель каждого объекта различается в зависимости от того, как далеко он находится от камеры. Как можно заметить, единой и целостной сцена смотрится именно тогда, когда объекты имеют разный тексель, но при этом на экране создается ощущение, что текстура имеет одинаковое качество у каждого из них.
Сразу стоит заметить, что если вы испытываете скепсис по поводу того, что эта разница видна только на чекере, а в игре с рабочими текстурами все резко изменится, то спешу вас убедить, что эффект будет более чем полностью идентичным, пусть и не столь очевидным.
Ну, и напоследок скажу, что в рамках одного объекта вы тоже вольны менять тексель. Например, нижнюю часть оружия в FPS игрок будет видеть реже, чем верхнюю. Так что, плотность на рукоятке можно снизить по отношению к верхней части. Но и в этом случае разница не должна быть слишком значительной.
Разумеется, в динамике игры вам вряд ли удастся держать тексель абсолютно равномерным, но стремиться к этому придется. Поэтому к определению категорий объектов стоит отнестись со всей серьезностью.
Теперь, после "краткого" знакомства с плотностью текселя, настало время понять, как он связан с UV.
Если вдруг вы еще не осознали этого, исходя из описанного выше, то поясню... Даже если осознали, то все равно поясню. Я, знаете ли, люблю пояснять. Слабость у меня такая 🙂
Так вот, всё ваше непреодолимое желание сделать "4К текстуры на вон той коробке шоб все ах*ели от графона" можете выбросить. Ибо разрешение текстуры определяется именно текселем и ничем иным. Для примера давайте определили наш эталонный тексель как 1 пиксель на 1 юнит (см, м, дюйм - без разницы). После этого мы создаем объект. В нашем случае для очевидности объектом будет квадратная плоскость со стороной, равной 15 юнитам. А теперь давайте накинем на него текстуру 8*8 пикселей:
Как мы видим, наш объект попросту не помещается в основную UV область. А значит, нам придется уменьшать UV шелл, а значит, плотность текселя уменьшится и сильно отойдет от эталонной. В утиль. Пробуем текстуру 32*32:
Таааак. На сей раз на UV остается слишком много свободного места. Это, как мы понимаем, тоже плохо. Ибо карта текстур, оттого что мы ее займем лишь частично, весить меньше не станет. В утиль. Наверное, стоит взять что-то среднее? Как насчет 16*16:
Иииии, да! Это как раз то что нам нужно.
Можете нас всех поздравить, теперь мы понимаем, как правильно выбирать разрешение для текстуры.
Но, разрешение - это разрешение, текстура - это текстура. UV то тут, блин, при чем? И, для того, чтобы связать всю эту информацию воедино, нам понадобится пригласить нашего следующего друга. Встречайте, padding.
В дословном переводе это слово обозначает набивку. Однако, в 3D софте этот термин обозначает простой и понятный "отступ".
Для объяснения данного термина в 3D позвольте напомнить вам об одном случае, которые мы разбирали в предыдущем посте:
Напомню, что мы пытались запечь на один UV шелл нормаль с разных смуз групп. И получили в итоге косяк, ибо нам попросту не хватило места на карте нормали чтобы компенсировать жесткий переход между разными тангентами.
Так вот, если бы даже объект в этом случае был разбит на несколько шеллов вместо одного, но лежали бы они вплотную друг к другу, то результат бы получился полностью идентичным. Даже если шеллов несколько, им, по прежнему, нужно свободное пространство.
Еще одна разновидность проблем, которая может возникнуть при отсутствии отступа между шеллами, связана с тем, что многие движки любят сжимать текстурные карты (особенно если дело касается текстур в формате .dds. И тогда пиксели с одного шелла могут запросто перекрыть пиксели с другого шелла или смешать информацию в среднее значение. Вызовет это крайне неприятные последствия.
И, наконец, с шеллами, лежащими вплотную друг к другу попросту неудобно работать.
Теперь перейдем к тому, как правильно определить необходимый паддинг.
Стандартным значением является отступ в 2-3 пикселя. Именно отступ от одного шелла. Т.е. между границей шелла и границей UV пространства должно быть 2-3 пикселя. Между границами двух шеллов 4-6 (по 2-3 от каждого из них). Это значение не меняется в зависимости от разрешения карты. Так, отступ в 2-3 пикселя в 1024*1024 останется таким же и в 2048*2048.
Однако, есть одно важное замечание. Если вы впоследствии планируете сжимать карту текстур (например, для лодов), то стоит отталкиваться именно от минимального разрешения. Так, если минимальная текстура объекта будет 128*128, а рабочая текстура 512*512, то отступ должен составлять 2-3 пикселя*4 = 8-12 пикселей.
Вот пример правильного отступа:
Теперь, когда мы выяснили, как правильно выбрать разрешение текстуры, и как этот выбор в дальнейшем повлияет на укладку UV, можно поговорить о правильной нарезке и упаковке. Но сделаем мы это уже в следующем посте.
А пока всем удачи и спасибо за внимание!