РАПИДОГРАФ ФИОЛЕТОВОГО КВАРЦА


Новости
Статьи
Файлы
О себе
Гостевая







BASS Photo Gallery Dumpy home page




E-mail

 

DirectX 8 - Урок 1. Вывод простых фигур

В нашем первом уроке мы с помощью Direct3D нарисуем две простые фигуры: треугольник и квадрат. Для этого нам понадобятся последняя версия DirectX SDK, которую вы можете взять здесь, и любой компилятор языка С++. Сам я пользуюсь Visual C++ 6.0, потому что с ним не возникает никаких проблем при работе с DirectX SDK. Итак, начнем:

Во-первых , мы создадим главное окно программы, в котором будут нарисованы наши фигуры.

// Функция CreateMainWindow() создает главное окно приложения
void CreateMainWindow(void)
{ 
    WNDCLASSEX wc = {sizeof(WNDCLASSEX),CS_CLASSDC,
        WindowMsgProc,0,0,
        GetModuleHandle(NULL),NULL,NULL,NULL,NULL,
        "D3D Samples",NULL};

    // Регестрируем класс окна
    RegisterClassEx(&wc);

    // Создаем главное окно приложения
    hWnd = CreateWindow("D3D Samples","D3D Lesson 1: Simple Draw",
           WS_OVERLAPPEDWINDOW,100,100,600,300,
           GetDesktopWindow(),NULL,GetModuleHandle(NULL),NULL);

    // Показываем главное окно
    ShowWindow(hWnd,SW_SHOWNORMAL);
}

Для тех, кто не знаком с программированием для Windows, поясню, что сперва необходимо зарегистрировать класс окна, затем мы создаем само окно и отображаем его на экране. Каждое окно имеет свой обработчик сообщений, поступающих от Windows. Я ограничился лишь обработкой сообщения о закрытиии окна WM_DESTROY , чтобы закрыть все приложение:

// Функция обработки сообщений главного окна приложения
LRESULT WINAPI WindowMsgProc(HWND hWnd,UINT msg,
                             WPARAM wParam,LPARAM lParam)
{
    switch(msg) 
    {
        case WM_DESTROY: PostQuitMessage(0);
                         return 0;
    }
    return DefWindowProc(hWnd,msg,wParam,lParam);
}

Теперь проинициализируем Direct3D:

// Функция InitDirect3D() инициализирует Direct3D
int InitDirect3D(void)
{ 
    D3DDISPLAYMODE d3d_dm;
    D3DPRESENT_PARAMETERS d3d_pp;

    // Создаем Direct3D
    d3d = Direct3DCreate8(D3D_SDK_VERSION);
    if(!d3d) return 0;

    // Получаем текущий режим дисплея
    if(FAILED(d3d->GetAdapterDisplayMode(D3DADAPTER_DEFAULT,
                                  &d3d_dm)))
        return 0;

    // Создаем устройство Direct3D
    ZeroMemory(&d3d_pp,sizeof(d3d_pp));
    d3d_pp.Windowed = TRUE;
    d3d_pp.SwapEffect = D3DSWAPEFFECT_DISCARD;
    d3d_pp.BackBufferFormat = d3d_dm.Format;
    if(FAILED(d3d->CreateDevice(D3DADAPTER_DEFAULT,
                                D3DDEVTYPE_HAL,hWnd,
                                D3DCREATE_SOFTWARE_VERTEXPROCESSING,
                                &d3d_pp,&d3d_device))) 
                                return 0;

    // Возращаем OK
    return 1;
}

Функция инициализации InitDirect3D() разбита на два этапа:

1. Создание объекта Direct3D. Это первый объект, который должна получить любая ваша программа. Только через него мы сможем получить информацию о всех устройствах Direct3D и создать любой из них.

2. Создание устройства Direct3D. Устройство Direct3D является основным компонентом, который выполняет трансформацию, освещение и растеризацию наших графических данных, проще говоря, именно оно и рисует нашу картинку. Устройство Direct3D может быть нескольких типов, но остановимся на основных двух:
   - D3DDEVTYPE_HAL - Аппаратное устройство, в котором все операции      выполняет с помощью графического процессора видеокарты, что заметно ускоряет работу.
   - D3DDEVTYPE_REF - Программное устройство, все операции в котором выполняются центральным процессором, что крайне медленно, поэтому лучше его не использовать.

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

Direct3D оперирует тремя основными пространственными координатими X, Y и Z . Иначе их можно назвать "ширина","высота" и "глубина". С помощью этих трех координат можно однозначно определить положение любого объекта в пространстве, будь-то это человек, дом или дерево. Любой объект состоит из конечного количества точек (для дальнейшего удобства будем называть точки - вершинами), которые образуют его каркас.

Рисунок 1. Куб

Каркас объекта состоит из треугольников, каждый из которых определен в пространстве тремя вершинами. Треугольник - это основной графический примитив, который используются в Direct3D. Например, модель куба, показанного на Рис.1, состоит из 12 треугольников и 8 вершин. Каждая вершина в объекте имеет свои уникальные параметры: положение в пространстве, цвет вершины и т.д.

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

struct CUSTOMVERTEX {
    FLOAT x,y,z,rhw; // Позиция вершины
    DWORD color;     // Цвет вершины
};

Мы создали структуру CUSTOMVERTEX , в которой содержится необходимая нам информация о каждой вершине:
    x,y,z - координаты вершины
    rhw - обратная величина координаты w из гомогенной точки (x,y,z,w)
    color - цвет вершины
Мы используем величину rhw , для того, чтобы самим определить позицию каждой вершины в окне без стандартных преобразований Direct3D. Сформируем массив вершин Vertices с нашими данными:

// Массив данных
CUSTOMVERTEX Vertices[] = {
    {150.0f, 50.0f,0.5f,1.0f,0x00ff0000},
    {250.0f,250.0f,0.5f,1.0f,0x0000ff00},
    { 50.0f,250.0f,0.5f,1.0f,0x000000ff},
    {500.0f, 50.0f,0.5f,1.0f,0x00ff0000},
    {500.0f,250.0f,0.5f,1.0f,0x0000ff00},
    {300.0f,250.0f,0.5f,1.0f,0x000000ff},
    {300.0f,250.0f,0.5f,1.0f,0x000000ff},
    {300.0f, 50.0f,0.5f,1.0f,0x0000ff00},
    {500.0f, 50.0f,0.5f,1.0f,0x00ff0000},
};

В нашем массиве 9 вершин, которые и составляют три треугольника. Чтобы устройство Direct3D нарисовало наши фигуры, необходимо данные записать в специальный буфер вершин.

// Функция InitDirect3DData() загружает данные в буфер вершин
int InitDirect3DData(void)
{
    void *pVertices;

    // Создаем буфер вершин
    if(FAILED(d3d_device->CreateVertexBuffer(9*sizeof(CUSTOMVERTEX),
              0,D3DFVF_CUSTOMVERTEX,
              D3DPOOL_DEFAULT,&d3d_vb))) return 0;

    // Загружаем данные в буфер вершин
    if(FAILED(d3d_vb->Lock(0,sizeof(Vertices),(BYTE**)&pVertices,0))) 
                                  return 0;
    memcpy(pVertices,Vertices,sizeof(Vertices));
    d3d_vb->Unlock();

    // Возращаем OK
    return 1;
}

При создании этого буфера мы должны указать формат наших вершин. Для этого существуют так называемые флаги формата вершины.

#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZRHW|D3DFVF_DIFFUSE) 
                                             // FVF Flags

Первый флаг D3DFVF_XYZRHW указывает на то, что передаваемая вершина содержит позицию вершины, а второй флаг D3DFVF_DIFFUSE - ее цвет. После инициализации Direct3D и подготовки данных, теперь мы можем нарисовать наши фигуры.

// Функция RenderDirect3D() прорисовывает сцену
void RenderDirect3D(void)
{
    // Очищение заднего буфера
    d3d_device->Clear(0,NULL,D3DCLEAR_TARGET,
                         D3DCOLOR_XRGB(0,0,0),1.0f,0);

    // Начало прорисовки сцены
    d3d_device->BeginScene();

    // Прорисовка сцены
    d3d_device->SetStreamSource(0,d3d_vb,
                                   sizeof(CUSTOMVERTEX));
    d3d_device->SetVertexShader(D3DFVF_CUSTOMVERTEX);
    d3d_device->DrawPrimitive(D3DPT_TRIANGLELIST,0,3);

    // Конец прорисовки сцены
    d3d_device->EndScene();
    d3d_device->Present(NULL,NULL,NULL,NULL);
}

Прорисовка сцены выполняется функцией DrawPrimitive , аргументами которой являются: последовательность и тип графических примитивов, в нашем случае это список треугольников (D3DPT_TRIANGLELIST), индекс первого элемента в буфере вершин и количество выводимых треугольников. Чтобы выполнять все вышеперечисленные действия в правильном порядке, их нужно определить в главной функции программы.

// Главная функция приложения
int APIENTRY WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,
                     LPSTR lpCmdLine,int nCmdShow)
{
    MSG msg;

    CreateMainWindow();
    if(!InitDirect3D()||!InitDirect3DData()) 
                                  return 0;
    PeekMessage(&msg,NULL,0,0,PM_NOREMOVE);
    while(msg.message!=WM_QUIT)
        if(PeekMessage(&msg,NULL,0,0,PM_REMOVE)) 
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
        else 
        {
            RenderDirect3D();
        }
    ReleaseDirect3D();
    return 0;
}

Перед выходом из главной функции программы закроем все созданные нами объекты Direct3D.


// Функция ReleaseDirect3D() деинициализирует DirectX Graphics
void ReleaseDirect3D(void)
{
    if(d3d_vb) d3d_vb->Release();
    if(d3d_device) 
      d3d_device->Release();
    if(d3d) d3d->Release();
}

Полный исходный текст программы и exe-файл находится тут.


Взято с DirectX Design

Все права проигнорированны © 2002, StasH
Сайт создан в системе uCoz