DirectX 8 Graphics. Частицы (Particles)
Содержание
- DirectX 8 Graphics. Частицы (Particles)
- Intro
- Создание текстуры частицы
- Создание 3D-объекта частицы
- Пример приложения с летающими частицами (Win32, DirectX 8)
- Создаём Проект приложения Particle01
- Добавляем в Проект WinMain.cpp
- Готовим Проект Particle01 к компиляции
- Указываем пути к DirectX SDK 8.1
- Указываем пути к Windows SDK
- Выбираем многобайтовую кодировку
- Отключаем инкрементную компоновку (incremental linking)
- Удаляем файл cvtres.exe
- Прописываем библиотеки d3dx8.lib, d3d8.lib и Winmm.lib в окне "Дополнительные зависимости" (Additional dependencies) компоновщика (Linker)
- Отключаем использование компоновщиком библиотеки libci.dll
- Компилируем Проект Particle01
- Готовим текстуру
- Архив с готовым Проектом Particle01 (VC++2010)
- Заключение
- Источники
Intro
Системы частиц:- С их помощью в играх создают взрывы, дымовые шлейфы, огонь из летящей ракеты и т.д.1
- Действуют по тому же принципу, что и билборды (billboards).
- Относительно просты в применении.
Самая главная фишка частиц заключает в том, что они могут быть в принципе любого размера. Согласно замыслу, создаётся матрица масштабирования (scaling matrix), которая затем комбинируется (=перемножается) с мировой матрицей трансформации (world transformation matrix) полигона частицы. То есть в самом простом случае для создания системы частиц нужен всего 1 полигон. При создании анимации костра берут несколько базовых полигонов частиц красного, оранжевого и жёлтого цветов.
Для компиляции примера на понадобится:
- MS Visual C++ 2010 Express,
- Microsoft DirectX SDK 8.
Создание текстуры частицы
Для примера возьмём (или создадим в Фотошопе) квадратное изображение с окружностью, размещённой по середине. Центр окружности полностью непрозрачен (opaque), но прозрачность постепенно нарастает при движении к краям изображения (См. Рис. 1). (Примерно так выглядит частица снежных хлопьев в игре.) При создании такой текстуры используется прозрачность (если поддерживается движком) либо цвет "выключки" альфа-канала (обычно чёрный или синий).
Создание 3D-объекта частицы
Сперва создаём вершинный буфер из 4-х вершин, образующих 2 треугольных полигона с одной общей стороной (trianglestrip; по факту - плоский квадрат). Координаты этих вершин в пространстве задают размер объекта частицы по умолчанию, на который затем будет нанесена текстура. Как правило, начальный размер объекта роли не играет, т.к. затем с помощью кода он будет изменён. Каждая частица может обладать своими уникальными свойствами, включая цвет (при использовании материалов).Далее предварительно созданную структуру комбинируем с созданным вершинным буфером, содержащим 3D-объект частицы (состоящий из двух треугольных полигонов с одной общей стороной, образующих плоский квадрат). Перед отрисовкой каждая частица ориентируется (т.е. поворачивается) с применением своей собственной мировой матрицы (техника билборда). Таким образом, все частицы всегда повёрнуты лицевой стороной к наблюдателю. Далее просто комбинируем мировую матрицу трансформации с матрицей масштабирования частицы (particle's scale transformation matrix), назначаем материал (путём вызова функции IDirect3DDevice8::SetMaterial) для смены цвета и выводим частицу на экран.
Вот пример кода, где создаётся вершинный буфер объекта частицы и затем отправляется в объект устройства Direct3D для последующей отрисовки:
// g_pD3DDevice - предварительно созданный и проинициализированный объект устройства Direct 3D. // Определяем (define) кастомную FVF-структуру и её дескриптор. typedef struct { FLOAT x, y, z; // Локальные 3D-координаты. FLOAT u, v; // Координаты текстуры. }sVertex; #define VertexFVF(D3DFVF_XYZ | D3DFVF_TEX1) // Вершинный буфер частиц и их текстура. IDirect3DVertexBuffer8 *g_pParticleVB = NULL; IDirect3DTexture8 *g_pParticleTexture = NULL; BOOL SetupParticle() { BYTE *Ptr; sVertex Verts[4] = { {-1.0f, 1.0f, 0.0f, 0.0f, 0.0f}, {1.0f, 1.0f, 0.0f, 1.0f, 0.0f}, {-1.0f, -1.0f, 0.0f, 0.0f, 1.0f}, {1.0f, -1.0f, 0.0f, 1.0f, 1.0f} }; // Создаём вершинный буфер частиц и заполняем данные. if(FAILED(g_pD3DDevice->CreateVertexBuffer(sizeof(sVertex)*4, 0, VertexFVF, D3DPOOL_DEFAULT, &g_pParticleVB))) return FALSE; if(FAILED(g_pParticleVB->Lock(0, 0, (BYTE**)&Ptr, 0))) return FALSE; memcpy(Ptr, Verts, sizeof(Verts)); g_pParticleVB->Unlock; // Получаем текстуру частицы. D3DCreateTextureFromFile(g_pD3DDevice, "particle.bmp", &g_pParticleTexture); return TRUE; } BOOL DrawParticle(float x, float y, float z, float scale) { D3DXMATRIX matWorld, matView, matTransposed; D3DXMATRIX matTrans, matScale; D3DMATERIAL8 d3dm; // Назначаем рендерстейты (альфа-смешивание и его атрибуты). g_pD3DDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); g_pD3DDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); g_pD3DDevice->SetRenderState(D3DRS_DESTBLEND_ONE); // Включаем фоновое (ambient) освещение. g_pD3DDevice->SetRenderState(D3DRS_AMBIENT, 0xffffff); // Назначаем вершинному буферу частиц поток-источник (source stream). g_pD3DDevice->SetStreamSource(0, g_pParticle_VB, sizeof(sVertex)); // Назначаем в качестве вершинного шейдера ранее созданную FVF-структуру частицы. g_pD3DDevice->SetVertexShader(VertexFVF); // Назначаем текстуру. g_pD3DDevice->SetTexture(0, g_pParticleTexture); // Назначаем цвет частицы. ZeroMemory(&d3dm, sizeof(D3DMATERIAL8)); d3dm.Diffuse.r = d3dm.Ambient.r = 1.0f; d3dm.Diffuse.g = d3dm.Ambient.g = 1.0f; d3dm.Diffuse.b = d3dm.Ambient.b = 0.0f; d3dm.Diffuse.a = d3dm.Ambient.a = 1.0f; // Строим матрицу масштабирования (scaling matrix). D3DXMatrixScaling(&matScale, scale, scale, scale); // Строим матрицу трансляции (translation matrix). D3DXMatrixTranslation(&matTrans, x, y, z); // Строим матрицу билборда (billboard matrix). g_pD3DDevice->GetTransform(D3DTS_VIEW, &matView); D3DXMatrixTranspose(&matTransposed, &matView); // Комбинируем матрицы для получения мировой матрицы трансляции (world translation matrix). D3DXMatrixMultiply(&matWorld, &matScale, &matTransposed); D3DXMatrixMultiply(&matWorld, &matWorld, &matTrans); // Назначаем полученную мировую матрицу трансляции // в качестве действующей в объекте устройства Direct3D. g_pD3DDevice->SetTransform(D3DTS_WORLD, &matWorld); // Рисуем частицу. g_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2); // Выключаем альфа-смешивание. g_pD3DDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE); return TRUE; }
Приведённый выше две функции демонстрируют создание вершинного буфера и текстуры для создания частицы и её последующей отрисовки. Данный код далеко не полный.
Пример приложения с летающими частицами (Win32, DirectX 8)
Перед началом проверь, что у тебя установлены следующие программные компоненты:- MS Visual C++ 2010;
- DirectX SDK 8.1
- Windows SDK (для программирования под Win7/8/10).
- + инструкции по их установке ты найдёшь в разделе "Софт" нашего сайта;
- Бесплатны;
- Без труда гуглятся.
Создаём Проект приложения Particle01
- Создай пустой Проект с именем Particle01.
Добавляем в Проект WinMain.cpp
Для чистоты эксперимента мы создали пустой Проект, т.е. без каких-либо файлов в нём. Создадим единственный файл с исходным кодом WinMain.cpp.- В "Обозревателе решений" главного окна MSVC++2010 щёлкни правой кнопкой мыши по папке (в терминологии Майкрософт это не папки, а фильтры!) "Файлы исходного кода" Проекта Particle01.
- Во всплывающем меню Добавить->Создать элемент...
- В появившемся окне выбери "Файл С++ (.cpp)" и в поле "Имя" введи WinMain.cpp. Жмём "Добавить".
Добавленный файл сразу откроется в правой части MSVC++2010.
- В только что созданном и открытом файле WinMain.cpp набираем следующий код:
/************************************************** WinMain.cpp Chapter 6 Particle Demo Programming Role-Playing Games with DirectX by Jim Adams (01 Jan 2002) Required libraries: WINMM.LIB, D3D8.LIB, and D3DX8.LIB **************************************************/ // Include files #include <windows.h> #include <stdio.h> #include "d3d8.h" #include "d3dx8.h" // Window handles, class and caption text // Дескриптор окна, класс и текст тулбара HWND g_hWnd; HINSTANCE g_hInst; static char g_szClass[] = "ParticleClass"; static char g_szCaption[] = "Particle Demo by Jim Adams"; // The Direct3D and Device object IDirect3D8 *g_pD3D = NULL; IDirect3DDevice8 *g_pD3DDevice = NULL; // The particle vertex format and descriptor // FVF-структура частицы и её дескриптор typedef struct { FLOAT x, y, z; // 3D coordinates D3DCOLOR Diffuse; // Color FLOAT u, v; // Texture coordinates } sVertex; #define VERTEXFVF (D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX1) // The Particle vertex buffer and texture // Вершинный буфер частицы и её текстура IDirect3DVertexBuffer8 *g_pParticleVB = NULL; IDirect3DTexture8 *g_pParticleTexture = NULL; // Create a structure for tracking particles // Создаём структуру для отслеживания частиц typedef struct sParticle { float XPos, YPos, ZPos; // Coordinates float XAdd, YAdd, ZAdd; // Movement values. Значения смещения float Red, Green, Blue; // Colors long Timer, Counter; // Current and update counter. Текущее время и счётчик sParticle() { // Position particle at origin // Начальное положение частицы XPos = YPos = ZPos = 0.0f; // Get a random update counter // Случайно обновляем счётчик Counter = rand() % 50 + 10; Timer = 0; // Get a random speed // Получаем случайную скорость XAdd = (float)(rand() % 11) - 5.0f; YAdd = (float)(rand() % 11) - 5.0f; ZAdd = (float)(rand() % 11) - 5.0f; // Get a random color // Получаем случайный цвет Red = (float)(rand() % 101) / 100.0f; Green = (float)(rand() % 101) / 100.0f; Blue = (float)(rand() % 101) / 100.0f; } } sParticle; sParticle *g_pParticles = NULL; // Function prototypes int PASCAL WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int nCmdShow); long FAR PASCAL WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); BOOL DoInit(); BOOL DoShutdown(); BOOL DoFrame(); BOOL SetupParticles(); int PASCAL WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int nCmdShow) { WNDCLASSEX wcex; MSG Msg; g_hInst = hInst; // Create the window class here and register it // Создаём оконный класс и регистрируем его wcex.cbSize = sizeof(wcex); wcex.style = CS_CLASSDC; wcex.lpfnWndProc = WindowProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = hInst; wcex.hIcon = LoadIcon(NULL, IDI_APPLICATION); wcex.hCursor = LoadCursor(NULL, IDC_ARROW); wcex.hbrBackground = NULL; wcex.lpszMenuName = NULL; wcex.lpszClassName = g_szClass; wcex.hIconSm = LoadIcon(NULL, IDI_APPLICATION); if(!RegisterClassEx(&wcex)) return FALSE; // Create the Main Window // Создаём окно программы g_hWnd = CreateWindow(g_szClass, g_szCaption, WS_CAPTION | WS_SYSMENU, 0, 0, 400, 400, NULL, NULL, hInst, NULL ); if(!g_hWnd) return FALSE; ShowWindow(g_hWnd, SW_NORMAL); UpdateWindow(g_hWnd); // Run init function and return on error if(DoInit() == FALSE) return FALSE; // Start message pump, waiting for signal to quit // Стартуем конвейер выборки сообщений ZeroMemory(&Msg, sizeof(MSG)); while(Msg.message != WM_QUIT) { if(PeekMessage(&Msg, NULL, 0, 0, PM_REMOVE)) { TranslateMessage(&Msg); DispatchMessage(&Msg); } if(DoFrame() == FALSE) break; } // Run shutdown function DoShutdown(); UnregisterClass(g_szClass, hInst); return Msg.wParam; } long FAR PASCAL WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch(uMsg) { case WM_DESTROY: PostQuitMessage(0); return 0; } return DefWindowProc(hWnd, uMsg, wParam, lParam); } BOOL DoInit() { D3DPRESENT_PARAMETERS d3dpp; D3DDISPLAYMODE d3ddm; D3DXMATRIX matView, matProj; // Do a windowed mode initialization of Direct3D // Инициализируем объект устройства Direct3D // для работы в оконном режиме if((g_pD3D = Direct3DCreate8(D3D_SDK_VERSION)) == NULL) return FALSE; if(FAILED(g_pD3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &d3ddm))) return FALSE; ZeroMemory(&d3dpp, sizeof(d3dpp)); d3dpp.Windowed = TRUE; d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; d3dpp.BackBufferFormat = d3ddm.Format; d3dpp.EnableAutoDepthStencil = TRUE; d3dpp.AutoDepthStencilFormat = D3DFMT_D16; if(FAILED(g_pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, g_hWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &g_pD3DDevice))) return FALSE; // Set the render states g_pD3DDevice->SetRenderState(D3DRS_LIGHTING, TRUE); g_pD3DDevice->SetRenderState(D3DRS_ZENABLE, D3DZB_TRUE); // Set ambient light to highest level (to see particles) // Устанавливаем цвет подсветки и его наивысшее значение // (чтобы видеть частицы) g_pD3DDevice->SetRenderState(D3DRS_AMBIENT, 0xFFFFFFFF); // Create and set the projection transformation // Создаём и назначаем трансформацию проекции D3DXMatrixPerspectiveFovLH(&matProj, D3DX_PI/4, 1.0f, 1.0f, 1000.0f); g_pD3DDevice->SetTransform(D3DTS_PROJECTION, &matProj); // Create and set the view transformation // Создаём и назначаем трансформацию вида D3DXMatrixLookAtLH(&matView, &D3DXVECTOR3(0.0f, 0.0f, -500.0f), &D3DXVECTOR3(0.0f, 0.0f, 0.0f), &D3DXVECTOR3(0.0f, 1.0f, 0.0f)); g_pD3DDevice->SetTransform(D3DTS_VIEW, &matView); // Create the vertices // Создаём частицы SetupParticles(); return TRUE; } BOOL DoShutdown() { // Free particles // Освобождаем частицы if(g_pParticles != NULL) delete [] g_pParticles; // Release textures and vertex buffers // Очищаем память от текстур и вершинных буферов if(g_pParticleTexture != NULL) g_pParticleTexture->Release(); if(g_pParticleVB != NULL) g_pParticleVB->Release(); // Release device and 3D objects if(g_pD3DDevice != NULL) g_pD3DDevice->Release(); if(g_pD3D != NULL) g_pD3D->Release(); return TRUE; } BOOL DoFrame() { D3DXMATRIX matView, matWorld, matTransposed, matTrans; static D3DMATERIAL8 Mat; static BOOL InitMat = TRUE; static DWORD Counter = timeGetTime(); // Limit to 30fps // Ограничиваем частоту кадров до 30 в сек. if(timeGetTime() < Counter+33) return TRUE; Counter = timeGetTime(); // Configure the material if first time called // При первом вызове настраиваем материал if(InitMat == TRUE) { InitMat = FALSE; ZeroMemory(&Mat, sizeof(Mat)); Mat.Diffuse.a = Mat.Ambient.a = 0.5f; } // Clear device backbuffer g_pD3DDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_RGBA(0,64,128,255), 1.0f, 0); if(SUCCEEDED(g_pD3DDevice->BeginScene())) { // Set the particle source, shader, and texture // Назначаем источник частиц, шейдер и текстуру g_pD3DDevice->SetStreamSource(0, g_pParticleVB, sizeof(sVertex)); g_pD3DDevice->SetVertexShader(VERTEXFVF); g_pD3DDevice->SetTexture(0, g_pParticleTexture); // Get and set the transposed view matrix (billboard technique) // Получаем и назначаем транспонированную матрицу вида // (техника билбордов) g_pD3DDevice->GetTransform(D3DTS_VIEW, &matView); D3DXMatrixTranspose(&matTransposed, &matView); // Enable alpha blending // Включаем альфа-смешивание g_pD3DDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); g_pD3DDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); g_pD3DDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE); // Loop through all particles and draw them // Зацикленно проходим через каждую частицу // и отрисовываем их for(short i=0;i<512;i++) { // Move particle first // Сперва перемещаем частицы g_pParticles[i].XPos += g_pParticles[i].XAdd; g_pParticles[i].YPos += g_pParticles[i].YAdd; g_pParticles[i].ZPos += g_pParticles[i].ZAdd; // Reverse movements if past counter // При достижении счётчиком порогового значения, // меняем направление движ. частицы на обратное if((g_pParticles[i].Timer += 1) >= g_pParticles[i].Counter) { g_pParticles[i].Timer = 0; g_pParticles[i].XAdd *= -1.0f; g_pParticles[i].YAdd *= -1.0f; g_pParticles[i].ZAdd *= -1.0f; } // Setup the particle's world transformation // Настраиваем мировую матрицу частиц D3DXMatrixTranslation(&matTrans, g_pParticles[i].XPos, \ g_pParticles[i].YPos, \ g_pParticles[i].ZPos); D3DXMatrixMultiply(&matWorld, &matTrans, &matTransposed); g_pD3DDevice->SetTransform(D3DTS_WORLD, &matWorld); // Set the particle's material // Назначаем материал частицы Mat.Diffuse.r = Mat.Ambient.r = g_pParticles[i].Red; Mat.Diffuse.g = Mat.Ambient.g = g_pParticles[i].Green; Mat.Diffuse.b = Mat.Ambient.b = g_pParticles[i].Blue; g_pD3DDevice->SetMaterial(&Mat); // Draw the particle // Отрисовываем частицу g_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2); } // Clear the texture usage g_pD3DDevice->SetTexture(0, NULL); // End the scene g_pD3DDevice->EndScene(); } // Display the scene // Выводим сцену на экран g_pD3DDevice->Present(NULL, NULL, NULL, NULL); return TRUE; } BOOL SetupParticles() { BYTE *Ptr; sVertex Verts[4] = { { -50.0f, 50.0f, 0.0f, 0xFFFFFFFF, 0.0f, 0.0f }, { 50.0f, 50.0f, 0.0f, 0xFFFFFFFF, 1.0f, 0.0f }, { -50.0f, 0.0f, 0.0f, 0xFFFFFFFF, 0.0f, 1.0f }, { 50.0f, 0.0f, 0.0f, 0xFFFFFFFF, 1.0f, 1.0f } }; // Create vertex buffers and set data // Создаём вершинный буфер и размещаем в нём вершины g_pD3DDevice->CreateVertexBuffer(sizeof(Verts)*4, 0, \ VERTEXFVF, D3DPOOL_DEFAULT, &g_pParticleVB); g_pParticleVB->Lock(0,0, (BYTE**)&Ptr, 0); memcpy(Ptr, Verts, sizeof(Verts)); g_pParticleVB->Unlock(); // Get textures // Получаем текстуру D3DXCreateTextureFromFile(g_pD3DDevice, "Particle.bmp", &g_pParticleTexture); // Create some particles // Генерим частицы g_pParticles = new sParticle[512](); return TRUE; }
- Сохрани Решение (Файл -> Сохранить все).
- Бесплатная IDE MS Visual C++ 2010 Express Edition;
- Бесплатный DirectX SDK 8.1 .
Сейчас мы это исправим.
Готовим Проект Particle01 к компиляции
Для успешной компиляции изменим настройки (=свойства) текущего Проекта, созданного в MSVC++2010. При этом сам код из книги 2002 года останется нетронутым.Обрати внимание
Напомним, что такую настройку необходимо повторно проделывать при создании каждого нового Проекта. Ниже представлен алгоритм действий по настройке Проекта, созданного в MSVC++2010 Express с применением DirectX SDK. При создании приложений под платформы, отличные от Win32, либо применении более новых версий DirectX SDK, процесс конфигурирования Проекта может отличаться от приведённого ниже.
Указываем пути к DirectX SDK 8.1
Если попытаться скомпилировать Проект Particle01 в таком виде, то ничего не выйдет.В единственном файле исходного кода WinMain.cpp можно увидеть инклуды различных заголовочных файлов DirectX (весии 8):
... // Include files #include <windows.h> #include <stdio.h> #include "d3d8.h" #include "d3dx8.h" ...
На данном этапе MSVC++2010 ничего не знает об их местоположении. В статье MS Visual Cpp 2010 Express. Установка и указание путей к DirectX SDK мы указывали пути к DirectX SDK (версии 9 и выше). Для DirectX SDK 8 это делается аналогично. Начнём.
- Убедись, что MSVC++2010 запущена и в ней открыт наш текущий Проект Particle01.
- Убедись, что DirectX SDK 8.1 установлен на компьютере и ты уверенно можешь назвать полный путь к его каталогу.
- Жмём правой кнопкой мыши по названию Проекта Particle01. Во всплывающем меню выбираем пункт "Свойства".
Или в Главном меню выбираем Проект->Свойства. Или нажимаем Alt+F7.
В появившемся меню свойств проекта выбираем Свойства конфигурации -> Каталоги VC+ + . В правой части этой страницы расположены пути ко всевозможным каталогам. Здесь нас интересуют только 2 строки: Каталоги включения и Каталоги библиотек.
Указываем каталог включений (include) DirectX SDK 8.1
- В меню свойств Проекта щёлкаем левой кнопкой мыши по пункту Каталоги включения. В правой части этой строки видим кнопку с чёрным треугольником, указывающим на наличие выпадающего меню. Нажимаем на неё -> выбираем "Изменить..."
В появившемся меню "Каталоги включения" жмём кнопку "Создать строку" (с жёлтой папкой) и указываем полный путь к заголовочным файлам DirectX SDK 8.1 (include). В нашем случае это C:\DXSDK8\include. Можно просто выбрать каталог из дерева каталогов, нажав кнопку с троеточием, расположенную справа от строки ввода.
- Жмём "ОК".
Указываем каталог библиотек (lib) DirectX SDK 8.1
- В меню свойств Проекта щёлкаем левой кнопкой мыши по пункту Каталоги библиотек. В правой части этой строки видим кнопку с чёрным треугольником, указывающим на наличие выпадающего меню. Нажимаем на неё -> выбираем "Изменить..."
- В появившемся меню "Каталоги библиотек" жмём кнопку "Создать строку" (с жёлтой папкой) и указываем полный путь к 32-разрядным версиям файлов библиотек DirectX SDK 8.1 (lib). В нашем случае это c:\DXSDK8\lib\. Можно просто выбрать каталог из дерева каталогов, нажав кнопку с троеточием, расположенную справа от строки ввода.
- Жмём "ОК".
- На Странице свойств тоже жмём "ОК".
- Сохрани Решение (File -> Save All).
Указываем пути к Windows SDK
Помимо указания путей к заголовкам (include) и библиотекам (lib) DirectX SDK, для любого DirectX-Проекта также необходимо указать пути к заголовкам (include) и библиотекам (lib) Windows SDK. Самое смешное, что в MS Visual C++ 2010 эти пути указываются по умолчанию для каждого создаваемого Проекта. В этом нетрудно убедиться, если ещё раз открыть Проект -> Свойства -> Свойства конфигурации - >Каталоги VC++ -> Каталоги включения -> Изменить. В окне "Каталоги включения" в нижней (недоступной для редактирования) части видим список "Унаследованные значения", где в третьей строке стоит значение:$(WindowsSdkDir)include
В результате видим, что добавленные пути к DirectX SDK (в обоих окнах: include и lib) расположены вверху списка, а пути к Windows SDK - в недоступной области, на несколько строк ниже.
Но! Заголовочным файлам DirectX SDK "жизненно важно", чтобы они включались после включений заголовков Windows SDK.
Важно!
Каталоги, пути к которым указаны в окнах "Каталоги включения" и "Каталоги библиотек" при компиляции считываются один за другим по списку сверху вниз. Поэтому для корректного указания путей надо разместить пути к Windows SDK выше, а к DirectX SDK - ниже по списку (чтобы они считывались последними).
В данной ситуации мы не можем поднять пути к Windows SDK, прописанные по умолчанию при создании Проекта, т.к. они расположены в специальной нередактируемой области (ограничение бесплатной версии MSVC++2010 Express). Но можем схитрить и добавить ещё раз пути к тем же самым каталогам Windows SDK, подняв эти строки выше строк DirectX SDK.
Выше мы указывали пути к DirectX SDK. Для путей к Windows SDK это делается аналогично. Начнём.
- Убедись, что MSVC++2010 запущена и в ней открыт Проект, с которым работаешь в данный момент.
- Убедись, что Windows SDK (в нашем случае версия 7) установлен на компьютере и ты уверенно можешь назвать полный путь к его каталогу.
- Жмём правой кнопкой мыши по названию Проекта. Во всплывающем меню выбираем пункт "Свойства".
Или в Главном меню выбираем Проект->Свойства. Или нажимаем Alt+F7.
В появившемся меню свойств проекта выбираем Свойства конфигурации -> Каталоги VC++ . В правой части этой страницы расположены пути ко всевозможным каталогам. Здесь нас, как и в прошлый раз, интересуют только 2 строки: Каталоги включения и Каталоги библиотек.
Указываем каталог включений (include) Windows SDK
- В меню свойств Проекта щёлкаем левой кнопкой мыши по пункту Каталоги включения. В правой части этой строки видим кнопку с чёрным треугольником, указывающим на наличие выпадающего меню. Нажимаем на неё -> выбираем "Изменить..."
В появившемся меню "Каталоги включения" жмём кнопку "Создать строку" (с жёлтой папкой) и указываем полный путь к заголовочным (include) файлам Windows SDK. В нашем случае (Win7 x64) это C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Include. Можно просто выбрать каталог из дерева каталогов, нажав кнопку с троеточием, расположенную справа от строки ввода.
- Меняй порядок считывания каталогов включений с помощью кнопок с чёрными стрелками в верхней части окна "Каталоги вложений".
- Жмём "ОК".
Указываем каталог библиотек (lib) Windows SDK
- В меню свойств Проекта щёлкаем левой кнопкой мыши по пункту Каталоги библиотек. В правой части этой строки видим кнопку с чёрным треугольником, указывающим на наличие выпадающего меню. Нажимаем на неё -> выбираем "Изменить..."
- В появившемся меню "Каталоги библиотек" жмём кнопку "Создать строку" (с жёлтой папкой) и указываем полный путь к папке с файлами библиотек (lib) Windows SDK. В нашем случае (Win7 x64) это C:\Program Files (x86)\MicrosoftSDKs\Windows\v7.0A\Lib. Можно просто выбрать каталог из дерева каталогов, нажав кнопку с троеточием, расположенную справа от строки ввода.
- Меняй порядок считывания каталогов вложений с помощью кнопок с чёрными стрелками в верхней части окна.
- Жмём "ОК".
- На Странице свойств тоже жмём "ОК".
- Сохрани Решение (File -> Save All). Готово.
Выбираем многобайтовую кодировку
Примечание
В MS Visual C++ 2010 в настройках по умолчанию стоит набор (кодировка) символов UNICODE. В MS Visual C++ 6.0 - напротив, по умолчанию стоит кодировка ANSI (многобайтовая). Данная настройка сильно влияет на типы используемых переменных, что приводит к заметным различиям в исходном коде.
Несмотря на то, что во всех случаях рекомендуется использовать кодировку UNICODE, поддерживаемую во всех современных ОС семейства MS Windows (начиная с Win 2000/XP), большинство книг по программированию игр на классическом C++ придерживаются именно многобайтовой кодировки. Чтобы сильно не переделывать исходные коды под UNICODE, данный Проект мы настроим под многобайтовую кодировку.
Чтобы сильно не переделывать исходные коды под UNICODE, все наши игровые Проекты мы настроим под многобайтовую кодировку. Для этого...
- Убедись, что MSVC++2010 запущена и в ней открыт наш текущий Проект Particle01.
- В Обозревателе решений щёлкаем правой кнопкой мыши по названию Проекта Particle01.
- Во всплывающем контекстном меню выбираем "Свойства".
- В появившемся окне установки свойств Проекта жмём Свойства конфигурации->Общие, в правой части в строке "Набор символов" выставляем значение "Использовать многобайтовую кодировку".
- Жмём ОК.
- Сохрани Решение (Файл->Сохранить все)
Отключаем инкрементную компоновку (incremental linking)
Инкрементная компоновка призвана сократить время компилирования. Но на деле её присутствие часто вызывает ошибки вроде этой:Error LNK1123: сбой при преобразовании в COFF: файл недопустим или поврежден
Ошибка LINK : fatal error LNK1123: failure during conversion to COFF: file invalid or corrupt
В MS Visual C++ 2010 даже компиляция консольных приложений нередко завершается неудачей, а вместо исполняемого файла программист видит сообщение:
LINK : fatal error LNK1123: failure during conversion to COFF: file invalid or corrupt.
ПРИЧИНА: MS Visual С++ 2010 "не нравится" версия .NET Framework, установленная в операционной системе. В общих чертах, MS Visual С++ 2010 спрограммирована для работы под управлением .NET Framework 4.0 и сильно к нему привязана. Если точнее, к нему сильно привязана система инкрементной компоновки приложений (incremental linking), которая по умолчанию включена для всех создаваемых проектов.
Во время установки MS Visual C++ 2010 пытается установить свой "родной" .NET Framework 4.0, проверяя версию этой программной платформы, установленную в ОС на данный момент. Если версия .NET Framework ниже 4.0, то она обновляется до 4.0 и всё прекрасно компилируется. Если версия .NET Framework выше 4.0, то всё оставляется как есть: IDE успешно завершает установку, но при компиляции ВСЕХ приложений выскакивает данная ошибка. Более того, ошибка была замечена даже при наличии в системе .NET Framework версии 4.0, но отличающейся от "родной" припиской вроде "Beta" или "Release Candidate".
ВАРИАНТЫ РЕШЕНИЙ:
1. Отключить инкрементную линковку в опциях Проекта.
В главном меню MSVC++2010 выбираем: Проект->Свойства->Свойства конфигурации->Компоновщик(Linker)->Включить инкрементное построение (Incremental Linking). Данный пункт по умолчанию включен для всех новых проектов. Выставляем его в Нет (No). И жмём OK. Инкрементное построение заметно сокращает время компилирования больших проектов. Но в нашем случае его отсутствие некритично.
2. Удалить (переместить в другое место) утилиту cvtres.exe из каталога bin установленной MS Visual C++ 2010.
В нашем случае (Win7 x64) полный путь до данного файла такой: C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\bin\cvtres.exe . Официальное название данного приложения - Microsoft® Resource File To COFF Object Conversion Utility (утилита конвертации файлов двоичных ресурсов в Component Object File Format). Опытным путём установлено, что при линковке IDE "спотыкается" именно об него.
3. Удалить из системы все версии .NET Framework (включая языковые пакеты и всякие профайлеры, если есть) и саму MS Visual C++ 2010.
Всё вышеперечисленное можно без труда найти в меню "Программы и компоненты" (MS Windows Vista/7/8). Затем заново установить MS Visual C++ 2010. При этом автоматом установится .NET Framework 4.0, идущий с ней в наборе.
Третий пункт - самый долгий. На деле почти всегда хватает выполнения первых двух. Данным вопросом озадачивались ребята здесь: https://www.cyberforum.ru/cpp-beginners/thread637174.html?ysclid=l3akpmanrq. После этого линковка (=компоновка) проходит идеально. Подобные "костыли" в IDE от Майков - не редкость. Можно предположить, что команда с головой ударилась в тестирование .NET-возможностей MSVC++2010, совсем забыв о Win32-направлении (либо признав его бесперспективным).
Отключим инкрементную компоновку в свойствах открытого Проекта. Для MS Visual C++ 2010 порядок следующий:
- Убедись, что MSVC++2010 запущена и в ней открыт Проект, с которым работаешь.
- В Обозревателе решений щёлкаем правой кнопкой мыши по названию Проекта.
- Во всплывающем контекстном меню выбираем "Свойства".
- В появившемся окне установки свойств Проекта жмём Свойства конфигурации -> Компоновщик -> Общие (Configuration Properties -> Linker -> General), в правой части в строке "Включить инкрементную компоновку" ставим значение Нет (/INCREMENTAL:NO).
- Жмём ОК.
Удаляем файл cvtres.exe
В нашем случае (Win7 x64) полный путь до данного файла такой: C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\bin\cvtres.exeВ Win32-кодинге он особо ни на что не влияет. Зато без него линковка идёт как по маслу.
Прописываем библиотеки d3dx8.lib, d3d8.lib и Winmm.lib в окне "Дополнительные зависимости" (Additional dependencies) компоновщика (Linker)
Данный этап проходил даже автор кода Jim Adams в 2002 году, прогая на MSVC++6.0. В начальных комментариях листинга WinMain.cpp он намекнул, что библиотеки D3D8.LIB, D3DX8.LIB и WINMM.LIB необходимо явно указывать в списке дополнительных зависимостей линкера ( = компоновщика):... Required libraries: WINMM.LIB, D3D8.LIB and D3DX8.LIB ...
Библиотеки D3D8.LIB и D3DX8.LIB расположены в папке с установленным DirectX SDK 8 (в нашем случае по пути C:\DXSDK8\lib\), пути к которой мы прописали выше.
Т.к. мы создаём исполняемое приложение (исполняемый .exe-файл), а не библиотеку, то после компиляции полученный объектный модуль сразу линкуется путём вызова компоновщика (=linker). Так вот, этот самый компоновщик по ранее прописанным каталогам данные библиотеки не ищет. Поэтому их необходимо указывать отдельно в окне настроек Проекта, в разделе "Компоновщик". ОК, начинаем.
- Убедись, что MSVC++2010 запущена и в ней открыт наш текущий Проект.
- В Главном меню MS Visual C++ 2010 выбираем Проект -> Свойства (Project -> Properties).
- В появившемся окне установки свойств Проекта последовательно щёлкаем по раскрывающимся ветвям иерархического дерева: Свойства конфигурации -> Компоновщик -> Ввод (Configuration Properties -> Linker -> Input).
- В правой части, напротив строки "Дополнительные зависимости" жмём кнопку с чёрным треугольником.
- В всплывающем списке жмём "Изменить".
- В появившемся окне "Дополнительные зависимости" в верхнем поле ввода прописываем в столбик (один под другим) имена файлов трёх библиотек:
d3d8.lib
Winmm.lib
Библиотека Winmm.lib отвечает за мультимедиа-возможности приложения и расположена в каталоге с установленным Windows SDK.
- Жмём ОК, ОК.
- Сохрани Решение (Файл->Сохранить все)
Отключаем использование компоновщиком библиотеки libci.dll
Да, даже на данном этапе компиляция Проекта выдаст ошибку. Библиотека libci.dll использовалась в VisualStudio когда-то очень давно, и в современных версях IDE её нет. Тем не менее компоновщик почти всегда вызывает её при компиляции, ругаясь на её отсутствие. Самый простой способ это исправить - запретить использовать libci.dll по умолчанию.ОК, начнём.
- Убедись, что MSVC++2010 запущена и в ней открыт Проект, с которым работаешь в данный момент.
- В Главном меню MS Visual C++ 2010 выбираем Проект -> Свойства (Project -> Properties).
- В появившемся окне установки свойств Проекта последовательно щёлкаем по раскрывающимся ветвям иерархического дерева: Свойства конфигурации -> Компоновщик -> Командная строка (Configuration Properties -> Linker -> Command Promt).
- Пишем в него строку: /NODEFAULTLIB:libci
- Жмём ОК.
- Сохрани Решение (Файл->Сохранить все).
Компилируем Проект Particle01
Наконец, наш тестовый Проект готов к компиляции.- Жми кнопку с зелёным треугольником на панели инструментов главного окна MSVC++2010 или F5 на клавиатуре.
Скомпилированное .exe-приложение в нашем случае (Win7 x64) расположено по пути C:\Users\<Имя пользователя>\Documents\Visual Studio 2010\Projects\Particle01\Debug .
После компиляции приложение Particle01 автоматически запустится и покажет окно с разноцветными прямоугольниками, разлетающимися из единого центра. На частицы они мало похожи. Ведь текстуру частицы пока никто не готовил.
Готовим текстуру
Если ты внимательно изучил код WinMain.cpp данного примера, то наверняка обратил внимание на строку загрузки текстуры:... // Get textures // Получаем текстуру D3DXCreateTextureFromFile(g_pD3DDevice, "Particle.bmp", &g_pParticleTexture); ...
Здесь в качестве текстуры используется файл изображение с расширением .bmp.
- Создай в Фотошопе или найди в Интернете любое изображение.
- Пересохрани его в формат .bmp (например с помощью приложений XNView или Paint), переименуй в Particle.bmp и размести в папке с полученным исполняемым .exe-файлом (по умолчанию C:\Users\<Имя пользователя>\Documents\Visual Studio 2010\Projects\Particle01\Debug).
- Перезапусти приложение Particle01.
Архив с готовым Проектом Particle01 (VC++2010)
Берём здесь: https://yadi.Sk/d/-SWmDcti3iTs6wЗаключение
С помощью общедоступных и совершенно бесплатных программных средств мы создали графическое приложение. Тем самым мы в очередной раз доказали, что для создания приложений под DirectX нужны только компьютер с ОС Windows и выход в Интернет. Светлая голова и желание тоже всячески приветствуются. Все примеры из DirectX SDK 8 компилируются таким же образом.Помимо формата .bmp, DirectX также поддерживает загрузку текстур из файлов формата .jpg (+ некоторых других).
- Проверь это, исправив ссылку в коде на загружаемый файл и разместив данный файл в папке с исполняемым .exe-файлом программы.
Источники
1. Adams J. Programming Role Playing Games with DirectX 8.0. - Premier Press, 2002
Последние изменения страницы Вторник 31 / Май, 2022 00:31:42 MSK
Последние комментарии wiki