Загрузка мешей с использованием D3DX

Библиотека D3DX определяет удобный объект ID3DXMesh, который хранит и визуализирует трехмерные меши. Кроме этого вы можете использовать собственные специализированные контейнеры для хранения мешей, которые, я думаю, разумно использовать с ID3DXMesh. Этот объект я буду использовать до окончания этой главы (за исключением использования удобного объекта ID3DXSkinMesh, о котором я расскажу позже).

Самым быстрым способом загрузки данных меша при помощи D3DX является использование функций D3DXLoadMeshFromX и D3DXLoadMeshFromXof. Оба этих меша берут данные, хранимые в .X файле, и преобразуют их в объект ID3DXMesh. D3DXLoadMeshFromX сразу загружает весь файл .X (объединяя все меши в один), в то время как D3DXLoadMeshFromXof загружает один меш, указанный объектом IDirectXFileData.

Функция D3DXLoadMeshFromX имеет в качестве параметров имя загружаемого файла, некоторые флаги для контролирования загрузки, указатель на 3D устройство, указатели на буферы, содержащие данные материалов и различные указатели на данные, которые вы можете пока проигнорировать. Посмотрите на прототип функции D3DXLoadMeshFromX.

HRESULT D3DXLoadMeshFromX(

LPSTR pFilename, // Имя загружаемого .X файла DWORD Options, // Опции загрузки

LPDIRECT3DDEVICE9 pDevice, // указатель на трехмерное устройство LPD3DXBUFFER* ppAdjacency, // Установить в NULL LPD3DXBUFFER* ppMaterials, // Буфер для материалов

LPD3DXBUFFER* ppEffectlnstances, // Здесь не используется - NULL PDWORD pNumMaterials, // # загруженных материалов LPD3DXMESH* ppMesh) ; // Указатель на интерфейс меша

Приведенные комментарии являются самоописательными, так что сразу перейдем к рассмотрению использования функции D3DXLoadMeshFromX Для начала вам необходимо создать экземпляр объекта ID3DXMesh.

ID3DXMesh *Mesh = NULL;

Далее предположим, вы хотите загрузить файл .X, называемый "test.x". Все просто - вам необходимо указать имя файла при вызове функции D3DXLoad-MeshFromX ... но подождите! А как же параметр Options? Вы используете его, чтобы сказать D3DX как загружать меш - в системную или видео память, использовать память только для записи и так далее. Для каждой опции есть флаг. В таблице 3.3 приведен список основных макросов.

Таблица 3.3. Флаги D3DXLoadMeshFromX

Макрос

Описание

Р30ХМЕ8Н_32В1Т

Использовать 32-битные индексы (не всегда поддерживается)

030ХМЕ8Н_ІІ8ЕН/Л/ОМІУ

Использовать только аппаратную обработку. Использовать только те устройства, которые точно поддерживают аппаратное ускорение.

Р30ХМЕ8Н_8У8ТЕММЕМ

Хранить меш в системной памяти

Р30ХМЕ8Н_ШТЕОМ1_У

Установить данные меша только для записи, позволяя й^еШй находить лучшие расположения для хранения данных меша (обычно в видео памяти)

030ХМЕ8Н_РУМЛМІС

Использовать динамические буферы (для мешей, изменяющихся со временем)

□30ХМЕБН_8ОРТ№ЛРЕРРОСЕБ8ІМО

Использовать программную обработку вершин, используемую вместо движка аппаратного преобразования и освещения

Из таблицы 3.3 видно, что опций загрузки мешей на самом деле не так уж и много. Вообще-то, я бы рекомендовал вам использовать только D3DXMESHSYSTEMMEM или D3DXMESHWRITEONLY. Первая опция D3DXMESHSYSTEMMEM вынуждает храниться данным вашего меша в системной памяти, что ускоряет доступ к его данным для записи и чтения.

Задание флага D3DXMESHDYNAMIC означает, что вы собираетесь периодически изменять данные меша. Лучше всего устанавливать этот флаг, если вы собираетесь периодически изменять данные меша (вершины) во время выполнения.

Если вам необходима скорость, то я предлагаю использовать флаг 3DXMESH_WRITEONLY, который говорит D3DX использовать память, из которой нельзя читать. В большинстве случаев это означает использование видеопамяти, потому что она обычно (но не всегда) только для записи. Если вы не будете читать данные вершин меша, тогда используйте этот флаг.

Совет. Если вы не используете системную память или память только для записи, что остается использовать? Просто задайте в качестве параметра Options 0 при вызове D3DXLoadMeshFromX, и все будет нормально.

Возвращаясь к параметрам D3DXLoadMeshFromX, вы найдете указатель на интерфейс 3D устройства. Никаких проблем - хотя бы одно должно быть у вас в проекте! Следующий параметр - указатель на ID3DXBUFFER, ppAdjacency. Установите его в NULL, мы не будем его тут использовать.

Следующие три параметра ppMaterials, ppEffectInstance и pNumMaterials содержат информацию о материале, такую как значения цветов, название текстуры и данные эффектов. Если вы используете DirectX 8, вы можете безопасно удалить ссылку ppEffectInstance - она не существует в той версии. Если вы используте DirectX 9, вы можете установить ppEffectInstance в NULL, потому что вам не нужна никакая информация об эффектах.

Указатель ppMaterials указывает на интерфейс ID3DXBuffer, который является простым контейнером данных. pNumMaterials - это указатель на переменную DWORD, которая будет содержать количество материалов в загруженном меше. Вы узнаете, как использовать информацию о материалах немного позже.

Завершает список параметров D3DXLoadMeshFromX указатель на объект ID3DXMesh - ppMesh. Этот интерфейс вы предоставляете для хранения данных загруженного меша. Вот и все! Теперь объединим все это в работающий пример загрузки меша.

Загрузите меш, названный "test.x", используя память для записи. После создания указателя объекта меша вам необходимо создать экземпляр объекта ID3DXBuffer для хранения данных материала и переменную DWORD для хранения количества материалов.

ID3DXBuffer *pMaterials = NULL;

DWORD NumMaterials;

После этого вызываем D3DXLoadMeshFromX.

// pDevice = указатель на правильный объект IDirect3DDevice9 D3DXLoadMeshFromX("test.x", D3DXMESH_WRITEONLY, pDevice, \ NULL, &pMaterials, NULL, &NumMaterials, &Mesh);

Замечательно! Если все прошло, как и было задумано, D3DXLoadMeshFromX вернет код успешного завершения, и ваш меш загрузится в интерфейс ID3DXMesh! Конечно, все меши, содержащиеся в файле, были объединены в один меш, но как насчет тех случаев, когда необходимо получить доступ к каждому отдельно определенному мешу в файле?

Вот здесь то и появляется D3DXLoadMeshFromXof. Вы можете использовать D3DXLoadMeshFromXof в сочетании с вашим анализатором .X для загрузки данных меша из перечисленного объекта Mesh. Посмотрите на прототип функции

D3DXLoadMeshFromXof.

HRESULT D3DXLoadMeshFromXof(

LPDIRECTXFILEDATA pXofObjMesh, DWORD Options,

LPD3DXBUFFER* ppMaterials, LPD3DXBUFFER* ppEffectInstances, PDWORD pNumMaterials, LPD3DXMESH* ppMesh);

Подождите-ка! D3DXLoadMeshFromXof выглядит практически так же как D3DXLoadMeshFromX! Единственным отличием является первый параметр, вместо указания имени загружаемого .X файла, D3DXLoadMeshFromXof использует указатель на объект IDirectXFileData. Задав указатель на текущий перечисляемый объект IDirectXFileData, D3DX загрузит все необходимые данные меша! И так как оставшиеся параметры совпадают с D3DXLoadMeshFromX, у вас не возникнет трудностей с использованием D3DXLoadMeshFromXof в вашем классе анализатора .X!

Остановимся на этом, потому что вы увидите, как использовать D3DXLoadMeshFromXof в вашем классе анализатора далее в этой главе, в разделе "Загрузка мешей, используя анализатор .X ".

Независимо от используемой функции для загрузки данных меша (D3DXLoadMeshFromX или D3DXLoadMeshFromXof) все, что вам остается сделать после загрузки меша в объект ID3DXMesh - это обработать информацию о материалах.

Для обработки информации о материалах вам необходимо получить указатель на буфер данных ID3DXBuffer (используемый при вызове D3DXLoadMeshFromX или D3DXLoadMeshFromXof), и преобразовать его к типу D3DXMATERIAL. После этого обработать все материалы, используя количество материалов сохраненных в NumMaterials. После этого вам необходимо создать массив структур D3DMATERIAL9 и интерфейсов IDirect3DTexture9 для хранения данных материалов меша. Используйте следующий код для обработки информации материалов:

// Объекты для хранения данных материалов и текстур D3DMATERIAL9 *Materials = NULL; IDirect3DTexture9 *Textures = NULL;

// Получить указатель на данные материалов D3DXMATERIAL *pMat;

pMat = (D3DXMATERIAL*)pMaterials->GetBufferPointer() ;

// Выделить пространство для хранения материала

if(NumMaterials) {

// Loading Meshes from .X

Materials = new D3DMATERIAL9[NumMaterials] ; Textures = new IDirect3DTexture9*[NumMaterials];

// Просмотреть все загруженные материалы for(DWORD i=0;i<NumMaterials;i++) {

// Скопировать информацию о материале

Materials[i] = pMat[i].MatD3D; // Копировать рассеянный цвет в окружающий Materials[i].Ambient = Materials[i].Diffuse;

// Загрузить текстуру, если задана Textures[i] = NULL; if(pMat[i].pTextureFilename) { D3DXCreateTextureFromFile(pDevice, \

pMat[i].pTextureFilename, &Textures[i]);

}

}

} else {

// Создать материал по умолчанию, если не загрузился Materials = new D3DMATERIAL9[1]; Textures = new IDirect3DTexture9*[1];

// Установить по умолчанию белый материал без текстуры Texturebis[0] = NULL;

ZeroMemory(&Materials[0], sizeof(D3DMATERIAL9)); Materials[0].Diffuse.r = Materials[0].Ambient.r = 1.0f; Materials[0].Diffuse.g = Materials[0].Ambient.g = 1.0f; Materials[0].Diffuse.b = Materials[0].Ambient.b = 1.0f; Materials[0].Diffuse.a = Materials[0].Ambient.a = 1.0f;

}

/ / Освободить буфер данных материала pMaterials->Release() ;

Вы можете видеть в предыдущем коде, что я добавил проверку случая, когда материал не был загружен, а создается материал, используемый по умолчанию. После загрузки материалов вы можете использовать интерфейс меша для визуализации. В главе 1 было показано, как использовать интерфейс меша для его визуализации. А пока вернемся к теме, о которой я говорил ранее - загрузка мешей, используя анализатор .X.

Загрузка мешей из .X || Оглавление || Загрузка мешей, используя анализатор .X