Github源工程:https://github.com/ColorGalaxy/UE4-Batch-Draw-Mesh-And-OpenGL-Get-Model-Data
😊覺得贊,記得點Star⭐
目錄
一、功能需求
想必你肯定會問我一個問題,UE4直接導入模型不好麼?
哈哈,前提是在做畢設時,導師提供的只有頂點與面索引數據,沒有模型。
下文詳細介紹了畢設開發中的難點,涉及三篇其他文章。
後來學習了《LearnOpenGL模型加載》一章後,能夠通過Assimp庫讀取obj模型並在窗口中繪製了。
因此十分好奇,我能否也可以經由C++輸出與畢設相同格式的模型頂點與面片數據集。
二、成果
1.輸出的CSV表格在MeshData文件夾下,比如這是個簡單的三棱錐(方便調試查找BUG)輸出的點面數據集。
2. 3ds max建一個茶壺,通過Opengl窗口繪製顯示,然後輸出點面數據道CSV表格,最後導入UE4中繪製。
三、環境配置
我將該項目所需的第三方庫文件GLFW、GLAD、ASSIMP、stb_image.h均放在了項目中,並設置了相對路徑防止路徑丟失。
若有疑問或想嘗試,也可去LearnOpenGL網址學習自行配置。
四、詳細步驟
4.1 Max製作三棱錐並處理
用自帶的工具欄新建簡單的三棱錐,轉換爲可編輯多邊形,可以看到頂點、邊還是很多。
通過邊刪除、點去除、焊接、邊界封口,去掉多餘的邊、頂點,轉化成一個只包含四個頂點,四個面的簡單三棱錐用於測試。
導出爲obj,使用VS工程,設置模型路徑,輸出模型的頂點、面索引數據。
4.2 核心代碼
如何讀取模型,學習《LearnOpenGL模型加載》,此處不再贅述,主要對重複頂點數據去除、索引更新、打印CSV做說明。
4.2.1 傳入結構體數據
Debug模式可以看到三棱錐的點面數據,有很多頂點是重複的,並且與面索引是一一對應的。
UE4中使用Procedural Mesh繪製只需要傳入不同的頂點,因此簡化數據,進行頂點去重、更新索引。
在Mesh.h的構造器中,將Vertex結構體中的position傳入到MeshInfoCSV.h文件中進行處理,面索引是自動遞增的,直接傳入i值,然後調用Export函數打印。
struct Vertex//Assimp讀數據的結構體
{
glm::vec3 position;
glm::vec3 normal;
glm::vec2 texCoords;
};
struct outData//自定義進行去重操作的結構體
{
float verticesPos_X;
float verticesPos_Y;
float verticesPos_Z;
unsigned int index;
unsigned int initialIndex;
};
Mesh(vector<Vertex> vertices, vector<unsigned int> indices, vector<Texture> textures)
{
this->vertices = vertices;
this->indices = indices;
this->textures = textures;
#ifdef EXPORT_MODEL_DATA
vector<outData> allInfo;
outData info;
for (int i = 0; i < vertices.size(); i++)
{
info.verticesPos_X = vertices[i].position.x;
info.verticesPos_Y = vertices[i].position.y;
info.verticesPos_Z = vertices[i].position.z;
info.index = i;
info.initialIndex = i;
allInfo.push_back(info);
}
MeshInfoCSV exportTxt(allInfo);
exportTxt.ExportVertices();
exportTxt.ExportTriangles();
#endif
setupMesh();
}
4.2.2 頂點去重、更新索引
思想:將所有的頂點座標從小到大進行排序。面索引更新的原則是遍歷所有頂點結構體成員時,若當前項與後一項頂點重複,allInfo結構體中去除後一項,並根據記錄後一項的初始面索引,找到需要更新的新索引數組的下標,更新其值爲當前項的頂點序號;若後一項不重複,就將頂點序號增加,再更新後一項的新索引。
最終得到的結果就是不同的頂點座標結構體allInfo與更新的面索引數組indices。
MeshInfoCSV(vector<outData> allInfo)
{
this->allInfo = allInfo;
//initial indices
for (int i = 0; i < allInfo.size(); i++)
this->indices.push_back(i);
OptimizeData();
}
//remove duplicate vertex and modify indices
void OptimizeData()
{
//sort by position's value for remove the duplicate index
sort(allInfo.begin(), allInfo.end(), cmpByPosition);
//compare with previous data
//將重複的頂點去掉,更新面片的索引下標爲不重複的頂點下標(內存優化)
if (allInfo.size() > 1)
{
int newIndex = 0;
allInfo[0].index = newIndex;
indices[allInfo[0].initialIndex] = newIndex;
int len = allInfo.size();
for (int i = 0; i < len - 1; i++)
{
if (allInfo[newIndex].verticesPos_X == allInfo[newIndex + 1].verticesPos_X
&& allInfo[newIndex].verticesPos_Y == allInfo[newIndex + 1].verticesPos_Y
&& allInfo[newIndex].verticesPos_Z == allInfo[newIndex + 1].verticesPos_Z)
{//update repetitive vertex's indexa
allInfo[newIndex + 1].index = newIndex;
indices[allInfo[newIndex + 1].initialIndex] = newIndex;
allInfo.erase(allInfo.begin() + newIndex + 1);
}
else
{
newIndex++;
indices[allInfo[newIndex].initialIndex] = newIndex;
allInfo[newIndex].index = newIndex;
}
}
}
}
4.2.3 輸出本地CSV文件
fopen會提示不安全,要用fopen_s打開文件,使用w+模式可以覆蓋原文件內容。
void ExportVertices()
{
int i;
FILE *fp;
//please keep close excel when print to file
fopen_s(&fp,"MeshData/OpenglVertices.csv", "w+");//model has one mesh
fprintf(fp, ",MeshID,Vertice_X,Vertice_Y,Vertice_Z\n");
for (i = 0; i < allInfo.size(); i++)
{
fprintf(fp, "%d,1,%.2f,%.2f,%.2f\n", i+1,allInfo[i].verticesPos_X, allInfo[i].verticesPos_Y, allInfo[i].verticesPos_Z);
}
fprintf(fp, "%d,0,0,0,0\n",i+1);
fclose(fp);
cout << "Vertices successfully print to csv excel!" << endl;
}
打印面索引的順序必須是indices[i], indices[i+2], indices[i+1],因爲要保證三個頂點是順時針順序排列,否則在UE4中繪製得到的面就是反向的,會造成三棱錐外表面不可見,內表面可見的結果。
void ExportTriangles()
{
int i;
FILE *fp;
fopen_s(&fp, "MeshData/OpenglTriangles.csv", "w+");//model has one mesh
fprintf(fp, ",MeshID,Vertice1,Vertice2,Vertice3\n");
for (i = 0; i < indices.size(); i+=3)
{
//Vertex order must be clockwise in ue4 draw
fprintf(fp, "%d,1,%d,%d,%d\n", i/3 + 1, indices[i], indices[i+2], indices[i+1]);
}
fprintf(fp, "%d,0,0,0,0\n", i/3 + 1);
fclose(fp);
cout << "Triangles successfully print to csv excel!" << endl;
}
4.3 UE4繪製
得到頂點、三角面索引CSV文件後,結合該文章【UE4 C++】由點面數據,批量繪製ProceduralMesh並轉化爲StaticMesh資產就能在UE4中繪製得到模型了。目前該VS項目僅適用於單個模型(只包含一個Mesh)的數據集輸出,不能同時傳入多個模型。