Создание октакля из Medieval Craft. Урок 0
Создание октакля из Medieval Craft. Урок 0
Доброго времени суток, я расскажу о том, как создать портал в ад из Medieval Craft, aka октакль (восьмиконечная звезда в круге)
В этом, если так можно сказать, цикле туториалов, я расскажу об использовании самописных шейдеров, материалов и анимированных частиц в новом Inner Core. Сегодня мы разберёмся с написанием шейдеров и их подготовкой для Minecraft.
Видеокарты используют шейдеры для для определения окончательных параметров объекта или изображения, таких как позиция вершин, способ наложения текстуры и цвет отдельно взятых пикселей. Шейдеры делятся на несколько типов, но нам понадобится только два из них: вершинный и фрагментный. Вершинный шейдер оперирует с вершинами, текстурными координатами и параметрами, передаваемыми в шейдер извне. Фрагментный шейдер используется для по-пиксельного отображения картинки, он использует информацию из вершинного шейдера и оперирует текстурами. Шейдеры в Minecraft написаны на языке GLSL, очень рекомендую ознакомится хоть немного с этим языком здесь или, для тех, кто не знает эльфийского, здесь. Также есть сайт, где можно быстро проверить свой шейдер: shadertoy.com.
Проще всего использовать уже готовые шейдеры Майнкрафта, переписав их под свои нужды, что я и буду делать. Все шейдеры Майнкрафта лежат по пути /assets/shaders/glsl в его apk файле. В моде шейдеры должны располагаться в папке /res/custom-shaders/. Очень важно, чтобы перед названием файла шейдера была приставка вашего мода, чтобы гарантировать уникальность.
В качестве образца я буду использовать entity.vertex и entity.fragment. Для октакля мне понадобится только фрагментный шейдер, а в качестве вершинного шейдера будет entity.vertex. Поэтому, я создаю два файла — mc_octacle.shader и mc_octacle_fired.shader — для обычного октакля и для подожжённого октакля.
Начну работу над mc_octacle.shader. Как говорил знаменитый скульптор Огюст Роден «Я беру камень и отсекаю всё лишнее», так и я буду брать entity.fragment и отсекать всё лишнее:
// __multiversion__ // This signals the loading code to prepend either #version 100 or #version 300 es as apropriate. #include "fragmentVersionCentroidUV.h" #include "uniformEntityConstants.h" #include "uniformShaderConstants.h" #include "util.h" LAYOUT_BINDING(0) uniform sampler2D TEXTURE_0; LAYOUT_BINDING(1) uniform sampler2D TEXTURE_1; varying vec4 light; varying vec4 fogColor; void main() { gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0); }
Шейдер выше имеет выше всё необходимое для начала работы, но сам по себе не делает почти ничего — просто отображает на месте меша белый цвет. Функция main() вызывается каждый раз, когда видеокарте нужно вычислить цвет для пикселя. Для вывода цвета используется переменная gl_FragColor, ей нужно присвоить четырёхмерный вектор, представляющий каналы цвета rgba.
Чтобы получить цвет в конкретной точке текстуры я буду использовать texture2D. Первым параметром передаётся текстура, а вторым двухмерный вектор, представляющий собой двухмерный вектор в отрезке [0,1] по обеим осям, он нам уже дан в переменной uv. Возвращает эта функция цвет — четырёхмерный вектор rgba. Чтобы получить четвёртый параметр (то есть альфа канал) нужно получить поле w (xyzw).
void main() { vec3 col = vec3(1.0, 1.0, 1.0); // Создаю идеально белый цвет vec3 alpha = texture2D(TEXTURE_0, uv).www; // Получаю альфа-канал текстуры. col*=alpha; // Перемножаю цвет и альфа-канал для применения маски. gl_FragColor = vec4(col,alpha*light.x); // Устанавливаю точке цвет }
Здесь текстура используется как трафарет, который накладывается на полотно идеально белого цвета. Хотел бы отдельно остановится на фрагменте с перемножением цвета, и зачем это нужно. Допустим я задам кислотно зелёный цвет vec3(0.0, 1.0, 0.0) или оранжевый vec3(1.0, 1.0, 0.0). Как же получить цвет, который в два раза темнее данных? Очень просто! Просто умножить на vec3(0.5, 0.5, 0.5).
В последней строчке я создаю цвет у которого первые три канала — rgb такие же, как и у col. А что же альфа канал? Он равен альфе из текстуры, умноженной на light. light — это четырёхмерный вектор, отображающий свет и переданный из вершинного шейдера. Это нужно для того, чтобы октакль как-то реагировал на свет. Ещё, нужно объяснить почему я умножаю альфа канал, а не col. Просто потому, что так выглядит лучше. Слева пример с умножением rgb на light, а справа с умножением альфа-канала на light
Теперь займусь mc_octacle_fired.fragment. Для этого вместо идеально-белого col будет использован огненно-красный vec3(0.9, 0.5, 0.5). Так как мне не нужно учитывать освещение для горящего октакля я и не буду его учитывать:
void main() { vec3 col = vec3(0.9, 0.5, 0.5); vec3 alpha = texture2D(TEXTURE_0, uv).www; col*=alpha; gl_FragColor = vec4(col,alpha); }
На этом на сегодня всё, в следующем уроке я расскажу о подготовке ресурсов (спрайтов и материалов).
Comments