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

Прозрачность

Интерфейс Direct3DRMTexture позволяет вам указать цвет текстуры, который будет восприниматься Direct3D как прозрачный. Сквозь прозрачные участки текстуры можно видеть сетки и текстуры, которые в ином случае были бы скрыты от глаз зрителя.

По умолчанию прозрачность текстур отключена. Для разрешения и запрещения прозрачности текстур может применяться функция SetDecalTransparency() интерфейса Direct3DRMTexture. После разрешения прозрачности любые черные точки текстуры будут считаться прозрачными. Цвет, который считается прозрачным, можно изменить с помощью функции SetDecalTransparencyColor().

Приложение OrbStar

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


Рис. 5.8. Приложение OrbStar

Рис. 5.8. Приложение OrbStar


Текстура, которая будет наложена на сферу в данном приложении, изображена на рис. 5.9.


Рис. 5.9. Текстура, используемая в приложении OrbStar

Рис. 5.9. Текстура, используемая в приложении OrbStar


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

Класс OrbStarWin

Класс OrbStarWin предоставляет большинство функциональных возможностей приложения OrbStar. Определение класса выглядит следующим образом:

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

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

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

Функция CreateScene() приложения OrbStar создает сетку звезды и сетку сферы, текстуру, которая будет наложена на сферу, два источника света и порт просмотра. Код функции CreateScene() приведен в листинге 5.4.

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

BOOL OrbStarWin::CreateScene()
{
    //-------- СЕТКА ЗВЕЗДЫ --------
    D3DRMLOADRESOURCE resinfo;
    resinfo.hModule = NULL;
    resinfo.lpName = MAKEINTRESOURCE(IDR_STARMESH);
    resinfo.lpType = "MESH";
    LPDIRECT3DRMMESHBUILDER starbuilder;
    d3drm->CreateMeshBuilder(&starbuilder);
    starbuilder->Load(&resinfo, NULL, D3DRMLOAD_FROMRESOURCE,
        NULL, NULL);
    starbuilder->SetColorRGB(D3DVALUE(1.0), D3DVALUE(0.0),
        D3DVALUE(0.0));
    ScaleMesh(starbuilder, D3DVALUE(20));

    //--------- ФРЕЙМ ЗВЕЗДЫ --------
    LPDIRECT3DRMFRAME starframe;
    d3drm->CreateFrame(scene, &starframe);
    starframe->SetRotation(scene,
            D3DVALUE(1.0), D3DVALUE(0.0),D3DVALUE(0.0),
            D3DVALUE(0.1));
    starframe->AddVisual(starbuilder);
    starframe->AddMoveCallback(MoveStar, NULL);
    starframe->Release();
    starframe = 0;
    starbuilder->Release();
    starbuilder = 0;

    //--------- СЕТКА СФЕРЫ --------
    resinfo.hModule = NULL;
    resinfo.lpName = MAKEINTRESOURCE(IDR_SPHEREMESH);
    resinfo.lpType = "MESH";
    LPDIRECT3DRMMESHBUILDER spherebuilder;
    d3drm->CreateMeshBuilder(&spherebuilder);
    spherebuilder->Load(&resinfo, NULL, D3DRMLOAD_FROMRESOURCE,
        NULL, NULL);
    spherebuilder->SetPerspective(TRUE);
    ScaleMesh(spherebuilder, D3DVALUE(25));

    //---------- ТЕКСТУРА ДЛЯ СФЕРЫ ------
    LPDIRECT3DRMTEXTURE texture;
    HRSRC texture_id = FindResource(NULL, MAKEINTRESOURCE(
        IDR_TRANSTEXTURE), "TEXTURE");
    d3drm->LoadTextureFromResource(texture_id, &texture);
    texture->SetDecalTransparency(TRUE);
    spherebuilder->SetTexture(texture);
    texture->Release();
    texture = 0;

    //---------- НАЛОЖЕНИЕ ТЕКСТУРЫ ДЛЯ СФЕРЫ --------
    D3DRMBOX box;
    spherebuilder->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(1.0), D3DVALUE(0.0),  // ось z
      D3DVALUE(0.0), D3DVALUE(0.0), D3DVALUE(1.0),  // ось y
      D3DVALUE(0.5), D3DVALUE(0.5),                 // начало координат
      D3DDivide(1,width), D3DDivide(1,height),      // масштаб
      &wrap);
    wrap->Apply(spherebuilder);
    wrap->Release();
    wrap = 0;

    //-------- ФРЕЙМ СФЕРЫ ----------
    LPDIRECT3DRMFRAME sphereframe;
    d3drm->CreateFrame(scene, &sphereframe);
    sphereframe->SetRotation(scene,
            D3DVALUE(0), D3DVALUE(1), D3DVALUE(0),
            D3DVALUE(.1));
    sphereframe->AddVisual(spherebuilder);
    sphereframe->AddMoveCallback(MoveSphere, NULL);
    sphereframe->Release();
    sphereframe = 0;
    spherebuilder->Release();
    spherebuilder = 0;

    //----------- СВЕТ --------
    LPDIRECT3DRMLIGHT light1, light2;
    d3drm->CreateLightRGB(D3DRMLIGHT_AMBIENT,
            D3DVALUE(0.8),D3DVALUE(0.8), D3DVALUE(0.8),
            &light1);
    d3drm->CreateLightRGB(D3DRMLIGHT_DIRECTIONAL,
            D3DVALUE(0.9), D3DVALUE(0.9), D3DVALUE(0.9),
            &light2);

    LPDIRECT3DRMFRAME lightframe;
    d3drm->CreateFrame(scene, &lightframe);
    lightframe->SetOrientation(scene,
            D3DVALUE(-1), D3DVALUE(-1), D3DVALUE(1),
            D3DVALUE(0), D3DVALUE(1), D3DVALUE(0));

    lightframe->AddLight(light1);
    lightframe->AddLight(light2);

    lightframe->Release();
    lightframe = 0;
    light1->Release();
    light1 = 0;
    light2->Release();
    light2 = 0;

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

    return TRUE;
}

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

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

Сначала создается сетка звезды:

D3DRMLOADRESOURCE resinfo;
resinfo.hModule = NULL;
resinfo.lpName = MAKEINTRESOURCE(IDR_STARMESH);
resinfo.lpType = "MESH";
LPDIRECT3DRMMESHBUILDER starbuilder;
d3drm->CreateMeshBuilder(&starbuilder);
starbuilder->Load(&resinfo, NULL, D3DRMLOAD_FROMRESOURCE,
    NULL, NULL);
starbuilder->SetColorRGB(D3DVALUE(1.0), D3DVALUE(0.0),
    D3DVALUE(0.0));
ScaleMesh(starbuilder, D3DVALUE(20));

Как и в других демонстрационных приложениях, для загрузки сетки из ресурсов программы используется функция Load() интерфейса Direct3DRMMeshBuilder. Как только сетка загружена, вызывается функция SetColorRGB() для окрашивания всей сетки в красный цвет. Затем для масштабирования сетки в соответствии с заданным размером применяется функция ScaleMesh().

Теперь создается фрейм (с именем starframe) и ему назначаются атрибуты вращения:

LPDIRECT3DRMFRAME starframe;
d3drm->CreateFrame(scene, &starframe);
starframe->SetRotation(scene,
        D3DVALUE(1.0), D3DVALUE(0.0),D3DVALUE(0.0),
        D3DVALUE(0.1));
starframe->AddVisual(starbuilder);
starframe->AddMoveCallback(MoveStar, NULL);
starframe->Release();
starframe = 0;
starbuilder->Release();
starbuilder = 0;

Новый фрейм получает атрибуты вращения, задающие его вращение вокруг оси X. Как вы увидите, эти атрибуты являются временными, поскольку мы используем функцию обратного вызова, для изменения атрибутов вращения во время работы приложения. Созданный ранее конструктор сеток присоединяется к новому фрейму с помощью функции AddVisual(). Перед освобождением указателей starframe и starbuilder выполняется установка функции обратного вызова MoveStar(). На код функции MoveStar() мы взглянем чуть позже. После выполнения описанных действий выполняется освобождение указателей starframe и starbuilder.

Далее создается и загружается сетка сферы:

resinfo.hModule = NULL;
resinfo.lpName = MAKEINTRESOURCE(IDR_SPHEREMESH);
resinfo.lpType = "MESH";
LPDIRECT3DRMMESHBUILDER spherebuilder;
d3drm->CreateMeshBuilder(&spherebuilder);
spherebuilder->Load(&resinfo, NULL, D3DRMLOAD_FROMRESOURCE, NULL, NULL);
spherebuilder->SetPerspective(TRUE);
ScaleMesh(spherebuilder, D3DVALUE(25));

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

Этап 4 — это создание текстуры для сферы:

LPDIRECT3DRMTEXTURE texture;
HRSRC texture_id = FindResource(NULL, MAKEINTRESOURCE(
    IDR_TRANSTEXTURE), "TEXTURE");
d3drm->LoadTextureFromResource(texture_id, &texture);
texture->SetDecalTransparency(TRUE);
spherebuilder->SetTexture(texture);
texture->Release();
texture = 0;

Как и в других приложениях, для создания текстуры используется функция LoadTextureFromResource(). Потом, чтобы разрешить прозрачность текстуры вызывается функция SetDecalTransparency(). Мы не определяем прозрачный цвет, поэтому по умолчанию как прозрачный будет восприниматься черный цвет. Для привязки текстуры к сетке сферы применяется функция SetTexture() интерфейса Direct3DRMMeshBuilder. После выполнения этих действий указатель texture освобождается.

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

D3DRMBOX box;
spherebuilder->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(1.0), D3DVALUE(0.0),  // ось z
  D3DVALUE(0.0), D3DVALUE(0.0), D3DVALUE(1.0),  // ось y
  D3DVALUE(0.5), D3DVALUE(0.5),                 // начало координат
  D3DDivide(1,width), D3DDivide(1,height),      // масштаб
  &wrap);
wrap->Apply(spherebuilder);
wrap->Release();
wrap = 0;

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

На шестом шаге создается фрейм для сетки сферы:

LPDIRECT3DRMFRAME sphereframe;
d3drm->CreateFrame(scene, &sphereframe);
sphereframe->SetRotation(scene,
        D3DVALUE(0), D3DVALUE(1), D3DVALUE(0),
        D3DVALUE(.1));
sphereframe->AddVisual(spherebuilder);
sphereframe->AddMoveCallback(MoveSphere, NULL);
sphereframe->Release();
sphereframe = 0;
spherebuilder->Release();
spherebuilder = 0;

Новому фрейму присваиваются атрибуты вращения, но, также как и для фрейма, созданного на этапе 2, для изменения этих атрибутов используется функция обратного вызова. С помощью функции AddVisual() к фрейму присоединяется сетка сферы и устанавливается функция обратного вызова MoveSphere(). Затем выполняется освобождение указателей sphereframe и spherebuilder.

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

Функции обратного вызова в приложении OrbStar

Функция CreateScene() приложения OrbStar устанавливает две функции обратного вызова: одну для фрейма к которому присоединена сетка звезды и другую для фрейма с сеткой сферы. Эти функции периодически назначают каждому фрейму случайные атрибуты вращения, вызывая изменение скорости и направления вращения сеток в сцене приложения. Функции обратного вызова MoveStar() и MoveSphere() практически идентичны, поэтому здесь приводится только код функции MoveStar().

void OrbStarWin::MoveStar(LPDIRECT3DRMFRAME frame, void*, D3DVALUE)
{
    static UINT delay;
    if (++delay < 11)
        return;
    delay = 0;

    LPDIRECT3DRMFRAME scene;
    frame->GetScene(&scene);

    D3DVECTOR spinvect;
    D3DRMVectorRandom(&spinvect);
    D3DVALUE spin = D3DDivide(rand() %100 + 1, 200);
    frame->SetRotation(scene,
            spinvect.x, spinvect.y, spinvect.z,
            spin);
}

Функция MoveStar() использует статическую переменную delay в качестве счетчика, регулирующего частоту изменения атрибутов вращения фрейма. В нашем случае изменение происходит, когда значение счетчика станет равно 11.

Как только станет ясно, что необходимо вычислить новые атрибуты вращения, с помощью функции GetScene() интерфейса Direct3DRMFrame мы получаем указатель на корневой фрейм сцены. Вспомните, что функции обратного вызова должны быть объявлены как статические из-за того, что для вызова обычных функций класса необходим указатель на класс. Статические функции класса не могут обращаться к переменным класса (если только эти переменные тоже не объявлены статическими). Если бы MoveStar() не была статической, мы могли бы использоать переменную RMWin::scene так же, как это делается в функции CreateScene(). К счастью Direct3D передает в первом параметре функции обратного вызова указатель на фрейм, для которого эта функция вызвана, и предоставляет функцию GetScene(). Нам потребуется указатель на фрейм сцены, когда позднее из этой функции мы вызовем функцию SetRotation().

Функция MoveStar() вычисляет новые атрибуты вращения случайным образом. Функция D3DRMVectorRandom() возвращает случайный вектор, а скорость вращения вычисляется с помощью функции rand(). Новые атрибуты вращения фрейма устанавливаются функцией SetRotation().


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

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