程式碼吸貓 | 用 OpenGL 影象渲染的養貓計劃
一起用程式碼吸貓!本文正在參與【喵星人徵文活動】。
在掘金上看到最近的新活動 "程式碼吸貓",技術類文章只要和貓有關就行。
對於沒有養貓的程式設計師,這不是為難人嘛。
不過沒關係,用 OpenGL 影象渲染給自己造一隻貓吧!!!
模型構造
首先需要構造出貓的模型,有能力的話可以直接在三維軟體裡面造一個。
或者像我一樣直接下載免費的貓模型,然後把它匯入 Blender 3D 軟體中。
在 Blender 中可以預覽貓模型,或者對它做一下調整,最後在把這個模型匯出。
模型載入
匯出的 obj 檔案裡面就記錄了模型的頂點資訊,接下來就要用 OpenGL 將它繪製出來。
這裡要用到 assimp 開源庫,它支援多種模型檔案的解析操作,通過它將模型解析成一個個 Mesh 。
Mesh 的定義如下:
cpp
class Mesh {
public:
/* Mesh Data */
vector<Vertex> vertices;
vector<unsigned int> indices;
vector<Texture> textures;
unsigned int VAO;
// 省略部分程式碼
}
Mesh 相當於繪製模型上的一個個網格或者說面片,它包含了該網格的頂點、紋理資訊和繪製索引。
而模型 Model 就是由這一系列網格 Mesh 組成的。
如上圖所示,貓模型是由一個個小矩陣組成的,小矩陣就可以理解成 mesh 網格了。
Model 的定義如下:
cpp
class Model
{
public:
/* Model Data */
vector<Texture> textures_loaded;
vector<Mesh> meshes;
// 省略部分程式碼
}
在實際繪製的時候,也是由一個一個 Mesh 最終繪製成的。
cpp
// draws the model, and thus all its meshes
void Draw(Shader shader)
{
for(unsigned int i = 0; i < meshes.size(); i++)
meshes[i].Draw(shader);
}
從圖中也可以看到,貓模型的網格數量是很多的,導致載入的時候會很很慢了,載入方法如下:
```cpp void loadModel(string const &path) { // 使用 assimp 庫進行載入 const aiScene* scene = importer.ReadFile(path, aiProcess_Triangulate | aiProcess_FlipUVs | aiProcess_CalcTangentSpace); // 檢查是否有錯 if(!scene || scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode) // if is Not Zero { cout << "ERROR::ASSIMP:: " << importer.GetErrorString() << endl; return; } // 獲取模型所在資料夾 directory = path.substr(0, path.find_last_of('/'));
// 從根節點一個一個節點開始處理
processNode(scene->mRootNode, scene);
} ```
使用 assimp 處理後會得到一個根節點,然後順著根節點一個一個往下處理就好了。
cpp
void processNode(aiNode *node, const aiScene *scene)
{
for(unsigned int i = 0; i < node->mNumMeshes; i++)
{
aiMesh* mesh = scene->mMeshes[node->mMeshes[i]];
// 處理得到的 aiMesh 並組裝成定義好的 Mesh 資料結構
meshes.push_back(processMesh(mesh, scene));
}
// 處理子節點
for(unsigned int i = 0; i < node->mNumChildren; i++)
{
processNode(node->mChildren[i], scene);
}
}
可以看到處理過程大量的 for 迴圈操作,所以後續才會針對模型檔案的優化,加快其載入速度。
模型渲染
得到了最終的 Model 之後,就可以對它做渲染顯示了。
cpp
// model 矩陣調整模型顯示位置和方向
glm::mat4 model = glm::mat4(1.0f);
model = glm::translate(model, glm::vec3(tranx_x, tranx_y, tranx_z));
model = glm::rotate(model,glm::radians(90.0f),glm::vec3(0.0,0.0,1.0));
model = glm::scale(model, glm::vec3(0.5f, 0.5f, 0.5f));
shader.setMatrix4fv("model", glm::value_ptr(model));
ourModel.Draw(shader);
由於模型自身就帶了一個位置和方向,顯示的時候不一定是我們想要的觀察方位,所以還是要調整一個模型矩陣。
最後渲染就可以看到 貓模型 效果啦。
小結
為了便於觀察,可以處理一下鍵盤或者滑鼠事件,修改模型矩陣的值,從不同角度擼貓。
目前的貓模型還只是靜態的,調整的話也只能用鍵盤調整,而且還只是改了 移動、縮放、旋轉這些屬性,貓本身是沒有動的。
想要貓自身能動的話,還需要模型裡面有對應的骨骼動畫才可以了,等後面有了這樣的模型,再繼續迭代。
關注微信公眾號 音視訊開發進階,看更多擼貓後續內容...
- 音視訊開發系統入門大致路線
- 乾貨 | 快速抽取縮圖是怎麼練成的?
- 關於直播、WebRTC、FFmpeg 的那些事
- 005 | 播放器系列專欄-在 Windows 上檢視 MP4 格式資訊
- 將音視訊中的花屏、綠屏、黑屏問題一網打盡
- 關於音視訊裡面的解碼幀率和渲染幀率
- 003 | 認識MP4視訊(上)
- 入門或者轉行音視訊,應該要怎麼做?
- Metal 開發 | 使用 C 進行介面呼叫~~
- FFmpeg 呼叫 MediaCodec 硬解碼到 Surface 上
- 程式碼吸貓 | 用 OpenGL 影象渲染的養貓計劃
- 音訊變速 | libsonic 開源庫的介紹與實踐
- FFmpeg 呼叫 Android MediaCodec 進行硬解碼(附原始碼)
- iOS開發 - 在 Swift 中去呼叫 C/C 程式碼
- 聲網 SDK 接入以及音視訊通話應用開發指南
- Shader 優化 | OpenGL 繪製網格效果
- KodeLife | Shader 實時編輯預覽的強大工具使用實踐