OpenGL glut importOBJモデルファイル



Opengl Glut Import Obj Model File



プログラム環境

IDE:Visual Stdio 2019
言語:C ++
OpenGLライブラリ:過剰
過剰な環境をインストールしません

OBJファイルとは

objファイルは3Dモデルファイル形式です。 Alias | Wavefrontが3Dモデリングおよびアニメーションソフトウェア「AdvancedVisualizer」用に開発した標準で、3Dソフトウェアモデル間の相互ガイダンスに適しており、Mayaを介して読み取りおよび書き込みを行うこともできます。
OBJファイルは一種です テキストファイル 、ワードパッドで直接開いて、表示、編集、変更することができます。



Blenderモデリングを使用してサルの頭のモデルを取得します
画像
objファイルとしてエクスポート
画像
objファイルを取得し、右クリックしてTXTを選択します
画像
画像

OBJファイル形式

上記をエクスポートするときに三角形の面を選択したので、objファイルのfの先頭のデータには3つの数値しかなく、これら3つは頂点インデックスです。これは、以下のインポート機能を容易にするためです。
特定の形式: このブログを見る



実装のアイデア

ご存知のとおり、同一線上にない3つの点で平面を定義できます。 OpenGLでは、面を描画するには3つの頂点座標が必要であり、描画方向は反時計回りです。
画像

OBJファイルからデータを読み取る

objファイルには非常に多くの行があるため、1つだけに含まれています 頂点データ頂点インデックス 猿の頭は持っています 1500 では、c ++ベクトルを使用してデータを格納します。ファイルを読み取るには文字列を処理する必要があります。幸い、c ++は非常に使いやすい文字列処理機能を提供します。 fstreamsstream
操作を容易にするために、ObjLoaderクラスを作成しました。

#pragma once #include #include #include using namespace std class ObjLoader { public: struct vertex { float x float y float z } ObjLoader(string filename)//Read function void Draw()//Drawing function private: vector<vector<GLfloat>> v//Store vertex (x,y,z) coordinates vector<vector<GLint>> f//Store the three vertex indexes of the face } ObjLoader::ObjLoader(string filename) { ifstream file(filename) string line while (getline(file, line)) { if (line.substr(0, 1) == 'v') { vector<GLfloat> Point GLfloat x, y, z istringstream s(line.substr(2)) s >> x s >> y s >> z Point.push_back(x) Point.push_back(y) Point.push_back(z) v.push_back(Point) } else if (line.substr(0, 1) == 'f') { vector<GLint> vIndexSets GLint u, v, w istringstream vtns(line.substr(2)) vtns >> u vtns >> v vtns >> w vIndexSets.push_back(u - 1) vIndexSets.push_back(v - 1) vIndexSets.push_back(w - 1) f.push_back(vIndexSets) } } file.close() }

私のコードはに基づいています このブログ フレームワークが変更され、3つの頂点インデックスのみを含むobjファイルにのみ適しています。元の作者のコードは全能ではなく、コピーは国境を越えて発生します。 objファイルの内容が異なるため、対応していないobjファイルを読み取るとエラーになります。



モデルを描く

アイデアを描くことは難しくありません。最初に3つの頂点を宣言し、次に頂点データを読み取り、glVertex3f関数を使用してインポートします。ここでの法線の計算については、後で照明を使用してよりリアルにレンダリングするためです。レンダリングする必要がない場合は、関連するステートメントを削除できます。

void ObjLoader::Draw() { glBegin(GL_TRIANGLES)//Start drawing for (int i = 0 i < f.size() i++) { GLfloat VN[3]//Normal //Three vertices vertex a, b, c, normal if ((f[i]).size() != 3) { cout << 'ERRER::THE SIZE OF f IS NOT 3!' << endl } else { GLint firstVertexIndex = (f[i])[0]//Remove the vertex index GLint secondVertexIndex = (f[i])[1] GLint thirdVertexIndex = (f[i])[2] a.x = (v[firstVertexIndex])[0]//The first vertex a.y = (v[firstVertexIndex])[1] a.z = (v[firstVertexIndex])[2] b.x = (v[secondVertexIndex])[0] //The second vertex b.y = (v[secondVertexIndex])[1] b.z = (v[secondVertexIndex])[2] c.x = (v[thirdVertexIndex])[0] //The third vertex c.y = (v[thirdVertexIndex])[1] c.z = (v[thirdVertexIndex])[2] GLfloat vec1[3], vec2[3], vec3[3]//Calculate normal vector //(x2-x1,y2-y1,z2-z1) vec1[0] = a.x - b.x vec1[1] = a.y - b.y vec1[2] = a.z - b.z //(x3-x2,y3-y2,z3-z2) vec2[0] = a.x - c.x vec2[1] = a.y - c.y vec2[2] = a.z - c.z //(x3-x1,y3-y1,z3-z1) vec3[0] = vec1[1] * vec2[2] - vec1[2] * vec2[1] vec3[1] = vec2[0] * vec1[2] - vec2[2] * vec1[0] vec3[2] = vec2[1] * vec1[0] - vec2[0] * vec1[1] GLfloat D = sqrt(pow(vec3[0], 2) + pow(vec3[1], 2) + pow(vec3[2], 2)) VN[0] = vec3[0] / D VN[1] = vec3[1] / D VN[2] = vec3[2] / D glNormal3f(VN[0], VN[1], VN[2])//Draw normal vector glVertex3f(a.x, a.y, a.z)//Draw triangle glVertex3f(b.x, b.y, b.z) glVertex3f(c.x, c.y, c.z) } } glEnd() }

実際の戦闘効果

描画ウィンドウ関数で呼び出されるグローバル変数として宣言されています

ObjLoader monkey= ObjLoader('monkey.obj') void display(void) { glClearColor(0.0, 0.0, 0.0, 0.0) glDepthFunc(GL_LESS) glEnable(GL_DEPTH_TEST) glPixelStorei(GL_UNPACK_ALIGNMENT, 1)//Pixel transmission setLight()//Render lighting monkey.Draw() } void main(int argc, char** argv) { InitWindow(argc, argv)//Execute the initialization procedure glutDisplayFunc(&display)//Send the graphic information to the window display glClear(GL_COLOR_BUFFER_BIT) glutMainLoop()//Cycle execution }

画像