Как в фотошопе наложить текстуру на объект. Наложение текстуры в фотошопе. Загружаем узоры в Фотошоп

Включает/отключает текстуру окружения карты (т.н. «скайбокс » или попросту небо).
очень малое или нет.

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

Подробнее о технологии мип-маппинга

MIP mapping (от лат. multum in parvo - «много в малом») - метод текстурирования, использующий несколько копий одной текстуры с разной детализацией. Это страшное слово на самом деле означает изменение детализации текстур в зависимости от расстояния от камеры. Методика позволяет избавиться от шума на удалённых объектах и существенно повышает производительность отрисовки.

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

При использовании этого метода вы увидите изображение в высоком разрешении, находясь близко от объекта, и изображение в низком разрешении при удалении от объекта. MIP-mapping снижает мерцание и «зашумлённость» изображения, возникающие при texture mapping.

Мип-маппинг использует некоторые умные методы для упаковки данных о текстурах изображения в памяти. Чтобы использовать MIP mapping, необходимо, взяв все размеры текстур и умножив это число на два, построить одну карту наибольшего размера. Все карты меньшего размера обычно фильтруются и становятся усреднёнными и уменьшенными версиями самой большой карты.

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

Чтобы получить доступ к ручной настройке графических эффектов, приведённых ниже, снимите галочку с опции «Автоматическая настройка качества графики» в настройках. Если у вас нет этой опции, ознакомьтесь со статьёй «Отсутствие настроек графики » .

Включает/отключает тени, отбрасываемые объектами на карте, включая танки и дроп .
Влияние на производительность: высокое.

Включает/отключает затенение малоосвещённых участков карты, что позволяет получить более объёмное изображение.
Влияние на производительность: очень высокое.

Включает/отключает дымку над картой.
Влияние на производительность: очень малое или нет.

  • Разработка игр
    • Перевод

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

    Часть первая: Динамическое освещение На его создание меня вдохновил пост на реддите, где aionskull использовал карты нормалей в Unity для динамического освещения своих спрайтов. А пользователь с ником gpillow запостил в комментах что он сделал что-то похожее в Love2D. Вот тут 8-мб гифка с результатами. За неё спасибо jusksmit’у.

    Итак, что такое динамическое освещение? Это техника в 3D графике, где источник света освещает объекты на сцене. Динамическое потому, что обновляется в реальном времени при движении источника. Довольно стандартная штука в 3D мире и легко применимая к 2D, если, конечно, вы можете использовать преимущества шейдеров.

    Сделать динамическое освещение можно зная, что угол падения света на плоскость определяет её освещенность, а определить освещенность можно узнав вектор нормали, который показывает куда «смотрит» плоскость.

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

    Ок, всё очень здорово, но как получить вектора нормали в 2d игре? Здесь, вообще-то, нет никаких объемных объектов… Однако, здесь нам могут помочь дополнительные текстуры (те самые карты нормалей), в которых будет записана необходимая информация. Я создал 2 таких карты для двух домов в видео повыше и использовал их чтобы посчитать освещение, вот пример:

    В начале вы видите обычный спрайт домика без затенения. На второй части картинки расположена его карта нормалей, кодирующая вектора нормалей в цвет текстуры. У вектора есть (x,y,z) координаты, а у пикселя текстуры есть r,g и b компоненты, так что закодировать нормаль реально просто: Возьмем фасад дома, который направлен на юг. Его нормаль будет вектором с координатами . (По хорошему, нормаль должна быть равна (0, 1, 0), но так как вектор мы определяем от -1 до +1, а кодировать надо в промежуток от 0 до 1, то, видимо, автор решил не запариваться и сразу считать нормали от -0.5 до +0.5. прим. перев.)

    RGB значения не могут быть отрицательными, так что мы подвинем все значения на 0.5: . Ну и ещё RGB обычно представляется в числе от 0 до 255, так что мы домножим на 255 и получим , или, другими словами, вектор «на юг» будет вот этим светло-зеленым на карте нормалей.

    Теперь, когда у нас есть нормали, мы можем позволить графической карте сделать её магию.
    Я использую ImpactJS , у него неплохая совместимость с WebGL2D . (Он платный, я рекомендую pixi.js или любая другая графическая библиотека с webgl рендерером. Если знаете ещё аналоги - пишите в комменты! прим. перев.) Используя WebGL2D мы можем легко добавить пиксельный шейдер для освещения:

    #ifdef GL_ES precision highp float; #endif varying vec2 vTextureCoord; uniform sampler2D uSampler; uniform vec3 lightDirection; uniform vec4 lightColor; void main(void) { // Берем вектор нормали из текстуры vec4 rawNormal = texture2D(uSampler, vTextureCoord); // Если альфа-канал равен нулю, то ничего не делаем: if(rawNormal.a == 0.0) { gl_FragColor = vec4(0, 0, 0, 0); } else { // Транслируем из RGB в вектор, а именно из 0..1 в -0.5..+0.5 rawNormal -= 0.5; // Вычисляем уровень освещенности float lightWeight = dot(normalize(rawNormal.xyz), normalize(lightDirection)); lightWeight = max(lightWeight, 0.0); // И записываем в пиксель gl_FragColor = lightColor * lightWeight; } }

    Пара заметок: У нас получается попиксельное освещение, которое немного отличается от вершинного освещения (обычного в 3d). Выбора особого нет, так как вершины в 2d бессмысленны (их всего 4 штуки для отображения плоскости на сцене). Но, вообще-то, это не проблема, попиксельное освещение гораздо более точное. Также следует отметить, что шейдер рендерит только освещение, без основного спрайта. Придется признать, я немного жульничаю, ведь на самом деле я не освещаю свой спрайт, а, скорее, затеняю его и в lightColor я передаю темно-серый цвет. Настоящее освещение пикселей, а именно повышение яркости, выглядит хуже, пиксели кажутся «вытертыми». У этой проблемы есть решения, но сейчас это непринципиально.

    Часть вторая: рисование теней. Отбрасывание теней в 3D - хорошо изученная проблема с известными решениями, типа рейтрейсинга или shadow-mapping’а . Однако, я затруднился найти какое-нибудь приемлимое готовое решение для 2d, пришлось делать самому, думаю получилось нормально, хотя и у него есть пара недостатков.

    Вкратце, будем рисовать линию от пикселя на сцене к солнцу и проверять, есть ли какое-нибудь препятствие. Если есть - то пиксель в тени, если нет - на солнце, так что, впринципе, ничего сложного.

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

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


    Как только мы найдем препятствие, мы определим его высоту, и насколько высоким оно должно быть в данной точке чтобы преградить солнце (используя zAngle ).


    Если значение в карте высот будет больше, то всё, пиксель в тени. Если нет - мы продолжим искать. Но рано или поздно мы сдадимся и объявим, что пиксель освещен солнцем. В примере я захардкодил 100 шагов, пока что работает отлично.

    Вот код шейдера в упрощенной/псевдо форме:

    Void main(void) { float alpha = 0.0; if(isInShadow()) { alpha = 0.5; } gl_FragColor = vec4(0, 0, 0, alpha); } bool isInShadow() { float height = getHeight(currentPixel); float distance = 0; for(int i = 0; i < 100; ++i) { distance += moveALittle(); vec2 otherPixel = getPixelAt(distance); float otherHeight = getHeight(otherPixel); if(otherHeight > height) { float traceHeight = getTraceHeightAt(distance); if(traceHeight height) { traceHeight = getTraceHeight(height, zAngle, distance); if(traceHeight height) { float traceHeight = getTraceHeightAt(distance); if(traceHeight height) { traceHeight = getTraceHeight(height, zAngle, distance); if(traceHeight