UV текстурирование куба
В статье будет показано как можно наложить простую текстуру на куб (box).
В программировании графики часто используется uv текстурирование. Когда текстура накладывается по координатам на вершины модели. Это работает с разомкнутыми моделями. Но при наложении на замкнутые вроде куба (или цилиндра) возникает проблема. Одна и та же вершина используется для разных плоскостей. И не всегда возможно наложить текстуру как хотелось бы. Можно конечно добавить вершин, и сделать их независимыми, но это лишний расход памяти, и другие проблемы.
Сразу покажу конечный результат. Текстура наложена на куб (box), и со всех сторон выглядит корректно. Но это сработает только для простой текстуры, которая допускает отражение по диагонали (вроде бетона, кирпича). Либо если достаточно только 4 сторон (кроме верха и низа например). Здесь графическая API (в моём случае OpenGl) получает всего 8 вершин с uv координатами каждая. Без каких-либо хитростей вроде геометрических шейдеров (которые требуют дополнительных операций) и т.д. Т.е. это будет эффективно.

Далее переходим к мат части. Вся информация на рисунке ниже.

Сверху это условно текстура. Координаты нижнего левого угла (0, 0), правого верхнего (1, 1) . Эти координаты присваиваются вершинам куба. На рисунке все возможные варианты (вроде). Их всего 8. Мы оставим нижнюю плоскость XY с корректными координатами как в текстуре. И не будет её трогать больше. Будет вращать верхнюю плоскость. Когда точка (0, 0) оказывается в следующей позиции, то пробуем 2 варианта: прямого и зеркального (по диагонали) наложения.
Мы видим что образуются грани (треугольника) с совпадающими координатами текстуры. Они отмечены красным — это значит что тут точно текстуры никакой не будет, развёртка будет некорректной. Жёлтым отмечены диагональные грани текстуры, которые наложение вертикально — так тоже не пойдёт. Видим что наиболее корректными оказываются 3 и 5 варианты. Но даже у них, полностью корректны только верхняя и нижняя части. Стороны же имеют только 1 половинку текстуры отражённую по диагонали.
Есть ещё 2 варианта: 4 и 6. У них 4 стороны полностью корректны, но 2 боковые стороны не будут иметь никакой текстуры. Но этот вариант тоже может пригодится — например когда они скрыты, и нам нужны только 4 стороны.
При создании куба, в 3 и 5 вариантах, важно также верно построить боковые стороны. Чтобы треугольники были по правильной диагонали. Это влияет на координаты их текстур. Если нужен более точный пример, то вариант 3, в коде на C++ может выглядит так. Создаём массив вершин, затем массив индексов:
vector<vec3> MakeBox(vec3 a, vec3 b)
{ vector<vec3> aVertex =
{ // Низ.
{a.x, a.y, a.z}, {b.x, a.y, a.z}, {a.x, b.y, a.z}, {b.x, b.y, a.z},
// Верх.
{a.x, a.y, b.z}, {b.x, a.y, b.z}, {a.x, b.y, b.z}, {b.x, b.y, b.z}
};
return aVertex;
}
vector<int> GetBoxIndex()
{ vector<int> aIndex =
{ 0, 3, 1, 0, 2, 3, // Низ.
4, 5, 7, 4, 7, 6, // Верх.
0, 1, 4, 1, 5, 4, // Сзади.
2, 7, 3, 2, 6, 7, // Спереди.
0, 6, 2, 0, 4, 6, // Лево.
1, 3, 5, 3, 7, 5, // Право.
};
return aIndex;
}