Как уже понятно из названия статьи, речь пойдет об использовании текстур в OpenGL. В прошлом уроке мы создали куб и добавили возможность вращать его вокруг осей координат. Сегодня давайте попробуем наложить текстуры на грани куба и получить некое подобие игральной кости.
Итак, возьмем за основу проект из предыдущей статьи, и для начала нужно добавить в него изображения, на базе которых впоследствии мы создадим текстуры. Я не стал особо заморачиваться, просто нарисовал по-быстрому в paint'е 6 картинок, по одной для каждой грани куба. Получилось вот так:
Тем, кто как и я, использует Qt Creator теперь необходимо добавить эти файлы в проект. Для этого нужно создать пустой файл ресурсов и прописать в нем пути для всех используемых изображений. Итак, картинки готовы, задача понятна, давайте приступать к реализации. И первым делом нам необходимо, собственно, создать текстуры из изображений. Добавим в проект функцию generateTextutes():
void MainScene::generateTextures()
{
glGenTextures(6, textures);
QImage currentTexture;
currentTexture.load(":/cubeOne.jpg");
currentTexture = QGLWidget::convertToGLFormat(currentTexture);
glBindTexture(GL_TEXTURE_2D, textures[0]);
glTexImage2D(GL_TEXTURE_2D, 0, 3, (GLsizei)currentTexture.width(), (GLsizei)currentTexture.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, currentTexture.bits());
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
// Далее генерация остальных текстур...
Я решил привести в качестве примера код для создания только одной OpenGL текстуры для одной грани. Для остальных граней все делается абсолютно также. В конце статьи я обязательно выложу полный проект с примером, и там можно будет посмотреть весь код.
Давайте разбираться, что тут происходит...
Первым делом вызываем функцию glGenTextures() - она генерирует специальные имена для каждой из текстур и помещает их в массив, который мы передаем в качестве одного из аргументов. А первый аргумент - количество текстур, которые нам понадобятся (в данном случае у нас 6 граней, значит передаем в функцию аргумент "6"). Эта функция вызывается только один раз, в самом начале функции generateTextures(). И, кстати, не забудьте объявить массив в нашем классе MainScene:
GLuint textures[6];
С этим все понятно, переходим дальше. Теперь мы создаем объект класса QImage и загружаем в него наше изображение. Функция glBindTexture() делает активной текстуру с номером, соответствующим аргументу функции. В данном случае это текстура для первой грани (textures[0]). Вызовом этой функции мы как бы показываем OpenGL, что дальнейшие действия нужно производить именно с той текстурой, которую мы выбрали. Поэтому вызов glTexImage2D() произведет генерацию текстуры, соответствующей номеру textures[0] (напоминаю, в этом массиве у нас хранятся уникальные номера-идентификаторы для каждой из текстур проекта).
Функция glTexImage2D() принимает на вход кучу аргументов, так что давайте рассмотрим каждый из них в отдельности:
- первый параметр говорит о том, что мы будем работать с 2D текстурой
- второй параметр - уровень детализации, у нас 0
- третий - 3 - число цветовых компонент - RGB
- четвертый, пятый - ширина и высота текстуры, у нас они определяются автоматически
- пятый - относится к границе текстуры, его просто оставляем нулевым
- шестой, седьмой - дают OpenGL информацию о цветах и типе данных исходного изображения
- и, наконец, седьмой параметр передает OpenGL сами данные изображения, из которых нужно формировать текстуру.
На этом создание текстуры заканчивается, но нужно еще настро
