日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【DirectX12】4.用FBX_SDK读取网格数据

發布時間:2024/9/30 编程问答 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【DirectX12】4.用FBX_SDK读取网格数据 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

用FBX_SDK讀取網格數據

1.前言

前一篇講了如何配置FBX_SDK,這一篇來看如何讀取模型的網格數據,效果如下:

2.導出

首先隨便創建一個場景,然后導出:

在導出的時候勾選上三角算法,將網格全部以三角形面的形式存儲,這樣方便DirectX的API使用:

有些模型在導出三角面時會失敗,我在3ds max里轉化為可編輯多邊形后就導出成功了。

當然也可以在代碼中執行轉換的操作,不過編輯器里都會轉換失敗,代碼就也很可能轉換失敗,所以我還是在編輯器里導出時就轉換好。

3.具體代碼

DX需要的是頂點緩存和索引緩存,所以先定義一個類來緩存數據,如果以后有需要也可以方便實現自己的3D模型中轉文件,這樣不僅加快讀取速度,并且可以避免版權問題。

所以如下,先用兩個vector保存頂點和索引:

class MeshObject { public:UINT64 GetVertexDataSize(){return _vecVertex.size() * sizeof(DirectX::Vertex);}UINT8* GetVertexData(){return (UINT8*)(_vecVertex.data());}UINT64 GetIndexDataSize(){return _vecIndex.size() * sizeof(UINT32);}UINT8* GetIndexData(){return (UINT8*)(_vecIndex.data());}vector<Vertex> _vecVertex;vector<UINT32> _vecIndex; };

先初始化FBX_SDK,設置iosetting,創建一個importer

// Initialize the SDK manager. This object handles all our memory management. FbxManager* _lSdkManager = FbxManager::Create();// Create the IO settings object. FbxIOSettings* ios = FbxIOSettings::Create(_lSdkManager, IOSROOT); _lSdkManager->SetIOSettings(ios);// Create an importer using the SDK manager. FbxImporter* lImporter = FbxImporter::Create(_lSdkManager, "");

然后用importer加載文件:

if (!lImporter->Initialize(lFilename, -1, _lSdkManager->GetIOSettings())) {//error }

接著用importer創建一個scene,然后釋放importer,遍歷scene的根節點,完成后再釋放內存:

// Create a new scene so that it can be populated by the imported file. FbxScene* lScene = FbxScene::Create(_lSdkManager, "myScene");// Import the contents of the file into the scene. lImporter->Import(lScene);// The file is imported; so get rid of the importer. lImporter->Destroy();// Print the nodes of the scene and their attributes recursively. // Note that we are not printing the root node because it should // not contain any attributes. MeshObject* ret = nullptr; FbxNode* lRootNode = lScene->GetRootNode(); if (lRootNode) {ret = _init_mesh_object(lRootNode);/*for (int i = 0; i < lRootNode->GetChildCount(); i++)PrintNode(lRootNode->GetChild(i));*/ } // Destroy the SDK manager and all the other objects it was handling. _lSdkManager->Destroy();

_init_mesh_object函數,我們傳入根節點,然后讀取了網格數據。從root_node遍歷有可能得到多個Mesh,下面的代碼處理了一下,將多個Mesh放到了一起,當然也可以分開放:

DND::MeshObject* DNDFBX::_init_mesh_object(FbxNode* root_node) {if (!root_node)return nullptr;MeshObject* ret = new MeshObject;int last_index = 0;//上一個模型的最大索引for (int i = 0; i < root_node->GetChildCount(); i++){FbxNode* p_node = root_node->GetChild(i);for (int j = 0; j < p_node->GetNodeAttributeCount(); j++){FbxNodeAttribute* p_attribute = p_node->GetNodeAttributeByIndex(j);if (p_attribute->GetAttributeType() == FbxNodeAttribute::eMesh){FbxMesh* mesh = p_attribute->GetNode()->GetMesh();if (mesh == NULL){return nullptr;}//數據是以形狀存儲的,會有重復的頂點,所以需要計算索引緩存int count_polygon = mesh->GetPolygonCount();//g_debug.Line(to_wstring(count_polygon));ret->_vecVertex.resize(last_index + count_polygon * 3);//已初始化標記vector<bool> vec_inited;vec_inited.resize(count_polygon * 3, false);int max_index = 0;for (int k = 0; k != count_polygon; ++k){if (mesh->GetPolygonSize(k) != 3){g_debug.Line(L"模型數據未三角化!");continue;}FbxVector4* ctrl_point = mesh->GetControlPoints();for (int l = 0; l != 3; ++l){int index = mesh->GetPolygonVertex(k, l);if (index == -1){g_debug.Line(L"獲取頂點失敗!");continue;}max_index = max(index, max_index);//依次記錄頂點的索引,而頂點數據只存放一次//g_debug.Line(to_wstring(index));//g_debug.Line(String::Format(L"(%.0lf)(%.0lf)(%.0lf)", ctrl_point[index][0], ctrl_point[index][1], ctrl_point[index][2]));ret->_vecIndex.push_back(last_index + index);if (!vec_inited[index]){vec_inited[index] = true;ret->_vecVertex[last_index + index].position.x = (float)(ctrl_point[index][0]) * 0.01f;ret->_vecVertex[last_index + index].position.y = (float)(ctrl_point[index][1]) * 0.01f;ret->_vecVertex[last_index + index].position.z = -(float)(ctrl_point[index][2]) * 0.01f;ret->_vecVertex[last_index + index].color = { 1.0f, 1.0f, 1.0f, 1.0f };}}}last_index += max_index + 1;}}}ret->_vecVertex.resize(last_index + 1);return ret; }

4.數據傳遞到DX

頂點緩存和索引緩存都是需要通過上載堆傳遞數據,使用com_ptr的局部變量需要在完成GPU的數據上傳后才能被釋放。這一部分比較麻煩,后面再詳細捋一捋。

HRESULT hr = S_OK; //-------------------------------------------------頂點緩存------------------------------------------------------------ // Create the vertex buffer. //默認堆需要上載堆傳遞CPU數據CD3DX12_HEAP_PROPERTIES heapProps0(D3D12_HEAP_TYPE_DEFAULT); auto desc0 = CD3DX12_RESOURCE_DESC::Buffer(mesh_object->GetVertexDataSize()); hr = g_dx._device->CreateCommittedResource(&heapProps0,D3D12_HEAP_FLAG_NONE,&desc0,D3D12_RESOURCE_STATE_COPY_DEST,nullptr,IID_PPV_ARGS(&_vertexBuffer)); if (FAILED(hr)) {g_debug.Line(L"創建頂點緩存失敗(DEFAULT)!");return; }//上載堆 com_ptr<ID3D12Resource> vertexBufferUploadHeap;CD3DX12_HEAP_PROPERTIES heapProps1(D3D12_HEAP_TYPE_UPLOAD); auto desc1 = CD3DX12_RESOURCE_DESC::Buffer(mesh_object->GetVertexDataSize());hr = g_dx._device->CreateCommittedResource(&heapProps1,D3D12_HEAP_FLAG_NONE,&desc1,D3D12_RESOURCE_STATE_GENERIC_READ,nullptr,IID_PPV_ARGS(&vertexBufferUploadHeap)); if (FAILED(hr)) {g_debug.Line(L"創建頂點緩存失敗(UPLOAD)!");return; } _vertexBuffer->SetName(L"vb0");// Copy data to the intermediate upload heap and then schedule a copy // from the upload heap to the vertex buffer. //從內存復制到上載堆,再復制到GPU D3D12_SUBRESOURCE_DATA vertexData = {}; vertexData.pData = mesh_object->GetVertexData(); vertexData.RowPitch = mesh_object->GetVertexDataSize(); vertexData.SlicePitch = vertexData.RowPitch;UpdateSubresources<1>(g_dx._commandList.get(), _vertexBuffer.get(), vertexBufferUploadHeap.get(), 0, 0, 1, &vertexData);auto num_barrier = CD3DX12_RESOURCE_BARRIER::Transition(_vertexBuffer.get(), D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER); g_dx._commandList->ResourceBarrier(1, &num_barrier);// Initialize the vertex buffer view. //創建頂點緩存視圖 _vertexBufferView.BufferLocation = _vertexBuffer->GetGPUVirtualAddress(); _vertexBufferView.StrideInBytes = sizeof(DirectX::Vertex); _vertexBufferView.SizeInBytes = mesh_object->GetVertexDataSize();//-------------------------------------------------索引緩存------------------------------------------------------------CD3DX12_HEAP_PROPERTIES heapProps2(D3D12_HEAP_TYPE_DEFAULT); auto desc2 = CD3DX12_RESOURCE_DESC::Buffer(mesh_object->GetIndexDataSize());hr = g_dx._device->CreateCommittedResource(&heapProps2,D3D12_HEAP_FLAG_NONE,&desc2,D3D12_RESOURCE_STATE_COPY_DEST,nullptr,IID_PPV_ARGS(&_indexBuffer)); if (FAILED(hr)) {g_debug.Line(L"創建索引緩存失敗(DEFAULT)!");return; }com_ptr<ID3D12Resource> indexBufferUploadHeap;CD3DX12_HEAP_PROPERTIES heapProps3(D3D12_HEAP_TYPE_UPLOAD); auto desc3 = CD3DX12_RESOURCE_DESC::Buffer(mesh_object->GetIndexDataSize());hr = g_dx._device->CreateCommittedResource(&heapProps3,D3D12_HEAP_FLAG_NONE,&desc3,D3D12_RESOURCE_STATE_GENERIC_READ,nullptr,IID_PPV_ARGS(&indexBufferUploadHeap));_indexBuffer->SetName(L"ib0");// Copy data to the intermediate upload heap and then schedule a copy // from the upload heap to the index buffer. D3D12_SUBRESOURCE_DATA indexData = {}; indexData.pData = mesh_object->GetIndexData(); indexData.RowPitch = mesh_object->GetIndexDataSize(); indexData.SlicePitch = indexData.RowPitch;UpdateSubresources<1>(g_dx._commandList.get(), _indexBuffer.get(), indexBufferUploadHeap.get(), 0, 0, 1, &indexData); auto num_barrier1 = CD3DX12_RESOURCE_BARRIER::Transition(_indexBuffer.get(), D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_INDEX_BUFFER); g_dx._commandList->ResourceBarrier(1, &num_barrier1);// Describe the index buffer view. _indexBufferView.BufferLocation = _indexBuffer->GetGPUVirtualAddress(); _indexBufferView.Format = DXGI_FORMAT_R32_UINT; _indexBufferView.SizeInBytes = mesh_object->GetIndexDataSize();_numIndices = mesh_object->GetIndexDataSize() / 4; // R32_UINT (SampleAssets::StandardIndexFormat) = 4 bytes each.

5.模型位置

之所以最終繪制出的模型都在原點,是因為FBX的單個模型的頂點都是以自身坐標系的,而自身的位置屬性(位移、旋轉、縮放)通過以下面方式得到:

FbxDouble3 translation = pNode->LclTranslation.Get(); FbxDouble3 rotation = pNode->LclRotation.Get(); FbxDouble3 scaling = pNode->LclScaling.Get();

其后可以通過構造矩陣,在讀取時就變換到整體的坐標系,比如一個大的游戲場景,有很多固定不動的物體,我們就不必分開處理,直接當成一個整體模型來處理。

如果是動態的、反復出現的模型,就需要單獨保存,通過上傳矩陣到著色器來計算位置。

6.結語

目前我也只是一步一步的嘗試,有很多不完善的地方,此文章只是簡單說一下,等以后理解得比較透徹后再詳細一步一步的說明。

代碼上傳到了這兒:

https://gitee.com/lveyou/dnd3d

接下來做一下按鍵檢測,來控制鏡頭,方便詳細的觀察模型,好弄清楚它們的坐標系到底是怎樣的。

總結

以上是生活随笔為你收集整理的【DirectX12】4.用FBX_SDK读取网格数据的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。