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

Анимация текстуры

В этой главе вы узнали, как различными методами накладывать текстуры на сетки. Мы также обсудили декалы и прозрачность текстур. Теперь пришло время поговорить об анимации текстур.

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

Для анимации единственной текстуры есть масса возможностей. Чтобы модифицировать способ наложения текстуры на сетку можно изменять масштаб текстуры, начало координат, метод наложения и даже параметры прозрачности. Наиболее простой способ для перемещения текстуры по сетке — изменение начала координат текстуры.

Приложение TextureDrift

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


Рис. 5.10. Приложение TextureDrift

Рис. 5.10. Приложение TextureDrift


Приложение TextureDrift демонстрирует следующие технологии:

В приложении TextureDrift используется техника, которая слегка отличается от той, которая применялась в рассмотренных ранее приложениях. Ранее для создания и отображения сеток использовался интерфейс Direct3DRMMeshBuilder (за исключением приложения Decal в котором вообще не использовались сетки). В приложении TextureDrift интерфейс Direct3DRMMeshBuilder применяется для создания сетки, но не для ее отображения. Вместо этого интерфейс Direct3DRMMeshBuilder используется для создания экземпляра интерфейса Direct3DRMMesh. Это делается из-за соображений быстродействия. В главе 3 говорилось, что всякий раз, когда выполняется модификация параметров сетки, экземпляр интерфейса Direct3DRMMeshBuilder создает внутри себя экземпляр интерфейса Direct3DRMMesh. Чтобы приложение TextureDrift не выполняло лишней работы, мы используем интерфейс Direct3DRMMesh непосредственно.

Это не означает, что предыдущие приложения были плохо спроектированы. Если во время работы приложения не выполняется частой модификации параметров сеток, интерфейс Direct3DRMMeshBuilder обеспечивает хорошее быстродействие. В приложении TextureDrift мы применили интерфейс Direct3DRMMesh из-за того, что характеристики сетки меняются при каждом обновлении экрана.

Класс TextureDriftWin

Все возможности приложения TextureDrift реализованы в классе TextureDriftWin. Определение класса выглядит следующим образом:

class TextureDriftWin : public RMWin
{
public:
    BOOL CreateScene();
    static void MoveTexture(LPDIRECT3DRMFRAME frame,
        void* arg, D3DVALUE delta);
protected:
    //{{AFX_MSG(TextureDriftWin)
    //}}AFX_MSG
    DECLARE_MESSAGE_MAP()
};

В классе объявлены две функции: CreateScene() и MoveTexture(). Функция CreateScene() создает сцену для приложения, а функция MoveTexture() является функцией обратного вызова, используемой для выполнения анимации текстуры.

Часть кода после ключевого слова protected будет использоваться, если в дальнейшем вы захотите добавить к приложению обработчики событий с помощью мастера ClassWizard.

Функция TextureDriftWin::CreateScene()

Функция TextureDriftWin::CreateScene() создает одну сетку и одну текстуру. Текстура связывается с сеткой, но наложения текстуры не выполняется. При каждом обновлении экрана функция обратного вызова генерирует новое наложение текстуры. Текст функции CreateScene() представлен в листинге 5.5.

Листинг 5.5. Функция TextureDriftWin::CreateScene()

BOOL TextureDriftWin::CreateScene()
{
    //------ КОНСТРУКТОР СЕТОК ------
    D3DRMLOADRESOURCE resinfo;
    resinfo.hModule = NULL;
    resinfo.lpName = MAKEINTRESOURCE(IDR_D3DMESH);
    resinfo.lpType = "MESH";
    LPDIRECT3DRMMESHBUILDER meshbuilder;
    d3drm->CreateMeshBuilder(&meshbuilder);
    meshbuilder->Load(&resinfo, NULL, D3DRMLOAD_FROMRESOURCE, NULL,
        NULL);
    meshbuilder->Scale(D3DVALUE(1), D3DVALUE(1), D3DVALUE(.5));
    ScaleMesh(meshbuilder, D3DVALUE(35));
    meshbuilder->SetPerspective(TRUE);

    //------- ТЕКСТУРА ------
    HRSRC texture_id = FindResource(NULL, MAKEINTRESOURCE(
        IDR_TEXTURE), "TEXTURE");
    LPDIRECT3DRMTEXTURE texture;
    d3drm->LoadTextureFromResource(texture_id, &texture);
    meshbuilder->SetTexture(texture);
    texture->Release();
    texture = 0;

    //-------- СЕТКА --------
    LPDIRECT3DRMMESH mesh;
    meshbuilder->CreateMesh(&mesh);
    meshbuilder->Release();
    meshbuilder = 0;

    //-------- ФРЕЙМ СЕТКИ --------
    LPDIRECT3DRMFRAME meshframe;
    d3drm->CreateFrame(scene, &meshframe);
    meshframe->SetOrientation(scene,
            D3DVALUE(0), D3DVALUE(-1), D3DVALUE(1),
            D3DVALUE(0), D3DVALUE(1), D3DVALUE(0));
    meshframe->AddVisual(mesh);
    meshframe->AddMoveCallback(MoveTexture, NULL);
    meshframe->Release();
    meshframe = 0;
    mesh->Release();
    mesh = 0;

    //-------- СВЕТ ----------
    LPDIRECT3DRMLIGHT light;
    d3drm->CreateLightRGB(D3DRMLIGHT_AMBIENT,
            D3DVALUE(1),D3DVALUE(1), D3DVALUE(1),
            &light);
    scene->AddLight(light);
    light->Release();
    light = 0;

    //-------- ПОРТ ПРОСМОТРА ----------
    d3drm->CreateFrame(scene, &camera);
    camera->SetPosition(scene,
            D3DVALUE(0.0), D3DVALUE(0.0), D3DVALUE(-50.0));
    d3drm->CreateViewport(device, camera, 0, 0,
            device->GetWidth(), device->GetHeight(),
            &viewport);

    return TRUE;
}

Функция CreateScene() выполняет следующие действия:

  1. Создание сетки с использованием интерфейса Direct3DRMMeshBuilder.
  2. Создание текстуры для сетки.
  3. Создание интерфейса Direct3DRMMesh.
  4. Создание фрейма для сетки.
  5. Создание источника света.
  6. Создание порта просмотра.

Сначала для загрузки сетки из ресурсов приложения используется интерфейс Direct3DRMMeshBuilder:

D3DRMLOADRESOURCE resinfo;
resinfo.hModule = NULL;
resinfo.lpName = MAKEINTRESOURCE(IDR_D3DMESH);
resinfo.lpType = "MESH";
LPDIRECT3DRMMESHBUILDER meshbuilder;
d3drm->CreateMeshBuilder(&meshbuilder);
meshbuilder->Load(&resinfo, NULL, D3DRMLOAD_FROMRESOURCE,
    NULL, NULL);
meshbuilder->Scale(D3DVALUE(1), D3DVALUE(1), D3DVALUE(.5));
ScaleMesh(meshbuilder, D3DVALUE(35));
meshbuilder->SetPerspective(TRUE);

Обратите внимание, что после загрузки сетки мы используем функцию Scale() интерфейса Direct3DRMMeshBuilder для уменьшения размера сетки по оси Z. Мы передаем функции Scale() в качестве аргумента Z значение 0.5, чтобы вдвое уменьшить размер сетки по оси Z. После вызова функции Scale() используется функция ScaleMesh() для масштабирования сетки таким образом, чтобы ее максимальный размер равнялся 35 единицам. Функция SetPerspective() вызывается чтобы разрешить перспективную коррекцию.

Затем создается текстура:

HRSRC texture_id = FindResource(NULL, MAKEINTRESOURCE(IDR_TEXTURE),
    "TEXTURE");
LPDIRECT3DRMTEXTURE texture;
d3drm->LoadTextureFromResource(texture_id, &texture);
meshbuilder->SetTexture(texture);
texture->Release();
texture = 0;

Новая текстура привязывается к ранее созданному конструктору сеток с помощью функции SetTexture(), но наложение текстуры не создается. Потом существующий конструктор сеток применяется для создания экземпляра интерфейса Direct3DRMMesh:

LPDIRECT3DRMMESH mesh;
meshbuilder->CreateMesh(&mesh);
meshbuilder->Release();
meshbuilder = 0;

После вызова функции CreateMesh() конструктор сеток нам больше не нужен, поэтому указатель на него освобождается.

Теперь настала пора создать фрейм и присоединить к нему сетку:

LPDIRECT3DRMFRAME meshframe;
d3drm->CreateFrame(scene, &meshframe);
meshframe->SetOrientation(scene,
        D3DVALUE(0), D3DVALUE(-1), D3DVALUE(1),
        D3DVALUE(0), D3DVALUE(1), D3DVALUE(0));
meshframe->AddVisual(mesh);
meshframe->AddMoveCallback(MoveTexture, NULL);
meshframe->Release();
meshframe = 0;
mesh->Release();
mesh = 0;

Новый фрейм ориентируется таким образом, чтобы сетка была расположена под углом 45 градусов к порту просмотра, после чего для присоединения сетки к фрейму вызывается функция AddVisual(). Функция обратного вызова MoveTexture(), которая будет анимировать текстуру, устанавливается с помощью функции AddMoveCallback().

Обратите внимание, что указатель mesh освобождается. Ранее в функции мы уже освободили указатели meshbuilder и texture, а значит у нас больше не осталось никаких указателей на графические объекты. Это затруднило бы установку новых параметров наложения текстуры, если бы не существовало способа получить визуальные объекты фрейма. Мы увидим как это делается при обсуждении функции обратного вызова MoveTexture().

На пятом и шестом этапах для сцены создаются источник света и порт просмотра.

Функция TextureDriftWin::MoveTexture()

MoveTexture() — это функция обратного вызова, которая при каждом вызове создает и применяет новое наложение текстуры. В самом начале функции должен быть получен интерфейс Direct3DRMMesh, который был добавлен к фрейму в функции CreateScene(). Код функции MoveTexture() показан в листинге 5.6.

Листинг 5.6. Функция TextureDriftWin::MoveTexture()

void TextureDriftWin::MoveTexture(LPDIRECT3DRMFRAME frame,
    void*, D3DVALUE)
{
    static D3DVALUE xtex;
    xtex += D3DVALUE(.02);

    LPDIRECT3DRMVISUALARRAY visualarray;
    frame->GetVisuals(&visualarray);
    int nvisuals = visualarray->GetSize();
    for ( int i = 0; i < nvisuals; i++ )
    {
        LPDIRECT3DRMVISUAL visual;
        visualarray->GetElement(i, &visual);
        LPDIRECT3DRMMESH mesh;
        if (visual->QueryInterface(IID_IDirect3DRMMesh,
            (void**)&mesh) == 0)
        {
            D3DRMBOX box;
            mesh->GetBox(&box);
            D3DVALUE w = box.max.x - box.min.x;
            D3DVALUE h = box.max.y - box.min.y;

            LPDIRECT3DRMWRAP wrap;
            d3drm->CreateWrap(D3DRMWRAP_FLAT, NULL,
              D3DVALUE(0.0), D3DVALUE(0.0), D3DVALUE(0.0),
              D3DVALUE(0.0), D3DVALUE(0.0), D3DVALUE(1.0),
              D3DVALUE(0.0), D3DVALUE(1.0), D3DVALUE(0.0),
              xtex, D3DVALUE(0.5),             // начало координат текстуры
              D3DDivide(1,w), D3DDivide(1,h),  // масштаб текстуры
              &wrap);
            wrap->Apply(mesh);
            wrap->Release();
            wrap = 0;
            mesh->Release();
            mesh = 0;
        }
        visual->Release();
        visual = 0;
    }
    visualarray->Release();
    visualarray = 0;
}

В начале функции MoveTexture() объявляется статическая переменная типа D3DVALUE, которая увеличивается при каждом вызове функции. Значение этой переменной используется как значение координаты X для начала координат текстуры, поэтому увеличение этого значения вызывает эффект перемещения текстуры по сетке.

Затем, для получения массива присоединенных к фрейму визуальных объектов, используется функция GetVisuals() интерфейса Direct3DRMFrame (Direct3D передает указатель frame в первом параметре функции обратного вызова).

Функция GetVisuals() инициализирует указатель на интерфейс Direct3DRMVisualArray. Этот интерфейс поддерживает всего лишь две функции: GetSize() и GetElement().

Для перебора элементов массива визуальных объектов применяется цикл. С помощью функции GetSize() мы определяем количество элементов в массиве, а для получения отдельного элемента используется функция GetElement(). Возвращаемый функцией указатель является указателем на интерфейс Direct3DRMVisual (который не предоставляет никаких функций). Чтобы узнать, поддерживает ли объект интерфейс Direct3DRMMesh, используется функция QueryInterface(). Мы знаем что один и только один из объектов, возвращаемых функцией GetElement() поддерживает интерфейс Direct3DRMMesh, поскольку в функции CreateScene() мы создали и присоединили к данному фрейму только одну сетку.

После получения указателя на интерфейс Direct3DRMMesh создается и применяется к сетке интерфейс Direct3DRMWrap.

Приложение ShowRoom

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


Рис. 5.11. Приложение ShowRoom

Рис. 5.11. Приложение ShowRoom


В приложении ShowRoom демонстрируется применение следующих технологий:

Подобно приложению TextureDrift, приложение ShowRoom использует интерфейс Direct3DRMMesh, чтобы избежать снижения быстродействия, вызванного выполняемой интерфейсом Direct3DRMMeshBuilder лишней работой.

Класс ShowRoomWin

Функциональность приложения ShowRoom сосредоточена в классе ShowRoomWin. Определение этого класса выглядит следующим образом:

class ShowRoomWin : public RMWin
{
public:
    BOOL CreateScene();
    static void UpdateTexture(LPDIRECT3DRMFRAME frame, void*, D3DVALUE);
protected:
    //{{AFX_MSG(ShowRoomWin)
    //}}AFX_MSG
    DECLARE_MESSAGE_MAP()
private:
    static LPDIRECT3DRMMESH mesh;
    static LPDIRECT3DRMTEXTURE texture[15];
};

В классе объявлены две открытые функции: CreateScene() и UpdateTexture(). Функция CreateScene() используется для создания сцены, а UpdateTexture() — это функция обратного вызова, применяемая для изменения накладываемой в данный момент на сетку текстуры.

Также объявлены две закрытых переменных: mesh и texture. Переменная mesh это указатель на интерфейс Direct3DRMMesh , используемый для доступа к сетке, на которую накладывается анимируемая текстура. Переменная texture является массивом текстур, которые будут по очереди накладываться на сетку.

Функция ShowRoom::CreateScene()

Во время конструирования сцены приложения ShowRoom, функция CreateScene() загружает 15 текстур, на каждой из которых изображена машина, повернутая под другим углом. Потом создаются сетка и плоское наложение текстуры, и первая текстура накладывается на сетку. Функция обратного вызова используется для последовательного наложения на сетку остальных текстур. Код функции CreateScene() приложения ShowRoom приведен в листинге 5.7.

Листинг 5.7. Функция ShowRoomWin::CreateScene()

BOOL ShowRoomWin::CreateScene()
{
    //-------- ТЕКСТУРЫ --------
    HRSRC texture_id;
    int t = 0;
    texture_id = FindResource(NULL, MAKEINTRESOURCE(IDR_TEXTURE01),
        "TEXTURE");
    d3drm->LoadTextureFromResource(texture_id, &texture[t++]);
    texture_id = FindResource(NULL, MAKEINTRESOURCE(IDR_TEXTURE02),
        "TEXTURE");
    d3drm->LoadTextureFromResource(texture_id, &texture[t++]);
    texture_id = FindResource(NULL, MAKEINTRESOURCE(IDR_TEXTURE03),
        "TEXTURE");
    d3drm->LoadTextureFromResource(texture_id, &texture[t++]);
    texture_id = FindResource(NULL, MAKEINTRESOURCE(IDR_TEXTURE04),
        "TEXTURE");
    d3drm->LoadTextureFromResource(texture_id, &texture[t++]);
    texture_id = FindResource(NULL, MAKEINTRESOURCE(IDR_TEXTURE05),
        "TEXTURE");
    d3drm->LoadTextureFromResource(texture_id, &texture[t++]);
    texture_id = FindResource(NULL, MAKEINTRESOURCE(IDR_TEXTURE06),
        "TEXTURE");
    d3drm->LoadTextureFromResource(texture_id, &texture[t++]);
    texture_id = FindResource(NULL, MAKEINTRESOURCE(IDR_TEXTURE07),
        "TEXTURE");
    d3drm->LoadTextureFromResource(texture_id, &texture[t++]);
    texture_id = FindResource(NULL, MAKEINTRESOURCE(IDR_TEXTURE08),
        "TEXTURE");
    d3drm->LoadTextureFromResource(texture_id, &texture[t++]);
    texture_id = FindResource(NULL, MAKEINTRESOURCE(IDR_TEXTURE09),
        "TEXTURE");
    d3drm->LoadTextureFromResource(texture_id, &texture[t++]);
    texture_id = FindResource(NULL, MAKEINTRESOURCE(IDR_TEXTURE10),
        "TEXTURE");
    d3drm->LoadTextureFromResource(texture_id, &texture[t++]);
    texture_id = FindResource(NULL, MAKEINTRESOURCE(IDR_TEXTURE11),
        "TEXTURE");
    d3drm->LoadTextureFromResource(texture_id, &texture[t++]);
    texture_id = FindResource(NULL, MAKEINTRESOURCE(IDR_TEXTURE12),
        "TEXTURE");
    d3drm->LoadTextureFromResource(texture_id, &texture[t++]);
    texture_id = FindResource(NULL, MAKEINTRESOURCE(IDR_TEXTURE13),
        "TEXTURE");
    d3drm->LoadTextureFromResource(texture_id, &texture[t++]);
    texture_id = FindResource(NULL, MAKEINTRESOURCE(IDR_TEXTURE14),
        "TEXTURE");
    d3drm->LoadTextureFromResource(texture_id, &texture[t++]);
    texture_id = FindResource(NULL, MAKEINTRESOURCE(IDR_TEXTURE15),
        "TEXTURE");
    d3drm->LoadTextureFromResource(texture_id, &texture[t++]);

    // ------- КОНСТРУКТОР СЕТОК --------
    D3DRMLOADRESOURCE resinfo;
    resinfo.hModule = NULL;
    resinfo.lpName = MAKEINTRESOURCE( IDR_BOXMESH );
    resinfo.lpType = "MESH";
    LPDIRECT3DRMMESHBUILDER meshbuilder;
    d3drm->CreateMeshBuilder(&meshbuilder);
    meshbuilder->Load(&resinfo, NULL, D3DRMLOAD_FROMRESOURCE,
        NULL, NULL);
    meshbuilder->Scale(D3DVALUE(1), D3DVALUE(1), D3DVALUE(.1));
    ScaleMesh(meshbuilder, D3DVALUE(20));
    meshbuilder->SetPerspective(TRUE);
    meshbuilder->SetQuality(D3DRMRENDER_FLAT);
    meshbuilder->SetTexture(texture[0]);

    //--------- НАЛОЖЕНИЕ --------
    D3DRMBOX box;
    meshbuilder->GetBox(&box);
    D3DVALUE width = box.max.x - box.min.x;
    D3DVALUE height = box.max.y - box.min.y;

    LPDIRECT3DRMWRAP wrap;
    d3drm->CreateWrap(D3DRMWRAP_FLAT, NULL,
      D3DVALUE(0.0), D3DVALUE(0.0), D3DVALUE(0.0), // начало координат наложения
      D3DVALUE(0.0), D3DVALUE(0.0), D3DVALUE(1.0), // ось z
      D3DVALUE(0.0), D3DVALUE(1.0), D3DVALUE(0.0), // ось y
      D3DVALUE(0.5), D3DVALUE(0.5),                // начало координат
      D3DDivide(1,width),D3DDivide(1,height),      // масштаб
      &wrap);
    wrap->Apply(meshbuilder);
    wrap->Release();
    wrap = 0;

    //------- СЕТКА ------
    meshbuilder->CreateMesh(&mesh);
    meshbuilder->Release();
    meshbuilder = 0;

    //------- ФРЕЙМ --------
    LPDIRECT3DRMFRAME meshframe;
    d3drm->CreateFrame(scene, &meshframe);
    meshframe->AddVisual(mesh);
    meshframe->SetRotation(scene,
            D3DVALUE(0), D3DVALUE(1), D3DVALUE(0),
            D3DVALUE(0.05));
    meshframe->AddMoveCallback(UpdateTexture, NULL);
    meshframe->Release();
    meshframe = 0;

    //-------- СВЕТ --------
    LPDIRECT3DRMLIGHT dlight, alight;
    d3drm->CreateLightRGB(D3DRMLIGHT_DIRECTIONAL,
            D3DVALUE(1.0), D3DVALUE(1.0), D3DVALUE(1.0),
            &dlight);
    d3drm->CreateLightRGB(D3DRMLIGHT_AMBIENT,
            D3DVALUE(1.0), D3DVALUE(1.0), D3DVALUE(1.0),
            &alight);

    LPDIRECT3DRMFRAME lightframe;
    d3drm->CreateFrame(scene, &lightframe);
    lightframe->SetOrientation(scene,
            D3DVALUE(0), D3DVALUE(-1), D3DVALUE(1),
            D3DVALUE(0), D3DVALUE(1), D3DVALUE(0));
    lightframe->AddLight(dlight);
    lightframe->AddLight(alight);
    lightframe->Release();
    lightframe = 0;
    dlight->Release();
    dlight = 0;
    alight->Release();
    alight = 0;

    //------ КАМЕРА ----------
    d3drm->CreateFrame(scene, &camera);
    camera->SetPosition(scene, D3DVALUE(0), D3DVALUE(0), D3DVALUE(-50));
    d3drm->CreateViewport(device, camera, 0, 0,
            device->GetWidth(), device->GetHeight(),
            &viewport);

    return TRUE;
}

Функция CreateScene() выполняет следующие действия:

  1. Создание пятнадцати текстур.
  2. Создание и конфигурирование конструктора сеток.
  3. Создание и применение плоского наложения текстуры.
  4. Создание интерфейса Direct3DRMMesh.
  5. Создание фрейма для сетки.
  6. Создание источника света.
  7. Создание порта просмотра.

Первая часть функции CreateScene() весьма прямолинейна (и скучна). Создаются и загружаются 15 текстур, и указатель на каждую из текстур сохраняется в массиве texture.

Затем с помощью интерфейса Direct3DRMMeshBuilder загружается сетка куба. Для масштабирования куба применяется функция Scale():

D3DRMLOADRESOURCE resinfo;
resinfo.hModule = NULL;
resinfo.lpName = MAKEINTRESOURCE( IDR_BOXMESH );
resinfo.lpType = "MESH";
LPDIRECT3DRMMESHBUILDER meshbuilder;
d3drm->CreateMeshBuilder(&meshbuilder);
meshbuilder->Load(&resinfo, NULL, D3DRMLOAD_FROMRESOURCE,
    NULL, NULL);
meshbuilder->Scale(D3DVALUE(1), D3DVALUE(1), D3DVALUE(.1));
ScaleMesh(meshbuilder, D3DVALUE(20));
meshbuilder->SetPerspective(TRUE);
meshbuilder->SetQuality(D3DRMRENDER_FLAT);
meshbuilder->SetTexture(texture[0]);

Это делается потому, что мы хотим для наложения текстур использовать почти плоскую прямоугольную сетку. Вместо того, чтобы создавать прямоугольную сетку, мы используем куб и масштабируем его по оси Z до одной десятой его исходного размера. Потом выполняется настройка параметров новой сетки для включения перспективной коррекции и использования при визуализации метода равномерной закраски. Первая текстура из массива texture связывается с новой сеткой.

На шаге 3 создается и применяется наложение текстуры:

D3DRMBOX box;
meshbuilder->GetBox(&box);
D3DVALUE width = box.max.x - box.min.x;
D3DVALUE height = box.max.y - box.min.y;

LPDIRECT3DRMWRAP wrap;
d3drm->CreateWrap(D3DRMWRAP_FLAT, NULL,
  D3DVALUE(0.0), D3DVALUE(0.0), D3DVALUE(0.0), // начало координат наложения
  D3DVALUE(0.0), D3DVALUE(0.0), D3DVALUE(1.0), // ось z
  D3DVALUE(0.0), D3DVALUE(1.0), D3DVALUE(0.0), // ось y
  D3DVALUE(0.5), D3DVALUE(0.5),                // начало координат
  D3DDivide(1,width),D3DDivide(1,height),      // масштаб
  &wrap);
wrap->Apply(meshbuilder);
wrap->Release();
wrap = 0;

Плоское наложение текстуры создается таким образом, чтобы размеры текстуры в точности соответствовали сетке. Наложение текстуры применяется к конструктору сеток с помощью функции Apply().

Теперь загруженный ранее конструктор сеток используется для инициализации указателя на интерфейс Direct3DRMMesh:

meshbuilder->CreateMesh(&mesh);
meshbuilder->Release();
meshbuilder = 0;

Новая сетка создается с теми же параметрами, что были у конструктора сеток.

Затем создается фрейм и сетка присоединяется к нему:

LPDIRECT3DRMFRAME meshframe;
d3drm->CreateFrame(scene, &meshframe);
meshframe->AddVisual(mesh);
meshframe->SetRotation(scene,
        D3DVALUE(0), D3DVALUE(1), D3DVALUE(0),
        D3DVALUE(0.05));
meshframe->AddMoveCallback(UpdateTexture, NULL);
meshframe->Release();
meshframe = 0;

Новому фрейму назначаются такие атрибуты вращения, чтобы он поворачивался вокруг оси Y. Кроме того, для фрейма устанавливается функция обратного вызова UpdateTexture().

Функция ShowRoom::UpdateTexture()

Функция обратного вызова UpdateTexture() отвечает за установку новой текстуры при каждом обновлении экрана. Код функции UpdateTexture() выглядит следующим образом:

void ShowRoomWin::UpdateTexture(LPDIRECT3DRMFRAME frame,
    void*, D3DVALUE)
{
    static UINT count;
    int curtex = count % 15;
    frame->DeleteVisual(mesh);
    mesh->SetGroupTexture(0, texture[curtex]);
    frame->AddVisual(mesh);
    count++;
}

Статическая переменная count используется для того, чтобы программа могла определить, какая из текстур должна быть наложена на сетку. Новая текстура накладывается с помощью функции SetGroupTexture() интерфейса Direct3DRMMesh. Обратите внимание, что конструктор сеток удаляется из фрейма перед вызовом функции SetGroupTexture() и вновь добавляется к фрейму после. Это вызвано тем обстоятельством, что функция SetGroupTexture() не оказывает никакого эффекта на конструктор сеток, присоединенный к фрейму.

Функция SetGroupTexture() интерфейса Direct3DRMMesh похожа на функцию SetTexture() интерфейса Direct3DRMMeshBuilder, которую мы использовали в предыдущих примерах. Отличие заключается в том, что интерфейс Direct3DRMMesh поддерживает группы, а интерфейс Direct3DRMMeshBuilder — нет. Группой называется набор граней, которым можно управлять как единой сущностью. Более подробно об интерфейсе Direct3DRMMesh мы поговорим в главе 8.


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

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