Как мне прочитать куб Блендера по умолчанию?

#c #directx-11

Вопрос:

Я изучаю DirectX 11, и я очень запутался, посмотрев на куб Блендера по умолчанию, я экспортировал его в формат Wavefront OBJ, и вот файл, который у меня есть:

 # Blender v2.92.0 OBJ File: ''
# www.blender.org
mtllib untitled.mtl
o Cube
v 1.000000 1.000000 -1.000000
v 1.000000 -1.000000 -1.000000
v 1.000000 1.000000 1.000000
v 1.000000 -1.000000 1.000000
v -1.000000 1.000000 -1.000000
v -1.000000 -1.000000 -1.000000
v -1.000000 1.000000 1.000000
v -1.000000 -1.000000 1.000000
vt 0.625000 0.500000
vt 0.875000 0.500000
vt 0.875000 0.750000
vt 0.625000 0.750000
vt 0.375000 0.750000
vt 0.625000 1.000000
vt 0.375000 1.000000
vt 0.375000 0.000000
vt 0.625000 0.000000
vt 0.625000 0.250000
vt 0.375000 0.250000
vt 0.125000 0.500000
vt 0.375000 0.500000
vt 0.125000 0.750000
vn 0.0000 1.0000 0.0000
vn 0.0000 0.0000 1.0000
vn -1.0000 0.0000 0.0000
vn 0.0000 -1.0000 0.0000
vn 1.0000 0.0000 0.0000
vn 0.0000 0.0000 -1.0000
usemtl Material
s off
f 1/1/1 5/2/1 7/3/1 3/4/1
f 4/5/2 3/4/2 7/6/2 8/7/2
f 8/8/3 7/9/3 5/10/3 6/11/3
f 6/12/4 2/13/4 4/5/4 8/14/4
f 2/13/5 1/1/5 3/4/5 4/5/5
f 6/11/6 5/10/6 1/1/6 2/13/6
 

Я знаю, что секрет для его визуализации заключается в использовании предоставленных индексов, но я не уверен, как я должен реализовать буфер для этих данных, если бы вершины, uv и нормали были в одинаковом количестве, я мог бы организовать их в массив структур, но если бы они были в другом количестве, я не знаю, как бы я мог это сделать и создать буфер.

Ответ №1:

Формат Wavefront OBJ очень старомоден, но он существует уже давно, поэтому его хорошо понимают и довольно легко анализировать. Тем не менее, пакетам 3D-визуализации, таким как Blender, не нужно хранить свои данные в тех же форматах, которые вы обычно используете для рендеринга во время выполнения, поэтому ожидайте выполнения некоторой работы по изменению метода Wavefront OBJ отдельных индексов для каждого вида данных в формат вершин для однопоточной визуализации.

Другая проблема заключается в том, что объект Wavefront хранит лица как «n-углы», и вам нужно преобразовать его в треугольники, чтобы отрисовывать с помощью Direct3D 11. Вы также можете столкнуться с относительными индексами (т. е. отрицательными числами) для разных массивов. А затем нужно разобраться с mtl файлом.

Пример выполнения всего анализа и преобразования текстовых файлов на C можно найти на GitHub: WavefrontReader.h, который описан здесь.

 WaveFrontReader<uint16_t> wfReader;
Microsoft::WRL::ComPtr<ID3D11Buffer> vertexBuffer;
Microsoft::WRL::ComPtr<ID3D11Buffer> indexBuffer;

HRESULT hr = wfReader.Load(L"cube.obj");
if (FAILED(hr))
    // Error

D3D11_BUFFER_DESC bufferDesc = {};
bufferDesc.ByteWidth = static_cast<UINT>(wfReader.vertices.size() * sizeof(WaveFrontReader::Vertex));
bufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
bufferDesc.Usage = D3D11_USAGE_DEFAULT;

D3D11_SUBRESOURCE_DATA initData = { wfReader.vertices.data(), 0, 0 };

hr = device->CreateBuffer(amp;bufferDesc, amp;initData, amp;vertexBuffer);
if (FAILED(hr))
    // Error

bufferDesc.ByteWidth = static_cast<UINT>(wfReader.indices.size() * sizeof(uint16_t));
bufferDesc.bindFlags = D3D11_BIND_INDEX_BUFFER;
initData.pSysMem = wfReader.indices.data();
hr = device->CreateBuffer(amp;bufferDesc, amp;initData, amp;indexBuffer);
if (FAILED(hr))
    // Error
 
 UINT vertexStride = sizeof(WaveFrontReader::Vertex);
uint vertexOffset = 0;
deviceContext->IASetVertexBuffers(0, 1, vertexBuffer.GetAddressOf(), amp;vertexStride, amp;vertexOffset);

deviceContext->IASetIndexBuffer(indexBuffer.Get(), DXGI_FORMAT_R16_UINT, 0);
 

Распространенная стратегия-по крайней мере, в играх-состоит в том, чтобы выполнять весь этот анализ в автономном режиме и записывать приятный, удобный для графического процессора формат файла во время выполнения, который вы можете просто считывать в память и визуализировать. Для DirectX существует ряд «примерных» форматов VBO , таких как SDKMESH , или Visual Studio CMO . Использование этих инструментов обычно делает чтение буфера вершин и индексов во время выполнения тривиальным. См. Раздел meshconvert DirectXMesh, экспортер образцов содержимого DirectX SDK и конвейер содержимого Visual Studio. Код для загрузки и рендеринга всех этих форматов можно найти в наборе инструментов DirectX.

Конечно, для простой общей формы, такой как куб, вы можете просто создать ее непосредственно в памяти, вместо того, чтобы в первую очередь проходить через весь беспорядок анализа модели. Вот что GeometricPrimitive делает набор инструментов DirectX.

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