DirectX 8 - Урок 4. Работа с моделями
Как вы помните, на протяжении всех трех наших предыдущих уроков, мне приходилось для
демонстрации использовать простые фигуры, такие как треугольник и квадрат.
Выглядело это достаточно красиво, но было очень не солидно, и поэтому я решил
кардинально исправить это положение. Покопавшись немного в первоисточниках, я с
радостью обнаружил, что в DirectX SDK есть много красивых моделей, которые
хранятся в файлах с расширением *.X. Так и приходит
на ум ассоциация с известным сериалом .... - ну вы поняли с каким. Так что же
они собой представляют?
Вы знаете из нашего первого примера, что каждый
объект или модель состоит из набора треугольников, которым соответствует
конечное множество вершин. В *.X файле хранятся не
только эти данные, но и названия файлов текстур, параметры материалов, анимация
и многое другое. Но сейчас для нас главное получит список вершин и образуемых
ими список треугольников, чтобы нарисовать модель. Для этого в Direct3D есть
класс модели ID3DXMesh (дословно Mesh означает "сетка").
int LoadMesh(void)
{
if(FAILED(D3DXLoadMeshFromX("bigship1.x", D3DXMESH_SYSTEMMEM,
d3d_device,NULL,NULL,
NULL,&d3dx_mesh))) return 0;
if(d3dx_mesh->GetFVF()&D3DFVF_XYZ)
i_size_of_mesh_vertex += sizeof(float)*3;
if(d3dx_mesh->GetFVF()&D3DFVF_NORMAL)
i_size_of_mesh_vertex += sizeof(float)*3;
if(d3dx_mesh->GetFVF()&D3DFVF_TEX1)
i_size_of_mesh_vertex += sizeof(float)*2;
d3dx_mesh->GetVertexBuffer(&d3d_vb);
d3dx_mesh->GetIndexBuffer(&d3d_ib);
return 1;
} |
Чтобы загрузить данные модели из файла и проинициализировать объект класса ID3DXMesh, воспользуемся функцией D3DXLoadMeshFromX. После этого можно
вычислить размер данных, отводящихся под одну вершину, и получить указатели на буфер вершин и индексный буфер.
Ну если с буфером вершин все ясно и понятно, и мы знаем, зачем он нужен, то причем
тут еще какой-то индексный буфер? А все дело в том, что крайне неэффективно
хранить в буфере вершин информацию о всех треугольниках и их вершинах. Если
взять к примеру куб, то видно, что мы вынуждены дублировать каждую его вершину
по несколько раз. Подсчитаем: 12 треугольников * 3 вершины на каждый
треугольник, получаем 36 вершины, а их на самом деле всего 8. А представьте,
если в нашей модели 10000 треугольников? Вот так-то!
Для этого и появилась необходимость в дополнительном индексном буфере. В этом
буфере, как понятно из названия, хранятся только индексы вершин из
соответствующего буфера, которые образуют треугольники. А так как размер одного
индекса составляет всего два байта, налицо явная экономия пространства и времени
(простите, я хотел сказать - памяти и времени обработки). Немного изменим
функцию прорисовки сцены.
d3d_device->SetVertexShader(d3d_vertex_shader);
d3d_device->SetStreamSource(0,d3d_vb,i_size_of_mesh_vertex);
d3d_device->SetIndices(d3d_ib,0);
d3d_device->DrawIndexedPrimitive(D3DPT_TRIANGLELIST,
0,d3dx_mesh->GetNumVertices(),
0,d3dx_mesh->GetNumFaces()); |
Функцией SetStreamSource наш буфер вершин назначается в нулевой поток, а функцией SetIndices
текущим индексным буфером становится d3d_ib. Прорисовка сцены теперь выполняется с помощью DrawIndexedPrimitive, к аргументам которой добавились
начальный номер индекса и общее количество вершин d3dx_mesh->GetNumVertices().
Рисунок 1. Модель космического коробля
В итоге мы получили очень красивую модель космического коробля. Исходный текст
этой программы и exe-файл вы можете взять
здесь. Также
в архиве вы найдете еще два файла с моделями: дельфин и биплан. Попробуйте их,
но не забудьте в функции SetMatrices поменять масштабный коэффициент f_scale на другой, т.к. все
модели разного масштаба.
Взято с DirectX Design
|