В статье будет показано как можно наложить простую текстуру на куб (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;
}