Урок показывает, как создать SkyBox. По сути это просто коробка с текстурой, создающая впечатление, что мы находимся в реальном 3д мире.
Это удобно, т.к. легко программируется и неплохо выглядит.
Используемые текстуры созданы Nick Coombe (http://www.planethalflife.com/crinity email: crinity@email.com). Работает всё так: мы создаём коробку, и накладываем на каждую из сторон текстуру.
Исходные коды возьмите из урока «Загрузка текстур», и добавьте класс камеры из последнего урока «камера».
В файле Init.cpp найдите строку
и замените в ней значение 150.0f на 500.0f. Иначе отсекание будет происходить слишком близко:
Изменяем файл main.h для использования камеры:
#include <math.h>// 2) Перенесите из уроков камеры класс CVector3:
class CVector3 {public:
// Дефолтный конструктор
CVector3() {}// Конструктор, инициализирующий данные
CVector3(float X, float Y, float Z)
{
x = X; y = Y; z = Z;
}
// Перегружаем оператор +, чтобы прибавлять друг к другу векторы
CVector3 operator+(CVector3 vVector)
{
// Возвращаем +добавленный вектор
return CVector3(vVector.x + x, vVector.y + y, vVector.z + z);
}
// перегружаем оператор —
CVector3 operator—(CVector3 vVector)
{
return CVector3(x—vVector.x, y—vVector.y, z—vVector.z);
}
// Перегружаем оператор *
CVector3 operator*(float num)
{
return CVector3(x*num, y*num, z*num);
}
// Перегружаем оператор /
CVector3 operator/(float num)
{
return CVector3(x/num,y/num,z/num);
}
float x, y, z; // Просто float для X,Y,Z
};
С этим всё.
Изменяем файл main.cpp:
#include «main.h»
#include «camera.h»
#include «texture.h»// Установим скорость движения камеры
#define SPEED 0.03f// Чтобы не запутаться, обозначим ID текстур сторонами куба#define BACK_ID 1 // ID текстуры для задней части бокса
#define FRONT_ID 2 // Для передней части
#define BOTTOM_ID 3 // Для нижней части
#define TOP_ID 4 // Для верхней части
#define LEFT_ID 5 // Для левой части
#define RIGHT_ID 6 // Для правой части
// Установим количество загружаемых текстур в 6:
TextureImage textures[6] = {0};
// Вместе с обьявлением класса текстур, обьявим класс камеры:
CCamera g_Camera; // Наша камера
CTexture *Texture; // Текстурный класс
// Изменим функцию инициализации: инициализируем камеру и загрузим наши текстуры
void Init(HWND hWnd)
{
g_hWnd = hWnd;
GetClientRect(g_hWnd, &g_rRect);
InitializeOpenGL(g_rRect.right, g_rRect.bottom);
// Инициализируем текстурный класс
Texture = new CTexture();
// Ниже мы читаем 6 текстурных карт для сторон нашего скайбокса.
// ID важны, так что не перепутайте их. У нас есть текстуры для
// каждой стороны бокса.
Texture->LoadTexture(IL_BMP, «Back.bmp», &textures[BACK_ID]);
Texture->LoadTexture(IL_BMP, «Front.bmp», &textures[FRONT_ID]);
Texture->LoadTexture(IL_BMP, «Bottom.bmp», &textures[BOTTOM_ID]);
Texture->LoadTexture(IL_BMP, «Top.bmp», &textures[TOP_ID]);
Texture->LoadTexture(IL_BMP, «Left.bmp», &textures[LEFT_ID]);
Texture->LoadTexture(IL_BMP, «Right.bmp», &textures[RIGHT_ID]);
// Дадим камере стартовую точку в мире.
g_Camera.PositionCamera( 0, 0, 0, 0, 0, 1, 0, 1, 0);
}
///////////////////////////////// CREATE SKY BOX \\\\*
///// Новая функция!
/////
///// Создает SkyBox с центром в X,Y,Z. Вместо окраски каждой вершины применяется
///// карта текстур для каждой стороны куба. Вы можете задавать ширину, высоту
///// и длинну скайбокса, чтобы создать разные перспективы для разных
///// текстур.
/////
///////////////////////////////// CREATE SKY BOX \\\\*
void CreateSkyBox(float x, float y, float z, float width, float height, float length)
{
// Это самая важная функция в этом уроке. Мы накладываем на каждую сторону текстуру,
// чтобы создать иллюзию 3д мира. Вы заметите, что я изменил текстурные
// координаты, чтобы стороны корректно выглядели. Также, в зависимости от
// ситуации, вершины могут быть перевернуты. В этом уроке такого не будет,
// но имейте в виду такую возможность.
// Так как мы хотим, чтобы скайбокс был с центром в x-y-z, мы производим
// небольшие рассчеты. Просто изменяем X,Y и Z на нужные.
// Это центрирует скайбокс на X,Y,Z
x = x — width / 2;
y = y — height / 2;
z = z — length / 2;
// забиндим заднюю текстуру на заднюю сторону
glBindTexture(GL_TEXTURE_2D, textures[BACK_ID].texID);
glBegin(GL_QUADS);
// Установим текстурные координаты и вершины ЗАДНЕЙ стороны
glTexCoord2f(1.0f, 0.0f); glVertex3f(x + width, y,z);
glTexCoord2f(1.0f, 1.0f); glVertex3f(x + width, y + height, z);
glTexCoord2f(0.0f, 1.0f); glVertex3f(x, y + height, z);
glTexCoord2f(0.0f, 0.0f); glVertex3f(x, y,z);
glEnd();
// Биндим ПЕРЕДНЮЮ текстуру на ПЕРЕДНЮЮ сторону бокса
glBindTexture(GL_TEXTURE_2D, textures[FRONT_ID].texID);
// Начинаем рисовать сторону
glBegin(GL_QUADS);
// Установим текстурные координаты и вершины ПЕРЕДНЕЙ стороны
glTexCoord2f(1.0f, 0.0f); glVertex3f(x, y, z + length);
glTexCoord2f(1.0f, 1.0f); glVertex3f(x, y + height, z + length);
glTexCoord2f(0.0f, 1.0f); glVertex3f(x + width, y + height, z + length);
glTexCoord2f(0.0f, 0.0f); glVertex3f(x + width, y,z + length);
glEnd();
// Биндим НИЖНЮЮ текстуру на НИЖНЮЮ сторону бокса
glBindTexture(GL_TEXTURE_2D, textures[BOTTOM_ID].texID);
// Начинаем рисовать сторону
glBegin(GL_QUADS);
// Установим текстурные координаты и вершины НИЖНЕЙ стороны
glTexCoord2f(1.0f, 0.0f); glVertex3f(x, y,z);
glTexCoord2f(1.0f, 1.0f); glVertex3f(x, y,z + length);
glTexCoord2f(0.0f, 1.0f); glVertex3f(x + width, y,z + length);
glTexCoord2f(0.0f, 0.0f); glVertex3f(x + width, y,z);
glEnd();
// Биндим ВЕРХНЮЮ текстуру на ВЕРХНЮЮ сторону бокса
glBindTexture(GL_TEXTURE_2D, textures[TOP_ID].texID);
// Начинаем рисовать сторону
glBegin(GL_QUADS);
// Установим текстурные координаты и вершины ВЕРХНЕЙ стороны
glTexCoord2f(0.0f, 1.0f); glVertex3f(x + width, y + height, z);
glTexCoord2f(0.0f, 0.0f); glVertex3f(x + width, y + height, z + length);
glTexCoord2f(1.0f, 0.0f); glVertex3f(x, y + height,z + length);
glTexCoord2f(1.0f, 1.0f); glVertex3f(x, y + height,z);
glEnd();
// Биндим ЛЕВУЮ текстуру на ЛЕВУЮ сторону бокса
glBindTexture(GL_TEXTURE_2D, textures[LEFT_ID].texID);
// Начинаем рисовать сторону
glBegin(GL_QUADS);
// Установим текстурные координаты и вершины ЛЕВОЙ стороны
glTexCoord2f(1.0f, 1.0f); glVertex3f(x, y + height,z);
glTexCoord2f(0.0f, 1.0f); glVertex3f(x, y + height,z + length);
glTexCoord2f(0.0f, 0.0f); glVertex3f(x, y,z + length);
glTexCoord2f(1.0f, 0.0f); glVertex3f(x, y,z);
glEnd();
// Биндим ПРАВУЮ текстуру на ПРАВУЮ сторону бокса
glBindTexture(GL_TEXTURE_2D, textures[RIGHT_ID].texID);
// Начинаем рисовать сторону
glBegin(GL_QUADS);
// Установим текстурные координаты и вершины ПРАВОЙ стороны
glTexCoord2f(0.0f, 0.0f); glVertex3f(x + width, y,z);
glTexCoord2f(1.0f, 0.0f); glVertex3f(x + width, y,z + length);
glTexCoord2f(1.0f, 1.0f); glVertex3f(x + width, y + height,z + length);
glTexCoord2f(0.0f, 1.0f); glVertex3f(x + width, y + height,z);
glEnd();
}
///////////////////////////////////
// В MainLoop() перед RenderScene() добавьте обновление камеры:
g_Camera.Update(); // Обновим данные камеры
RenderScene();
///////////////////////////////////
// И наконец RenderScene(). Код её совсем мал, так как вынесен в отдельные функции:
void RenderScene()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
// Передадим OpenGL позицию камеры
g_Camera.Look();
// Создаем наш скайбокс. Он будет с центром в (0,0,0), с шириной 400,
// высотой 200, и длинной 400. Вы можете удивится, почему бы не сделать
// ровный куб? Ну, если мы делаем высоту половиной ширины и длинны,
// всё выглядит лучше. Попробуйте увеличить высоту до 400 и
// вы заметите, что всё стало выглядеть хуже. Скайбокс выглядит
// лучше с разными перспективами и размерами.
CreateSkyBox(0, 0, 0, 400, 200, 400);
SwapBuffers(g_hDC);
}