Как сделать пиксельную 3д модель
3D своими руками. Часть 1: пиксели и линии
Давайте перед началом изучения интересного мира 3D, выберем язык программирования для примеров, а также среду разработки. Какой язык стоит выбрать для программирования 3D-графики? Любой, можете работать там, где вам удобнее всего, математика будет везде одинаковая. В этой статье все примеры будут показаны в контексте JS (тут в меня летят помидоры). Почему JS? Все просто — в последнее время работаю преимущественно с ним, и поэтому смогу эффективнее вам донести суть. Буду обходить стороной все особенности JS в примерах, т.к. нам нужны лишь самые основные возможности, которые есть у любого языка, поэтому будем уделять внимание конкретно 3D. Но вы выберите то, что любите, т.к. в статьях все формулы не будут привязаны к особенностям какого-либо языка программирования. Какую выбрать среду? Не имеет никакого значения, в случае с JS — подойдет любой текстовый редактор, вы можете использовать тот, что ближе вам.
Все примеры будут использовать canvas для рисования, т.к. с его помощью можно очень быстро, без подробного разбора начинать рисовать. Canvas — мощный инструмент, с большим количеством готовых методов для рисования, но из всех его возможностей, первое время, мы будем использовать только вывод пикселя!
Все трехмерное выводят на экран с помощью пикселей, позже в статьях вы увидите, как это происходит. Будет ли это тормозить? Без аппаратного ускорения (например, ускорения видеокартой) — будет. В первых статья мы не будем использовать ускорений, мы будем писать все с чистого листа, для того чтобы разобраться в основных аспектах 3D. Давайте посмотрим на несколько терминов, которые будут упоминаться в дальнейших статьях:
Для начала создадим проект, у меня это просто текстовый index.html файл, со следующим контентом:
Не буду слишком акцентировать внимание на JS и canvas сейчас — это не главные герои этой статьи. Но для общего понимания уточню, что это прямоугольник (в моем случае размером 800 на 600 пикселей) на котором я буду отображать всю графику. Я canvas прописал единожды и больше его менять не буду.
Script — элемент внутри которого мы будем писать всю логику для рендеринга 3D графики своими руками (на JavaScript).
Когда мы лишь обзорно рассмотрели структуру файла index.html только что созданного проекта, начнем разбираться с 3D графикой.
Когда мы что-то рисуем в окне, это в итоговом счете, превращается в пиксели, ведь именно их отображает монитор. Чем больше пикселей, тем более четкая картинка, но и компьютер нагружается сильнее. Как же хранится то, что мы рисуем в окне? Графику в любом окне можно представить в виде массива пикселей, а сам пиксель — просто цвет. То есть, разрешение экрана 800х600 означает, что наше окно содержит 600 строк по 800 пикселей в каждой, а именно 800 * 600 = 480000 пикселей, много, не правда ли? Пиксели хранятся в массиве. Давайте подумаем, в каком массиве мы бы хранили пиксели. Если у нас должно быть 800 на 600 пикселей, то самый очевидный вариант — в двумерном массиве 800 на 600. И это почти правильный вариант, а точнее — полностью правильный вариант. Но пиксели окна, лучше хранить в одномерном массиве на 480000 элементов (если разрешение 800 на 600), только потому что с одномерным массивом быстрее работать, т.к. он хранится в памяти сплошной последовательностью байт (все лежит рядом и поэтому его легко достать). В двумерном массиве (например, в случае JS), каждая строчка может быть разбросана по разным местам в памяти, поэтому обращение к элементам такого массива будет происходить дольше. Также, для перебора одномерного массива нужен только 1 цикл, а для двумерного целых 2, учитывая необходимость делать десятки тысяч итераций цикла, скорость здесь немаловажна. Что из себя представляет пиксель в таком массиве? Как выше упоминалось — это просто цвет, а точнее 3 его составляющих (красный, зеленый, синий). Любая, даже самая красочная картинка – это просто массив пикселей разного цвета. Пиксель в памяти можно хранить как угодно, либо массивом на 3 элемента, либо в структуре, где будут red, gree, blue; или как-то еще. Изображение, состоящее из массива пикселей, который мы только что разобрали, я дальше буду называть поверхностью (surface). Получается, раз все, что отображается на экране — хранится в массиве пикселей, то меняя элементы (пиксели) в этом массиве — мы будем попиксельно изменять изображение на экране. Именно так мы и поступим в этой статье.
В canvas отсутствует функция рисования пикселя, но есть возможность получить доступ к одномерном массиву пикселей, который мы обсудили выше. Как это сделать показано в примере ниже (этот и все примеры в дальнейшем будут только внутри элемента script):
В примере, imageData — это объект в котором есть 3 свойства:
По умолчанию, весь массив пикселей imageData.data (data это свойство, в котором массив пикселей, а imageData это просто объект) заполнен значениями 0, и если бы мы попытались вывести такой массив, то ничего интересного на экране не увидели бы, потому что 0, 0, 0 — это черный цвет, но поскольку прозрачность тут будет тоже 0, а это полностью прозрачный цвет, то даже черного на экране мы не увидим!
С таким одномерным массивом напрямую работать неудобно, поэтому напишем для него класс, в котором создадим методы для рисования. Я назову класс — Drawer. Этот класс будет хранить только необходимые данные и проводить необходимые вычисления, по максимуму абстрагируясь от используемого для рендеринга инструмента. Именно поэтому в нем мы разместим все расчеты и работу с массивом. А уже сам вызов метода отображения на canvas, мы разместим за пределами класса, т.к. вместо canvas может быть что-то еще. В таком случае, наш класс менять не придется. Для работы с массивом пикселей (surface) нам удобнее сохранить его в классе Drawer, а также ширину и высоту картинки, чтобы правильно уметь обращаться к нужному пикселю. Итак, класс Drawer с сохранением минимума необходимых для рисования данных у меня выглядит так:
Как видим в конструкторе класс Drawer принимает все необходимые данные и сохраняет их. Теперь можно создать экземпляр этого класса и передать в него массив пикселей, ширину и высоту (эти все данные у нас уже есть, т.к. мы их создали выше и хранятся они в imageData):
В классе Drawer мы напишем несколько функций рисования, для простоты работы в дальнейшем. У нас будет функция рисования пикселя, функция рисования линии, в дальнейших статьях еще появятся функции рисования треугольника и других фигур. Но начнем с метода рисования пикселя. Я его назову drawPixel. Если мы рисуем пиксель, то у него должны быть координаты, а также цвет:
Обратите внимание, что функция drawPixel не принимает параметр alpha (прозрачность), а выше мы разобрались, что массив пикселей состоит из 3-х параметров цвета и 1-го параметра прозрачности. Я специально не указал прозрачность, так как она нам для примеров совершенно не нужна. По умолчанию будем устанавливать 255 (т.е. все будет непрозрачным). Теперь подумаем, как в массив пикселей в координаты x, y записать нужный цвет. Поскольку у нас вся информация об изображении хранится в одномерном массиве, в котором на каждый пиксель отводится по 1-му числу (8 бит). Для обращения к нужному пикселю в массиве, нам нужно сначала определить индекс расположения красного цвета, потому что любой пиксель начинается именно с него (напр. [r, g, b, a]). Немного пояснения структуры массива:
В таблице зеленым цветом указано, как хранятся компоненты цвета в одномерном массиве surface. Синим цветом указаны их индексы в этом же массиве, а красным — координаты пикселя, который принимает функции drawPixel, которые нам нужно преобразовать в индексы в одномерном массиве, для задания r, g, b, a для пикселя. Итак, из таблицы видно, что для каждого пикселя красная составляющая цвета идет первой, начнем с нее. Предположим, что мы хотим поменять красную составляющую цвета пикселя в координатах X1Y1 при размере изображения 2 на 2 пикселя. В таблице мы видим, что это индекс 12, но как его вычислить? Для начала находим индекс нужной нам строки, для этого умножим ширину изображения на Y и на 4 (кол-во значений на каждый пиксель) — это будет:
Видим, что 2-я строка начинается с индекса 8. Если сравним с табличкой — результат сходится.
Теперь к найденному индексу строки нужно прибавить смещение по столбцам, чтобы получить искомый индекс красного цвета. Для этого к индексу строки добавим Х умноженный на 4. Полная формула будет такой:
Теперь мы сравниваем 12 с таблицей и видим что пиксель X1Y1 действительно начинается с индекса 12.
Чтобы найти индексы других компонентов цвета, нужно добавить смещение цвета к индексу красного цвет: +1 (зеленый), +2 (синий), +3 (альфа). Теперь можем реализовать метод drawPixel внутри класса Drawer используя формулу выше:
В этом методе drawPixel я повторяющуюся часть формулы вынес в константу offset. Также видно, что в alpha я просто пишу 255, т.к. она есть в структуре, но нам сейчас для вывода пикселей не нужна.
Настало время проверить работу кода и, наконец, увидеть первый пиксель на экране. Вот пример использования метода отрисовки пикселя:
В примере выше я рисую 2 пикселя, один красный 255, 0, 0, другой — синий 0, 0, 255. Но изменения в массиве imageData.data (он же surface внутри класса Drawer) сами на экране не отобразятся. Для отрисовки нужно вызвать ctx.putImageData(imageData, 0, 0), где imageData — объект в котором массив пикселей и ширина/высота области отрисовки, а 0, 0 — это точка, относительно которой будет выводиться массив пикселей (всегда оставляем 0, 0). Если вы все сделали правильно, тогда у вас вверху слева элемента canvas в окне браузера будет такая картина:
Увидели пиксели? Они такие маленькие, а сколько работы проделано.
Теперь попробуем добавить в пример немного динамики, например, чтобы каждые 10 миллисекунд наш пиксель смещался вправо (будем изменять X пикселя на +1 каждые 10 миллисекунд), поправим код рисования пикселя на такой с интервалом:
В этом примере я оставил только вывод синего пикселя и обернул код в JavaScript функцию setInterval с параметром 10. Это означает, что код будет вызываться примерно каждые 10 миллисекунд. Если вы запустите такой пример — увидите, что вместо смещающегося вправо пикселя у вас будет что-то такое:
Такая длинная полоска (или след) остается потому что мы в массиве surface не чистим цвет предыдущего пикселя, поэтому при каждом вызове интервала у нас добавляется еще один пиксель. Давайте напишем метод, который будет чистить surface до изначального состояния. Иными словами — заполним массив нулями. В класс Drawer добавим метод clearSurface:
В этом массиве нет никаких логик, просто заполнение нулями. Этот метод рекомендуется вызывать каждый раз перед рисованием нового изображения. В случае анимации пикселя — перед рисованием этого пикселя:
Теперь если запустить этот пример, пиксель будет смещаться вправо, один одинешенек — без ненужного следа от предыдущих координат.
Последнее, что мы реализуем в первой статье — это метод рисования линии. Добавим его, конечно же, в класс Drawer. Метод я назову drawLine. Что он будет принимать? В отличие от точки, линия еще имеет координаты, в которых она заканчивается. Иными словами, у линии есть начало, конец и цвет, что и будем передавать в метод:
Любая линия состоит из пикселей, осталось только правильно заполнить ее пикселями от x1, y1 до x2, y2. Для начала, раз линия состоит из пикселей, значит, мы будем ее выводить в цикле попиксельно, но как посчитать, сколько пикселей выводить? Например, для рисования линии из [0, 0] в [3, 0] интуитивно видно, что понадобится 4 пикселя ([0, 0], [1, 0], [2, 0], [3, 0],). А вот из [12, 6] в [43, 14], уже непонятно какая длина будет у линии (сколько пикселей выводить) и какие у них будут координаты. Для этого вспомним немного геометрии. Итак, у нас есть линия, которая начинается в точке x1, y1 и заканчивается в точке x2, у2.
Давайте проведем пунктиром линию от начала и конца так, чтобы получился треугольник (рисунок выше). Мы увидим, что в месте соединения проведенных линий образовался угол 90 градусов. Если в треугольнике есть такой угол, значит, треугольник называется прямоугольным, а его стороны, между которыми угол равен 90 градусам, называют катетами. Третья сплошная линия (которую мы и пытаемся нарисовать) называют в треугольнике гипотенузой. При помощи этих двух введенных катетов (на рисунке это c1 и с2), мы и сможем вычислить длину гипотенузы по теореме Пифагора. Давайте посмотрим, как это сделать. Формула длины гипотенузы (или длины линии), будет следующей:
Как получить оба катета также видно из рисунка треугольника. Теперь по формуле выше найдем гипотенузу, которая и будет длинной линии (количеством пикселей):
Мы уже знаем, сколько пикселей выводить для отрисовки линии. Но мы еще не знаем, как смещаются пиксели. То есть, нам нужно нарисовать линию от x1, у1 до х2, у2, мы знаем, что длина линии составит, например, 20 пикселей. Мы можем нарисовать 1-й пиксель в х1, у1 и последний в х2, у2, но как найти координаты промежуточных пикселей? Для этого нам и нужно получить, как смещать каждый следующий пиксель по отношению к x1, y1, чтобы получилась нужная линия. Приведу еще один пример, чтобы лучше понять, о каком смещении идет речь. У нас есть точки [0, 0] и [0, 3], по ним нужно нарисовать линию. Из примера хорошо видно, что следующая точка после [0, 0] будет [0, 1], а потом [0, 2] и наконец [0, 3]. То есть, Х каждой точки не смещался, ну или можно говорить, что смещался на 0 пикселей, а Y смещался на 1 пиксель, вот это и есть смещение, его можно записать в виде [0, 1]. Другой пример: у нас есть точка [0, 0] и точка [3, 6], попробуем посчитать в уме, как они смещаются, первой будет [0, 0], потом [0.5, 1], потом [1, 2] потом [1.5, 3] и так далее до [3, 6], в этом примере смещение будет [0.5, 1]. Как же его вычислить?
Можно использовать такую формулу:
В коде программы у нас будет так:
Все данные уже есть: длина линии, смещение пикселей по Х и по Y. Начинаем в цикле рисовать:
В качестве координаты Х функции Pixel передаем начало Х линии + смещение X * i, таким образом, получая координату i-го пикселя, точно также вычисляем и координату Y. Math.trunc это метод в JS который позволяет отбросить дробную часть числа. Весь код метода выглядит так:
Подошла к концу первая часть, длинного, но захватывающего пути постижения мира 3D. Ничего трехмерного еще не было, но мы выполнили подготовительные операции для рисования: реализовали функции рисования пикселя, линии, очистки окна и узнали несколько терминов. Весь код класса Drawer можно посмотреть под спойлером:
Пиксель-арт: от черновика до игрового ассета
→
В этой статье я постараюсь визуализировать общий подход к работе. Итак, вы решили учиться арту: вы скачали какое-то ПО, запустили его и увидели все эти опции, бесконечные цвета и многое другое, быстро всё закрыли, удалили программу и выбросили свой ноутбук в окно.
Возможно, спустя несколько месяцев вы это повторите. Иногда вы попытаетесь нарисовать пару линий, которые выглядят как детский карандашный рисунок, или даже хуже, и на этом решите бросить.
Если вам это знакомо, то данная статья как раз для вас, так что продолжайте читать.
Независимые разработчики игр довольно часто жалуются на то, что они не могут создавать графику, потому что они программисты, а денег на оплату художников у них нет.
И хотя изучение арта может показаться устрашающей задачей, в реальности вы можете подняться до вполне достойного уровня, потратив на практику по крайней мере один год.
Если возьмётесь за работу очень усердно, то, возможно, получите неплохие результаты через несколько месяцев.
Приготовьтесь к пиксель-арту
В этой статье я рассмотрю пиксель-арт. Считаете, что он давно стал клише и от него все устали?
Ну, на самом деле, пиксель-арт — превосходное подспорье для того, чтобы стать художником. Вы обнаружите, что достаточно хорошо освоив пиксель-арт, очень легко можно перейти к другим стилям графики.
Ещё одно серьёзное преимущество заключается в том, что вам нужна только мышь, и не надо тратить деньги на графический планшет. На самом деле, большинство людей, рисующих пиксель арт, предпочитает ради повышенной точности пользоваться мышью.
Часто про пиксель-арт говорят и такое: «он может выглядеть красиво, но большинство пиксельной графики инди-разработчиков ужасно».
И я могу с этим согласиться, но если вы будете следовать правилам из этой статьи, то ваш пиксель-арт будет выше среднего, не волнуйтесь.
10 этапов создания пиксель-арта
Лучший способ повышения навыка — сначала узнать правила. Позже их можно нарушить, но когда учишься чему-то новому, следование правилам даёт тебе сильный толчок вперёд.
В этой статье я расскажу вам о десяти этапах и паре правил, которые помогут вам начать. Можете повторять их с любой пиксель-артной графикой, которую вам нужно создать.
Чтобы игра выглядела хорошо, ей нужен уверенный графический стиль, и если вы будете следовать моим рекомендациям, вы этого добьётесь.
Этап 1 — палитра
Никогда не выбирайте цвета самостоятельно. Цвет — сам по себе искусство, но, к счастью, мы можем позволить заняться им профессионалам. Загляните сюда и выберите цветовую палитру.
Учтите, что количество цветов в палитрах может быть разным. Не рекомендую использовать палитры больше 32 цветов, а для начала даже 16 цветов.
Для этой статьи я выберу такую палитру. Можно было взять любую другую, я выбрал её случайным образом из списка.
Этап 2 — разрешение
Для начала выбирайте небольшое разрешение. Если вы новичок, то ударьтесь в ретро и создавайте спрайты размером 16×16 или 32×32, не больше.
Можно использовать и другие соотношения, например 24×32, главное, не слишком больше этого.
Этап 3 — контуры
При рисовании объекта сначала нарисуйте одним цветом, например чёрным, его контур. На этом этапе не допускаются никакие другие цвета.
Рекомендуется всегда иметь перед глазами референс (справочное изображение). Вы должны иметь возможность видеть референс, пока рисуете, а не постоянно переключать окна.
Также проверьте, чтобы в контуре не было дыр, на данном этапе это самое важное.
Я нарисовал такого паренька с разрешением 32×32. Выглядит он ужасно.
По крайней мере, теперь вы не будете жаловаться, что я не начал с самого начала!
Этап 4 — цвета
Убедившись, что контур достаточно хорош, можно приступать к заливке внутренней части. В большинстве программ есть инструмент «Заливка цветом», и это самый быстрый способ заполнения внутренних областей нужным цветом.
Здесь снова используйте как можно меньше цветов, и только из палитры, которую вы выбрали. В хорошем дизайне персонажа будет как минимум три различных диапазона. По сути, диапазон (ramp) — это способ упорядочивания цветов палитры по семействам оттенков, от тёмного к светлому.
Обычно на этом этапе нужно выбирать цвета из середины каждого диапазона, то есть не очень тёмные и не очень светлые, только если по каким-то причинам вы рисуете объект или персонаж, для которого нужны именно они.
Вот пример возможных диапазонов ранее выбранной мной палитры. Заметьте, что я не добавлял все цвета из палитры, только некоторые, чтобы вы поняли принцип.
Также на картинке видно, что цвет может использоваться в нескольких диапазонах, становясь или начальным, или конечным цветом.
Итак, я выбрал несколько цветов из палитры и раскрасил своего персонажа.
Помните, я говорил, что важно не оставлять дыр?
Этап 5 — оттенки
На этом этапе могут застрять многие, и на самом деле можно создать красиво выглядящую игру только на основе предыдущих этапов, без оттенков. Достаточно придерживаться правила цветовой палитры, сохранять целостность художественного стиля, и ваша игра уже будет выглядеть лучше, чем большинство других.
Но чтобы расти как художнику, вам необходимо освоить навык затенения.
Для начала есть простой трюк: нужно выбрать направление освещения в игре — слева или справа, а затем придерживаться его при создании каждого спрайта, тайла и всего остального.
Примечание
Это означает, что если у вас есть персонаж, смотрящий вправо, то чтобы он смотрел влево, нельзя просто отзеркалить его в коде. Его нужно перерисовать с учётом фиксированного направления света.
Основная идея затенения заключается в том, что части изображения, на которые падает прямой свет, становятся светлее, а части, на которые не падает свет, остаются в тени, поэтому они становятся темнее. Очень просто, правда?
Но если вы новичок в графике, то, скорее всего, не понимаете, как это сделать, и в большинстве туториалов это не объясняется, потому что просто читая слова, этому не научиться.
Поэтому вот вам хитрость. В своём примере я возьму освещение, падающее справа.
Для начала каждому цвету персонажа я подберу более светлый цвет, и раскрашу один пиксель каждого края, находящегося справа или сверху.
Затем для каждого цвета персонажа я выберу более тёмный цвет и раскрашу им каждый пиксель каждого края, находящегося слева или внизу.
Знаю, что это выглядит довольно ужасно, но продолжайте чтение, и вскоре мы улучшим ситуацию.
Если по каким-то причинам этот этап кажется вам слишком сложным, то приблизьте изображение и посмотрите, как я это сделал — добавлены два дополнительных оттенка для синего, красного и бежевого цветов. Все они выбраны из палитры и нанесены с учётом правила «сверху-справа»/«слева-внизу».
Этап 6 — пропорции
Это ещё один источник неудач для начинающего художника. К счастью, пиксель-арт низкого разрешения сильно упрощает его.
На этом этапе всё становится довольно субъективным. Возможно, это вас удивит, но чтобы стать хорошим художником, нужно практиковаться не руками, а глазами.
Ваша основная задача — разбудить в себе нечто, называемое «взглядом художника». Это особый навык, позволяющий вам смотреть на вещи и разлагать их на составные части, а затем складывать их своими руками.
«Взгляд художника» раскрывается сочетанием создания собственной графики и изучения работ других людей. Необходимы оба шага: если вы просто продолжите рисовать, не глядя на работы других, или будете только изучать других, не рисуя, то этот взгляд у вас не разовьётся.
Давайте проверим ваши собственные глаза — снова взгляните на этот ужасный спрайт и скажите, какие его части выглядят глупо.
(Не тратьте время на поиск отличий между этим и предыдущим изображением, они одинаковы, я просто повторил его здесь для удобства.)
Первое, что приходит в голову — похоже, что наш персонаж падает. Давайте ему поможем.
Единственное, что я здесь сделал — переместил по горизонтали несколько пикселей. Из этого можно понять, что создание рисунков — это очень итеративный процесс. У вас не получится сделать всё правильно с первого раза, придётся вносить кучу переработок.
Давайте ещё раз взглянем на эту версию и подумаем, что теперь с ней не так?
Мне кажется, что бедный персонаж танцует, но он не должен танцевать, так что давайте это исправим.
Отлично, поза стала получше, а ещё я добавил ему штаны.
Примечание
Для создания поз можно использовать тысячи референсов из Интернета. Вполне может хватить даже каких-то случайных фотографий.
Не думайте, что художники рисуют только из своего воображения, они смотрят на референсы!
Это похоже на то, как кодеры ежедневно заходят в Google или на Stack Overflow — никого это не волнует.
Этап 7 — подчищаем блоки
Видите эти некрасивые чёрные скопления пикселей?
Давайте избавимся от них всех и создадим правило, что пиксель может касаться максимум двух других пикселей.
Персонаж стал чище. По какой-то причине это изменение дало мне понять, что у него должен быть длинный нос, поэтому добавим его.
Иногда сам процесс редактирования даёт нам вдохновение.
Примечание
При удалении скоплений пикселей существуют некоторые исключения: иногда нельзя удалить определённый пиксель, даже если он образует скопление, потому что в противном случае в контуре возникнет дырка.
Я добавил нос и немного изменил форму головы, чтобы она лучше соответствовала носу.
Также я добавил контуры вокруг ног, чтобы они соответствовали остальным частям. Весь арт в игре должен быть целостным!
Этап 8 — подчищаем оттенки
Хитрость, которую мы применили при затенении, сработал, но в некоторых частях персонаж всё равно выглядит немного уродливо.
Если ваш взгляд художника уже активировался, то у вас появятся предпочтения по замене тёмных и светлых пикселей более нейтральным оттенком.
Здесь я сделал пару действий — заменил все яркие и тёмные пиксели, которые казались неуместными, а затем изменил внешние контуры.
Пиксель-арт имеет такое низкое разрешение, что контуры отнимают пространство, необходимое для деталей. В некоторых важных местах они нужны, но не в этом случае.
Также я добавил персонажу руки и ноги, больше соответствующие стилю других его частей.
Небольшое изменение: я изменил его штаны и переместил на пару пикселей. Но что-то всё равно кажется странным, я не совсем понимаю, что делать дальше.
Давайте попробуем убрать контуры, заменив их на цвета ближайших пикселей.
Если посмотреть на персонажа теперь, то ноги выглядят странно, как у кентавра. И ещё у него странное лицо — нос смотрит в одном направлении, а глаза — в другом.
Художники используют хитрость, позволяющую мозгу искать ошибки — они смотрят на рисунок под другим углом.
Свежий взгляд позволяет заметить то, что не видел раньше, и когда я убирал контуры, можно было просто посмотреть на перевёрнутое изображение!
Итак, я переделал многие части его головы, рук и ног. Он уже выглядит полностью иначе, немного правильнее.
Но постойте, почему у него нет ушей? И почему кажется, что его шляпа висит в воздухе, а не соединена с головой?
Мы это исправили, и теперь персонаж начал выглядеть намного профессиональнее. Посмотрите на затенение на шляпе. Понимаете ли вы, как оно работает?
В нём просто применено то же правило — свет с одной стороны, тень с другой. При правильной реализации персонаж выглядит почти трёхмерным.
Чтобы затенение выглядело правильным, если у вас ещё не открылся «взгляд художника», то просто пробуйте разные сочетания тёмных, нейтральных и светлых пикселей.
Всегда придерживайтесь трёх оттенков. Здесь сложно ошибиться, потому что при работе со спрайтами низкого разрешения изменений бывает очень мало.
Однако внешний вид затенения иногда может сильно зависеть от единственного пикселя. Это вы поймёте со временем и практикой.
Примечание
Как только вы начнёте понимать, как работает затенение, то сможете лучше создавать объекты, имеющие объём, что и является основной задачей затенения.
Однако стоит помнить, что изучаемой нами системы с тремя оттенками более чем достаточно для большинства пиксель-арта низкого разрешения. Добавление большего количества оттенков делает пиксель-арт более грязным и шумным.
Этап 9 — доводка
Да, персонажа уже можно использовать, но давайте продолжим улучшать его.
Ещё один простой трюк, позволяющий добавить объёма — знание о том, что в дальних частях объектов нужно использовать более тёмные оттенки.
Поэтому я сделал одну из рук и одну из ног более тёмного оттенка, всё просто.
Давайте ещё что-нибудь улучшим!
Здесь я немного изменил положение рук. Совершенно нормально перерисовывать части персонажа, пока вы не будете полностью довольны. Чем больше практикуетесь, тем быстрее будете получать качественный результат и тем меньше понадобится переделок.
Ещё я добавил шарф и волосы. Учтите, что если добавлять разные элементы, расположенные близко друг к другу и имеющие одинаковые или похожие цвета, то это будет сбивать с толку.
В нашем случае шарф позволяет добавить контраста для отделения волос от рубашки.
Также я немного изменил цвет глаз, это уже касается дизайна персонажа — мне показалось, что чёрные глаза не соответствуют остальным частям.
А затем нужны два тёмных пикселя посередине рубашки?
В основном ради эксперимента: я попробовал, и мне понравился результат. Так как пиксель-арт с низким разрешением требует немного воображения, эти два пикселя намекают складки на одежде, или что персонаж одет в водолазку, или что он женского пола.
Наконец, я снова вернул контур, рисуя по пикселю за раз и избегая создания скоплений пикселей.
Рисовать контуры или нет — в основном вопрос предпочтений. Но они помогают создать контраст между персонажами и фоном.
Контур не обязан всегда быть чёрным. Вот альтернативный способ создания контура — мы смотрим на соседние с контуром пиксели и выбираем немного более тёмный оттенок.
Разумеется, я всегда использую только цвета из исходной палитры, не забывайте об этом!
Эта последняя версия может выглядеть лучше, но чем больше цветов, тем больше времени будет уходить на анимацию. Поэтому здесь я снова вернусь к чёрному контуру.
Примечание
Если сравнить версию с контуром и версию без контура, то контур может выглядеть «тяжёлым».
Выбор того или иного варианта зависит от эффекта, который нужен для вашего стиля графики.
Этап 10 — анимация
По сути анимирование заключается в следующем: мы берём наш спрайт и создаём слегка отличающиеся кадры в других позах.
Низкое разрешение пиксель-арта помогает и в обучении анимации. Давайте начнём с анимации бездействия, самой простой из всех видов анимаций.
По сути, я просто выделил половину спрайта и переместил её вниз. Если вы ленивый разработчик, то вам и этого будет достаточно, но не для меня!
На этот раз я переместил ещё несколько пикселей, переместив вверх волосы, шляпу и нос. Так сделано потому, что когда перемещает голову вниз, всё остальное тоже сдвигается вниз, но не мгновенно, что добавляет задержку для этих частей.
Обе руки я немного сместил влево, чтобы симулировать небольшой вторичное движение. Это не какой-то специализированный термин, он просто означает, что это независимое действие, никак не связанное с колебаниями головы.
Этап 10 — субпиксельная анимация
Если вы добрались досюда, то уже входите на территорию более сложных задач.
Пока низкое разрешение помогало скрывать то, что мы изучаем графику, но иногда оно работает против нас.
Последний кадр стал хорошим тому примером: движения шляпы и носа слишком уж сильные. Но мы ведь сдвинули их всего на один пиксель вверх!
Вот если бы мы могли сдвинуть их меньше, чем на пиксель, чтобы сделать движение более плавным… Но увы, пиксель — это самая маленькая величина.
Однако есть одна хитрость — вместо того, чтобы двигать пиксели, мы можем двигать цвета!
Поэтому я вернул нос и шляпу на их исходное место, и вместо этого меняю только цвета, заливая их соответствующими тёмными и светлыми оттенками так, как мне показалось правильным.
И этот трюк тоже зависит от вашего «взгляда художника». Активно тренируйте его, и постепенно начнёте работать всё проще и быстрее!
Заключение
Надеюсь, вам понравилось наблюдать, как я превратил совершенно бесформенную фигуру из палочек и кружочков в персонажа, которого можно использовать в игре. Я попытался показать все этапы и объяснить, почему и как я их выполнял, чтобы это не превратилось в ещё один туториал «нарисуйте оставшуюся часть совы».
Я планирую выпустить похожие статьи по другим темам, например, тайлсетам, низкополигональным моделям или даже музыке, всё зависит только от свободного времени и мотивации.
Также не забудьте прочитать мою статью про pixel perfect graphics, которая тоже очень важна для создания целостного графического стиля.