netlib.narod.ru< Назад | Оглавление | Далее >

Использование небесного куба

Небесный куб (sky box) — это графическая техника, в которой текстурированный трехмерный куб окружает зрителя. При визуализации небесного куба его центр всегда располагается в точке местоположения зрителя, чтобы пользователь видел внутренние текстурированные грани куба. Данная техника позволяет имитировать мир, окружающий пользователя (рис. 8.10).


Рис. 8.10. Небесный куб создает у зрителя иллюзию, что его окружает огромный мир

Рис. 8.10. Небесный куб создает у зрителя иллюзию, что его окружает огромный мир


Реализовать небесный куб просто. Вам нужна только сетка куба (у которой грани обращены внутрь). Для хранения сетки куба замечательно подойдет буфер вершин. Что касается текстур, то их вам потребуется шесть — по одной для каждой стороны. Сетка не должна быть очень большой, достаточно куба с размером стороны 20.0 единиц. Размер текстур должен быть 256 × 256 или больше, поскольку меньшие будут выглядеть растянутыми и некрасивыми.

Создание класса небесного куба

Лучший способ реализации небесного куба в вашей игре — создание класса, который легко можно включать в собственные проекты. Этот класс, в нашем случае названный cSkyBox, управляет каждым аспектом небесного куба — от создания буфера вершин, содержащего данные куба, до хранения используемых при визуализации текстур. Приведенный ниже код класса небесного куба очень компактен и будет хорошим дополнением к любой игровой библиотеке:

class cSkyBox
{
  private:
    typedef struct sSkyBoxVertex {
        float x, y, z;
        float u, v;
    } sSkyBoxVertex;
    #define SkyBoxFVF (D3DFVF_XYZ | D3DFVF_TEX1)

    cGraphics *m_Graphics;  // Родительский объект cGraphics
    cTexture m_Textures[6]; // Текстуры граней (0-5)
    cVertexBuffer m_VB;     // Буфер вершин сетки
    cWorldPosition m_Pos;   // Ориентация небесного куба

  public:
    cSkyBox();  // Конструктор
    ~cSkyBox(); // Деструктор

    // Создание и освобождение объекта класса небесного куба
    BOOL Create(cGraphics *Graphics);
    BOOL Free();

    // Установка текстуры для заданной грани. Позволяет
    // использовать прозрачность и менять формат хранения
    BOOL LoadTexture(short Side, char *Filename,
                     D3DCOLOR Transparent = 0,
                     D3DFORMAT = D3DFMT_UNKNOWN);

    // Абсолютное и относительное вращение куба
    BOOL Rotate(float XRot, float YRot, float ZRot);
    BOOL RotateRel(float XRot, float YRot, float ZRot);

    // Визуализация небесного куба (с необязательным
    // альфа-смешиванием) с использованием текущего
    // преобразования вида из Camera.
    BOOL Render(cCamera *Camera, BOOL Alpha = FALSE);
};

В последующих разделах мы подробно рассмотрим каждую функцию из приведенного кода.

cSkyBox::Create и cSkyBox::Free

Этот дуэт функций вы используете для получения родительского объекта графической системы, создания сетки небесного куба и освобождения всех используемых объектов cTexture. Взгляните на код:

BOOL cSkyBox::Create(cGraphics *Graphics)
{
    sSkyBoxVertex Verts[24] = {
        { -10.0f,  10.0f, -10.0f, 0.0f, 0.0f }, // Верхние вершины
        {  10.0f,  10.0f, -10.0f, 1.0f, 0.0f },
        { -10.0f,  10.0f,  10.0f, 0.0f, 1.0f },
        {  10.0f,  10.0f,  10.0f, 1.0f, 1.0f },
        { -10.0f, -10.0f,  10.0f, 0.0f, 0.0f }, // Нижние вершины
        {  10.0f, -10.0f,  10.0f, 1.0f, 0.0f },
        { -10.0f, -10.0f, -10.0f, 0.0f, 1.0f },
        {  10.0f, -10.0f, -10.0f, 1.0f, 1.0f },
        { -10.0f,  10.0f, -10.0f, 0.0f, 0.0f }, // Левые вершины
        { -10.0f,  10.0f,  10.0f, 1.0f, 0.0f },
        { -10.0f, -10.0f, -10.0f, 0.0f, 1.0f },
        { -10.0f, -10.0f,  10.0f, 1.0f, 1.0f },
        {  10.0f,  10.0f,  10.0f, 0.0f, 0.0f }, // Правые вершины
        {  10.0f,  10.0f, -10.0f, 1.0f, 0.0f },
        {  10.0f, -10.0f,  10.0f, 0.0f, 1.0f },
        {  10.0f, -10.0f, -10.0f, 1.0f, 1.0f },
        { -10.0f,  10.0f,  10.0f, 0.0f, 0.0f }, // Передние вершины
        {  10.0f,  10.0f,  10.0f, 1.0f, 0.0f },
        { -10.0f, -10.0f,  10.0f, 0.0f, 1.0f },
        {  10.0f, -10.0f,  10.0f, 1.0f, 1.0f },
        {  10.0f,  10.0f, -10.0f, 0.0f, 0.0f }, // Задние вершины
        { -10.0f,  10.0f, -10.0f, 1.0f, 0.0f },
        {  10.0f, -10.0f, -10.0f, 0.0f, 1.0f },
        { -10.0f, -10.0f, -10.0f, 1.0f, 1.0f },
    };

    Free(); // Освобождаем предыдущий небесный куб

    // Проверка ошибок
    if((m_Graphics = Graphics) == NULL)
        return FALSE;

    // Создаем буфер вершин
    // (и копируем в него вершины небесного куба)
    if(m_VB.Create(m_Graphics, 24, SkyBoxFVF,
                   sizeof(sSkyBoxVertex)) == TRUE)
        m_VB.Set(0, 24, (void*)&Verts);

    // Поворачиваем небесный куб в положение по умолчанию
    Rotate(0.0f, 0.0f, 0.0f);

    return TRUE; // Возвращаем флаг успеха!
}

BOOL cSkyBox::Free()
{
    m_Graphics = NULL; // Очищаем родительский объект cGraphics

    for(short i = 0; i < 6; i++) // Освобождаем текстуры
        m_Textures[i].Free();

    m_VB.Free(); // Освобождаем буфер вершин

    return TRUE; // Возвращаем флаг успеха!
}

Как видите, названия функций соответствуют их сути. Сначала Create создает буфер вершин (для сетки куба с 12 гранями и 6 сторонами). Этот буфер вершин заполняется информацией, заданной внутри функции Create. После создания буфера вершин функция Create продолжает работу, и задает ориентацию сетки небесного куба, устанавливая ее в положение по умолчанию.

Используя вращение, вы можете создавать слои из небесных кубов для реализации трехмерных эффектов. Например, представьте себе слоеный пирог из нескольких небесных кубов — один со звездами, другой с облаками, третий с солнцем и луной — и так вы создаете законченное вращающееся небо со следующими по своим орбитам солнцем и луной!

Закончив с функцией Create, я перехожу к функции Free. Она освобождает ресурсы текстур и буфер вершин, используя функции Free соответствующих объектов.

cSkyBox::LoadTexture

Показанная ниже функция LoadTexture загружает единственную текстуру, которая будет использоваться для текстурирования одной стороны небесного куба.

BOOL cSkyBox::LoadTexture(short Side, char *Filename,
                          D3DCOLOR Transparent, D3DFORMAT Format)
{
    // Проверка ошибок
    if(m_Graphics == NULL || Side < 0 || Side > 5)
        return FALSE;

    m_Textures[Side].Free(); // Освобождаем предыдущую текстуру

    return m_Textures[Side].Load(m_Graphics, Filename,
                                 Transparent, Format);
}

Функция LoadTexture загружает одно растровое изображение в указанную текстуру (используя заданные прозрачный цвет и формат хранения, если вы намереваетесь применять копирование с учетом прозрачности или альфа-смешивание). Следует обратить внимание на нумерацию граней небесного куба. Соответствие номеров и граней приведено в таблице 8.2.


Таблица 8.2. Номера граней для cSkyBox::LoadTexture



Значение Грань

0 Верхняя
1 Нижняя
2 Левая
3 Правая
4 Передняя
5 Задняя

cSkyBox::Rotate и cSkyBox::RotateRel

Вы уже узнали, что небесные кубы могут вращаться, создавая иллюзию, что небесные объекты движутся по орбитам вокруг зрителя. Рассматриваемые две функции позволяют менять поворот небесных кубов:

BOOL cSkyBox::Rotate(float XRot, float YRot, float ZRot)
{
    return m_Pos.Rotate(XRot, YRot, ZRot);
}

BOOL cSkyBox::RotateRel(float XRot, float YRot, float ZRot)
{
    return m_Pos.RotateRel(XRot, YRot, ZRot);
}

Чтобы изменить значения вращения эти две функции вызывают методы класса cWorldPosition графического ядра (дополнительную информацию об объекте cWorldPosition вы найдете в главе 6, «Создаем ядро игры»).

cSkyBox::Render

Вот и действительно важная функция. Она центрирует небесный куб относительно указанной камеры, включает альфа-смешивание и альфа-проверку (если необходимо) и визуализирует шесть сторон небесного куба (или как минимум те из них, которые текстурированы):

BOOL cSkyBox::Render(cCamera *Camera, BOOL Alpha)
{
    D3DXMATRIX matWorld;
    short      i;

    // Проверка ошибок
    if(m_Graphics == NULL || Camera == NULL)
        return FALSE;

    // Располагаем небесный куб вокруг зрителя
    m_Pos.Move(Camera->GetXPos(),
               Camera->GetYPos(),
               Camera->GetZPos());
    m_Graphics->SetWorldPosition(&m_Pos);

    // Включаем альфа-проверку и альфа-смешивание
    m_Graphics->EnableAlphaTesting(TRUE);
    if(Alpha == TRUE)
        m_Graphics->EnableAlphaBlending(TRUE, D3DBLEND_SRCCOLOR,
                                        D3DBLEND_DESTCOLOR);

    // Рисуем каждый слой
    for(i = 0; i < 6; i++) {
        if(m_Textures[i].IsLoaded() == TRUE) {
            m_Graphics->SetTexture(0, &m_Textures[i]);
            m_VB.Render(i*4, 2, D3DPT_TRIANGLESTRIP);
        }
    }

    // Отключаем альфа-проверку и альфа-смешивание
    m_Graphics->EnableAlphaTesting(FALSE);
    if(Alpha == TRUE)
        m_Graphics->EnableAlphaBlending(FALSE);

    return TRUE;
}

При вызове функции Render вы должны передать ей текущий объект cCamera, который используется для визуализации сцены. Необязательному аргументу Alpha вы можете присвоить значение TRUE, чтобы функция Render визуализировала небесный куб с использованием техники альфа-смешивания.

Использование класса небесного куба

Теперь пора посмотреть небесный куб в действии. Вообще-то, если вы уже смотрели пример NodeTree, то видели небесный куб. В этом примере для небесного куба используется единственная текстура (звезды). Хотя я и использовал такой простой пример, в небесном кубе можно применять до шести текстур, что позволяет создавать изумительно выглядящие трехмерные сцены.


netlib.narod.ru< Назад | Оглавление | Далее >

Сайт управляется системой uCoz