OpenGL: Создание Скайбокса

Урок показывает, как создать SkyBox. По сути это просто коробка с текстурой, создающая впечатление, что мы находимся в реальном 3д мире.
Это удобно, т.к. легко программируется и неплохо выглядит.
Используемые текстуры созданы Nick Coombe (http://www.planethalflife.com/crinity   email: crinity@email.com). Работает всё так: мы создаём коробку, и накладываем на каждую из сторон текстуру.

Исходные коды возьмите из урока «Загрузка текстур», и добавьте класс камеры из последнего урока «камера».

В файле Init.cpp найдите строку

    gluPerspective(45.0f,(GLfloat)width/(GLfloat)height, .5f ,150.0f);

 

и замените в ней значение 150.0f на 500.0f. Иначе отсекание будет происходить слишком близко:

    gluPerspective(45.0f,(GLfloat)width/(GLfloat)height, .5f ,500.0f);

 

Изменяем файл main.h для использования камеры:

// 1) Включите хидер math.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(xvVector.x, yvVector.y, zvVector.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);
}

Исходные коды к уроку

Понравилась статья? Поделиться с друзьями: