• <noscript id="e0iig"><kbd id="e0iig"></kbd></noscript>
  • <td id="e0iig"></td>
  • <option id="e0iig"></option>
  • <noscript id="e0iig"><source id="e0iig"></source></noscript>
  • 【OpenGL C++ UE4】獲取模型頂點及面索引數據,并優化存儲結構供UE4繪制

    標簽: UE4  C++  OpenGL

    目錄

    一、功能需求

    二、成果

    三、環境配置

    四、詳細步驟

    4.1 Max制作三棱錐并處理

    4.2 核心代碼

    4.2.1 傳入結構體數據

    4.2.2 頂點去重、更新索引

    4.2.3 輸出本地CSV文件

    4.3 UE4繪制


    一、功能需求

    想必你肯定會問我一個問題,UE4直接導入模型不好么?

    哈哈,前提是在做畢設時,導師提供的只有頂點與面索引數據,沒有模型。

    下文詳細介紹了畢設開發中的難點,涉及三篇其他文章。

    【UE4 C++】由點面數據,批量繪制ProceduralMesh并轉化為StaticMesh資產

    后來學習了《LearnOpenGL模型加載》一章后,能夠通過Assimp庫讀取obj模型并在窗口中繪制了。

    因此十分好奇,我能否也可以經由C++輸出與畢設相同格式的模型頂點與面片數據集

    二、成果

    1.輸出的CSV表格在MeshData文件夾下,比如這是個簡單的三棱錐(方便調試查找BUG)輸出的點面數據集。

    Vertices
    Triangles

    2. 3ds max建一個茶壺,通過Opengl窗口繪制顯示,然后輸出點面數據道CSV表格,最后導入UE4中繪制。

    3ds max中的茶壺
    Opengl繪制——線框顯示
    UE4中靜態網格體——線框顯示

    三、環境配置

    我將該項目所需的第三方庫文件GLFWGLADASSIMPstb_image.h均放在了項目中,并設置了相對路徑防止路徑丟失。

    若有疑問或想嘗試,也可去LearnOpenGL網址學習自行配置。

    四、詳細步驟

    4.1 Max制作三棱錐并處理

    用自帶的工具欄新建簡單的三棱錐,轉換為可編輯多邊形,可以看到頂點、邊還是很多。

    通過邊刪除、點去除、焊接、邊界封口,去掉多余的邊、頂點,轉化成一個只包含四個頂點,四個面的簡單三棱錐用于測試。 

    導出為obj,使用VS工程,設置模型路徑,輸出模型的頂點、面索引數據。 

    4.2 核心代碼

    VS項目文件結構

    如何讀取模型,學習《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)的數據集輸出,不能同時傳入多個模型。

    版權聲明:本文為qq_31788759原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接和本聲明。
    本文鏈接:https://blog.csdn.net/qq_31788759/article/details/104476953

    智能推薦

    JavaWeb——【前端】——注冊頁面

    頁面效果 實現代碼 注意事項 主要使用的bootstrap樣式 如果想引用,不要直接復制,沒用的。 先介紹下所引用的文件: boostrap的js、bootstrap的css、jquery的js、以及自己編寫的register.css。 因為博主用的thymeleaf語法,所以有th符號。 若要使用時,根據個人情況導入相應的依賴。...

    網站HTTP升級HTTPS完全配置手冊

    本文由葡萄城技術團隊于博客園原創并首發 轉載請注明出處:葡萄城官網,葡萄城為開發者提供專業的開發工具、解決方案和服務,賦能開發者。 今天,所有使用Google Chrome穩定版的用戶迎來了v68正式版首個版本的發布,詳細版本號為v68.0.3440.75,上一個正式版v67.0.3396.99發布于6月13日,自Chrome 68起,當在加載非HTTPS站點時,都會在地址欄上明確標記為&ldqu...

    echarts 自定義儀表盤設置背景圖片

    echarts儀表盤 使用插件 vue-echarts 代碼示例 HTML部分 js部分 效果圖...

    RT-Thread Studio部分定時器時鐘不正確的解決方案

    在昨天的RT-Thread Studio硬件定時器hwtimer在stm32f411上的使用筆記中,遇到了部分定時器速度想象中和實際不一致的情況,具體表現在定時器2、3、4、5、9、10、11都正常,但定時器1要快一倍。 仔細查看代碼,找到了原因。 因為代碼使用的是工程是直接生成的時鐘代碼,實際的時鐘頻率是這樣的: 而實際的定時器時鐘配置代碼如下: 針對F411,去掉其中的宏定義是這樣的: 這里說...

    symfony學習筆記之模板渲染-----twig總結

    參考:https://blog.csdn.net/liebert/article/details/77414217 目錄 一、模板引擎工作原理 二、Twig模板引擎 1.運行環境要求 2.基本API用法 3.設計模板 (1)變量輸出         a.全局變量         b.設置變量 (2)...

    猜你喜歡

    小甲魚Python3學習筆記之第六講(僅記錄學習)

    第六講:python之常用操作符 一、知識點: 0.算術運算符:+,-,*,/,%(取模,即求余數),**(冪運算),//(地板除法,取整除,返回商的整數部分) 備注:①雙斜杠 // 除法總是向下取整。             ②從符點數到整數的轉換可能會舍入也可能截斷,建議使用math....

    Java 習題 (21)

    題目: 寫一個程序,打印從1 到 100 的值。 解答: 答案如下: (只是截取結果一部分) 如果覺得不錯,就用點贊或者關注來取代五星好評吧!...

    Pytorch 安裝

    Pytorch 安裝 已有Cuda 9.0,anaconda3,用conda命令安裝pytorch 驗證是否安裝成功 然后依次輸入 得到如下之類的輸出 驗證pytorch在當前GPU和cuda上是否能用...

    使用Python實現QQ郵箱/163郵箱的郵件發送

    QQ郵箱/163郵箱的郵件發送:py文件發送郵件內容相當于一個第三方的客戶端,借助于QQ/163郵箱服務器來發送的郵件。 主要配置:                 導入模塊——import  &...

    微信字體放大影響布局的處理

    下圖中是安卓微信中調整字體大小后的效果,行內的font-size:12px !important設置沒起作用,個人覺得是webview做了另外的處理,使用getComputedStyle獲取到的字體也確實是變大了(而且這是全局的,對所以元素都生效,包括頁面加載后append的元素),對設定了絕對值的元素則不影響。 很多webview提供了調整頁面字體大小的功能,例如手機QQ、微信、部分Androi...

    精品国产乱码久久久久久蜜桃不卡