Извлечение текстурированных 3D моделей из приложений Direct3D — Архив WASM.RU
1. Введение
2. Идея
3. Алгоритмы
4. Реализация
5. Результаты
6. Применение
7. Источники
1. Введение
Целью статьи является исследование принципов, позволяющих извлекать трехмерные текстурированные модели из приложений Direct3D.
Задача: Разработать и проверить реализацией методы, которые позволяли бы (без принципиальных изменений) извлекать 3D модели и текстуры из любых приложений, использующих Direct3D.
Требования и ограничения: В силу жесткого ограничения по времени исследования, реализация разработанных методов должна позволять:
- Извлекать данные из приложений Direct3D 8, поставляемых с SDK (dx8sdk\samples\Multimedia\Direct3D\bin\), в силу того, что их исходный код легко доступен каждому;
- Работать с приложениями не использующие шейдеры (для простоты реализации);
- Сохранять: текущий установленный материал, значения вершинного буфера из потока 0, текущие значения буфера индексов и текстуру с индексом 0.
2. Идея:
Идея состоит в подмене функций COM объектов Direct3D, из которых доступны необходимые для извлечения данные.
Все рассматриваемые приложения (1.1), используют для создания COM объекта Direct3D8 функцию Direct3DCreate8 из d3d8.dll. Эта функция возвращает адрес указателя на таблицу указателей на функции объекта Direct3D8 (согласно интерфейсу IDirect3D8). Необходимо ее подменить. При вызове функций CreateDevice из COM объекта Direct3D8 создается COM объект Direct3DDevice8 – основной объект приложения, использующего Direct3D, этот объект имеет функцию DrawIndexedPrimitive, которая используется для «отрисовки» трехмерных моделей в (1.1). Подмены функции IDirect3D8.CreateDevice, на функцию, которая выполнит действительную CreateDevice и подменит в объекте IDirect3DDevice8 DrawIndexedPrimitive, которая выполнит:
вполне достаточно для реализации цели.
- cохранение данных в файлы mesh.x и tex.bmp;
- вызов действительной функции DrawIndexedPrimitive;
- возврат к выполнению программы.
Вся необходимая исходная информация получена из [1], [2], [3], [4], [5].3. Алгоритмы
- Подмена библиотеки d3d8.dll естественно позволяет подменить функцию Direct3DCreate8. Для этого необходимо создать соответствующую библиотеку dll, экспортирующую Direct3DCreate8 и скопировать ее в директорию целевого приложения [6].
- Подмена функций СОМ объектов производится записью в таблицу адресов реализованных согласно (2) функций, с сохранением адресов действительных функций.
- Параметр obj объектно-ориентированных подмененных функций позволяет получить доступ ко всем функциям COM объекта, и выполнить сохранение необходимых данных.
4. Реализация
Реализация произведена в Flat assembler – version 1.62 by Tomasz Grysztar. При реализации проверка ошибок вызовов сознательно игнорируется, как не входящая в рамки рассматриваемой работы (целью которой не является создание приложения сохраняющего модели из любых программ).
1. Создание dll базируется на примере, поставляемом с fasm. Приведем реализацию функции Direct3DCreate8:; реализация экспортируемой функции Direct3DCreate8. d3d8lib db 'c:\windows\system32\d3d8.dll',0 ; путь к «дейсвительной» библиотеке d3d8proc db 'Direct3DCreate8',0 ; имя «действительной» фунции proc MyDirect3DCreate8 SDKVersion invoke LoadLibrary,d3d8lib ; загрузка d3d8.dll invoke GetProcAddress,eax,d3d8proc ; получение адреса Direct3DCreate8 stdcall eax,[SDKVersion] ; выполнение «действительной» Direct3DCreate8 ; сохранение адреса IDirect3D8.CreateDevice в переменную CreateDevice и замещение его на адрес MyCreateDevice stdcall replace,[eax],IDirect3D8_CreateDevice,MyCreateDevice,CreateDevice ret endp2. Функция замещения адресов в таблице адресов функций COM объекта имеет следующие параметры: IntTblAddr – адрес таблицы, MethodNumber – номер функции, NewFunction — адрес замещающей функции, SaveOldFunction – адрес переменной для сохранения адреса исходной функции.
; реализация функции замещения адресов в COM интерфейсах proc replace IntTblAddr,MethodNumber,NewFunction,SaveOldFunction push eax push ebx ; вычисление адреса элемента инерфейса MethodNumber*4+IntTblAddr. mov eax,[MethodNumber] shl eax,2 add eax,[IntTblAddr] ; проверка: не заменена ли уже функция. mov ebx,[eax] cmp [NewFunction],ebx je AlreadyReplaced ; сохранение адреса исходной функции push eax mov eax,[SaveOldFunction] mov [eax],ebx ; запись адреса замещающей функции mov eax,[esp] invoke VirtualQuery,eax,mbi,MEMORY_BASIC_INFORMATIONsz mov eax,[esp] push [mbi.Protect] invoke VirtualProtect,eax,4,PAGE_EXECUTE_READWRITE,esp add esp,4 pop eax mov ebx,[NewFunction] mov [eax],ebx ; непосредственно запись push PAGE_EXECUTE_READWRITE invoke VirtualProtect,eax,4,[mbi.Protect],esp add esp,4 AlreadyReplaced: pop ebx pop eax ret endp3. Реализация функций MyCreateDevice и MyDrawIndexedPrimitive является типовой для всех замещаемых функций. В MyCreateDevice вызывается CreateDevice и замещается DrawIndexedPrimitive. В MyDrawIndexedPrimitive, если нажата клавиша F12 происходит сохранение данных, далее вызывается DrawIndexedPrimitive. Параметры функций соответствуют параметрам замещенных [6]:
; реализация замещающих функций proc MyCreateDevice obj,Adapter,DeviceType,hFocusWindow,BehaviorFlags,pPresentationParameters,ppReturnedDeviceInterface ; Вызов исходной функции IDirect3D8.CreateDevice invoke CreateDevice,[obj],[Adapter],[DeviceType],[hFocusWindow],[BehaviorFlags],[pPresentationParameters],[ppReturnedDeviceInterface] ; получение адреса таблицы адресов функций объекта Direct3DDevice8 push eax mov eax,[ppReturnedDeviceInterface] mov eax,[eax] ; замена DrawIndexedPrimitive stdcall replace,[eax],IDirect3DDevice8_DrawIndexedPrimitive,MyDrawIndexedPrimitive,DrawIndexedPrimitive pop eax ret endp proc MyDrawIndexedPrimitive obj,Type,MinIndex,NumVertices,StartIndex,PrimitiveCount ; проверка нажатия F12 invoke GetAsyncKeyState,VK_F12 test eax,eax jns donotsave ; сохранение модели stdcall Save, [obj] donotsave: ; вызов исходной DrawIndexedPrimitive invoke DrawIndexedPrimitive,[obj],[Type],[MinIndex],[NumVertices],[StartIndex],[PrimitiveCount] ret endp4. Реализация функции сохранения текстуры и трехмерного объекта не представляет особого интереса с точки зрения текущего исследования, приведем ее вкратце:
- У объекта obj получим установленную текстуру IDirect3DDevice8.GetTexture;
- Далее сохраним текстуру с помощью D3DXSaveTextureToFile;
- Получим текущий материал IDirect3DDevice8.GetMaterial;
- Установим в материале имя файла текущей текстуры;
- Получим объект индексов Direct3DIndexBuffer8 через IDirect3DDevice8.GetIndices;
- Определим формат индексов и размер буфера индексов IDirect3DIndexBuffer8.GetDesc;
- Посчитаем количество треугольников в 3D объекте: (размер буфера индексов)/(размер одного индекса)/3;
- Получим объект Direct3DVertexBuffer8, хранящий данные вершин: IDirect3DDevice8.GetStreamSource;
- Получим описание размера буфера вершин: IDirect3DVertexBuffer8.GetDesc;
- Получим размер одной вершины: D3DXGetFVFVertexSize;
- Посчитаем количество всех вершин: (размер буфера)/(размер одной вершины);
- Создадим объект D3DXMesh для сохранения данных в файл: D3DXCreateMeshFVF;
- Откроем буфер вершин obj для чтения, а D3DXMesh – для записи: IDirect3DVertexBuffer8.Lock, ID3DXMesh.LockVertexBuffer;
- Запишем данные в буфер объекта D3DXMesh;
- Закроем буферы: IDirect3DIndexBuffer8.Lock, ID3DXMesh.LockIndexBuffer;
- Выполним шаги 12 – 14 для индексов;
- Сохраним данные в файл формата DirectX: D3DXSaveMeshToX.
5. Результаты
Созданная программа (несмотря на существенные ограничения ее применимости) позволяет доказать реализуемость рассматриваемой технологии.
6. Возможное применение
Наиболее эффективные, на мой взгляд, способы применения описанной технологии в приложениях Direct3D это:
- Модификация трехмерных объектов приложений и их текстур;
- Извлечение моделей из приложений и использование их в собственных целях (если это не нарушает авторских прав создателей);
- При замещении всех функций интерфейсов Direct3D возможна реализация «трехмерных» копий сцен приложений.
7. Достаточные источники:
© FrostFix
- Эш Рофэйл, Яссер Шохауд. COM и COM+. Полное руководство. Пер. с англ. – К.: ВЕК +, К.: НТИ, М.: Энтроп, 2000.
- April 2003 Release of the MSDN Library.
- d3d8.h, входящий в состав Microsoft Development Environment 2003.
- d3dfile.cpp из DirectX8 SDK.
- DirectX 8.1 Programmer's Reference.
- Рихтер Дж. Windows для профессионалов: создание эффективных Win32-приложений с учетом специфики 64-разрядной версии Windows/Пер. с англ. – 4-у изд. — СПб: Питер; М.: Издательско-торговый дом «Русская редакция», 2001.
Извлечение текстурированных 3D моделей из приложений Direct3D
Дата публикации 17 мар 2006