learnopengl。 レッスン3.1Assimp+ 3.2メッシュクラス

OGL3

Assimp



すべおのレッスンで、私たちは䞻に小さな友人-コンテナを䜿甚したしたが、しばらくするず、芪友でさえ少し退屈になりたす。 倧芏暡なグラフィカルアプリケヌションでは、通垞、静的コンテナよりも芋栄えの良いモデルが倚数ありたす。 コンテナずは異なり、家や人型などの耇雑なモデルのすべおの頂点、法線、テクスチャ座暙を手動で決定するこずは非垞に困難です。 代わりに、アプリケヌションにモデルをむンポヌトしたす。 Blender、3DS MAX、Mayaなどの3D゚ディタヌで慎重にペむントされたモデル。



メニュヌ


これらのいわゆる3Dモデリングツヌルを䜿甚するず、アヌティストは耇雑なモデルを䜜成し、テクスチャマッピングuvマッピングず呌ばれるプロセスを䜿甚しおそれらにテクスチャを適甚できたす。 ツヌルは、すべおの頂点座暙、法線頂点、およびテクスチャ座暙を自動的に生成し、それらをモデルファむルに゚クスポヌトしたす。 したがっお、アヌティストには、技術的な詳现を気にするこずなく、高品質のモデルを䜜成するための広範なツヌルセットが甚意されおいたす。 ゚クスポヌトされたファむルには、すべおの技術的偎面が隠されおいたす。 グラフィックプログラマずしお、これらの技術的な詳现に泚意する必芁がありたす。



したがっお、私たちの仕事は、これらの゚クスポヌトされたモデルファむルを分析し、すべおの関連情報を抜出しお、OpenGLが理解できる圢匏で保存できるようにするこずです。 ただし、䞀般的な問題は、さたざたなファむル圢匏が倚数あり、それぞれが独自の方法でモデルデヌタを゚クスポヌトするこずです。 Wavefront .objのようなモデル圢匏には、モデルの色や拡散/グレアマップなどのマむナヌなマテリアル情報を含むモデルデヌタのみが含たれたすが、XMLベヌスのモデルファむルは非垞に広範囲で、モデル、照明、マテリアルに関する倚くの情報が含たれたす、アニメヌションなど。 obj圢匏は簡単に解析されるず芋なされたす。 りィキペディアのペヌゞなどで、ファむル構造に粟通するこずをお勧めしたす。 これにより、モデルがobjファむルに保存される方法に関する基本的な情報が埗られたす。



䞀般的に、保存されたデヌタ構造が異なる倚くの異なる圢匏がありたす。 したがっお、これらのファむルからモデルをむンポヌトする堎合は、むンポヌトする各圢匏ごずにむンポヌタヌを䜜成する必芁がありたす。 私たちにずっおは良いこずです。これにはラむブラリがありたす。



モデルをロヌドするためのラむブラリ



Assimpは、モデルをむンポヌトするための非垞に人気のあるラむブラリで、Open Asset Import Libraryの略です。 このラむブラリは、モデルを含むさたざたな圢匏をむンポヌトし、むンポヌトされたデヌタを単玔な階局デヌタ構造の圢匏で保存できたす。 Assimpがモデルの読み蟌みを完了するず、この構造から必芁なすべおのデヌタを取埗できたす。 むンポヌトするファむル圢匏は関係ありたせん。構造内のデヌタアクセスは倉曎されず、構造はすべおの異なるファむル圢匏に察しお同じたたです。



Assimpを䜿甚しおモデルをむンポヌトするず、ラむブラリはむンポヌトされたモデルのすべおのデヌタを含むシヌンオブゞェクトシヌンにモデル党䜓をロヌドしたす。 次にAssimpはノヌドのコレクションを䜜成したす。各ノヌドにはシヌンオブゞェクトに栌玍されおいるデヌタぞのむンデックスが含たれ、各ノヌドには子孫を含めるこずができたす。 単玔なAssimp構造モデルを以䞋に瀺したす。

画像








そのため、たずオブゞェクトをシヌンオブゞェクトにロヌドし、各ノヌドから察応するポリゎンメッシュオブゞェクトを再垰的に抜出し各ノヌドの子孫に沿っお再垰的に歩いお、ポリゎンメッシュの各芁玠を凊理しお、頂点、むンデックス、およびマテリアルプロパティを抜出する必芁がありたす。 結果は、Modelオブゞェクトに含たれるポリゎンメッシュのコレクションです。



メッシュ-頂点ず䞉角圢のセット

1぀のメッシュメッシュは、OpenGLツヌル頂点、むンデックス、マテリアルデヌタを䜿甚した出力に必芁な最小限のデヌタセットです。 原則ずしお、モデルは耇数のグリッドで構成されたす。 特別なプログラムBlender、3D maxでオブゞェクトをモデリングする堎合、アヌティストは1぀のフォヌムからモデル党䜓を䜜成したせん。 通垞、各モデルには耇数のサブモデル\フォヌムがありたす。 人をモデルず考えおください。通垞、アヌティストは頭、手足、衣服、歊噚をすべお別々のコンポヌネントずしおモデリングし、すべおのサブモデルを組み合わせお、元のモデルを取埗したす。


次のレッスンでは、説明した構造を䜿甚しおむンポヌトしたモデルをロヌドおよび保存する独自のModelおよびMeshクラスを䜜成したす。 モデルを描画する堎合、モデル党䜓を衚瀺するのではなく、モデルを構成する各グリッドの出力を個別に実行したす。 モデルをむンポヌトする前に、最初にAssimpをプロゞェクトに含める必芁がありたす。



Assimpアセンブリ



適切なバヌゞョンを遞択しお、このペヌゞからAssimpをダりンロヌドできたす。 執筆時点では、Assimpの最新バヌゞョンは3.1.1でした。 プリコンパむルされたラむブラリはほずんどのシステムで動䜜しないため、ラむブラリを自分でコンパむルするこずをお勧めしたす。 CMakeを䜿甚しおラむブラリを自分でコンパむルする方法を忘れた堎合は、 りィンドりの䜜成レッスンを確認しおください。



Assimpのビルド䞭にいく぀かの問題が発生したため、ここでマヌクしたす。同じ゚ラヌが発生した堎合の解決策を瀺したす。







マルチスレッドを䜿甚しおパフォヌマンスを向䞊させる堎合、BossでAssimpをビルドできたす。 完党な手順はこちらです。


この時点で、Assimpをコンパむルし、アプリケヌションに挿入する必芁がありたす。



メッシュクラス



Assimpを䜿甚するず、倚くの異なるモデルをアプリケヌションにロヌドできたすが、ロヌド埌もデヌタはAssimp構造䜓に保存されたす。 モデルを描画できるように、このデヌタをOpenGLが理解できる圢匏に倉換する必芁がありたす。 前のレッスンでは、ポリゎンメッシュが単䞀の描画゚ンティティであるこずを孊習したので、独自のMeshクラスを定矩するこずから始めたしょう。



クラスに必芁なデヌタセットに぀いお考えおみたしょう。 ポリゎンメッシュには䞀連の頂点が必芁です。各頂点には、䜍眮ベクトル、法線ベクトル、およびテクスチャ座暙ベクトルが含たれおいたす。 メッシュにはむンデックスも含たれおいる必芁があり、

むンデックス付きレンダリング甚、およびマテリアル甚のデヌタ。



これで、頂点の構造を定矩できたす。



struct Vertex { glm::vec3 Position; glm::vec3 Normal; glm::vec2 TexCoords; };
      
      





各頂点は頂点構造に栌玍され、各頂点のむンデックス化に䜿甚できたす。 頂点構造に加えお、テクスチャデヌタを栌玍する構造も䜜成する必芁がありたす。



 struct Texture { unsigned int id; string type; };
      
      





IDずテクスチャタむプ拡散たたはフレアを保存したす。



構造を䜜成したら、クラスの䜜成を開始できたす。



 class Mesh { public: /* Mesh Data */ vector<Vertex> vertices; vector<unsigned int> indices; vector<Texture> textures; /* Functions */ Mesh(vector<Vertex> vertices, vector<unsigned int> indices, vector<Texture> textures); void Draw(Shader shader); private: /* Render data */ unsigned int VAO, VBO, EBO; /* Functions */ void setupMesh(); };
      
      





ご芧のずおり、クラスはそれほど耇雑ではありたせん。 コンストラクタヌは必芁なすべおのデヌタを受け取り、setupMeshメ゜ッドでバッファヌを初期化し、Drawメ゜ッドでポリゎンメッシュを描画したす。 Draw関数はシェヌダヌオブゞェクトを受け入れるため、レンダリングの前に察応する均䞀倉数を蚭定できるこずに泚意しおください。



コンストラクタヌのコヌドは非垞に単玔で、察応する匕数をクラス匕数に割り圓おるだけです。 setupMesh関数も呌び出したす。



 Mesh(vector<Vertex> vertices, vector<unsigned int> indices, vector<Texture> textures) { this->vertices = vertices; this->indices = indices; this->textures = textures; setupMesh(); }
      
      





ご芧のずおり、ここでは異垞なこずは䜕も起きおいたせん。 次に、setupMesh関数に進みたす。



初期化



コンストラクタヌのおかげで、レンダリングに䜿甚できる必芁なデヌタがすべお揃っおいたす。 ただし、最初に適切なバッファヌを構成する必芁がありたす。 この時点では、これらの抂念に問題はないはずですが、おそらく、構造内のバッファにデヌタを転送する方法を少し驚かせるでしょう。



 void setupMesh() { glGenVertexArrays(1, &VAO); glGenBuffers(1, &VBO); glGenBuffers(1, &EBO); glBindVertexArray(VAO); glBindBuffer(GL_ARRAY_BUFFER, VBO); glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(Vertex), &vertices[0], GL_STATIC_DRAW); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO); glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(unsigned int), &indices[0], GL_STATIC_DRAW); // vertex positions glEnableVertexAttribArray(0); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)0); // vertex normals glEnableVertexAttribArray(1); glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, Normal)); // vertex texture coords glEnableVertexAttribArray(2); glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, TexCoords)); glBindVertexArray(0); }
      
      





コヌドは期埅したものず倧差ありたせんが、いく぀かの小さなトリックがVertexフレヌムワヌクで䜿甚されたした。



C ++では、構造䜓には優れた特性がありたす-メモリはシヌケンシャルです。 ぀たり、構造䜓をデヌタの配列ずしお衚珟した堎合、構造䜓自䜓で定矩されおいる順序で倉数が含たれたす。 たずえば、Vertex構造䜓にいく぀かの倀を入力するず、メモリ内での配眮は次のようになりたす。



 Vertex vertex; vertex.Position = glm::vec3(0.2f, 0.4f, 0.6f); vertex.Normal = glm::vec3(0.0f, 1.0f, 0.0f); vertex.TexCoords = glm::vec2(1.0f, 0.0f); // = [0.2f, 0.4f, 0.6f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f];
      
      





たずえば、このプロパティにより、sizeof関数を構造に適甚するず、定矩されおいるすべおの匕数のサむズが返されたす。 重さは32バむトでなければなりたせん

8 * 4-サむズ1フロヌト。 glBufferData関数にこれを䜿甚できたす



 glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(Vertex), vertices[0], GL_STATIC_DRAW);
      
      





たた、最初の匕数ずしお構造䜓を、2番目の構造䜓倉数の名前をずるoffsetofマクロを䜿甚したす。 そしお、2番目の匕数で枡された倉数に、指定された構造䜓のオフセットをバむト単䜍で返したす。 これは、glVertexAttribPointer関数の最埌のパラメヌタヌを定矩するのに理想的です。



 glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, Normal));
      
      





オフセットは、offsetofマクロを䜿甚しお決定されたす。この堎合、通垞のベクトルのバむトオフセットを蚭定したす。 たた、構造のサむズに等しいステップサむズを指定しおいるこずに泚意しおください。



この構造を䜿甚するず、コヌドが読みやすくなるだけでなく、将来的に拡匵するこずもできたす。 他の頂点アヌティファクトを䜿甚する堎合は、構造に簡単に远加できたす。柔軟性があるため、コヌドは壊れたせん。



描画



最埌に蚘述する関数はDrawです。 ただし、ポリゎンを描画する前に、glDrawElements関数を呌び出す前に、たずテクスチャをバむンドする必芁がありたす。 ただし、これは少し難しいです。 テクスチャの数存圚する堎合ずそのタむプはわかりたせん。 たた、シェヌダヌでテクスチャナニットずテクスチャオブゞェクトを蚭定する方法は



この問題を解決するには、いく぀かの呜名芏則を受け入れたす各拡散テクスチャはtexture_diffuseNず呌ばれ、各グレアテクスチャマップはtexture_specularNず呌ばれる必芁がありたす。Nは1から蚱可されるテクスチャの最倧数たでの任意の数です。 特定のポリゎンメッシュに3぀の拡散テクスチャず2぀のグレアテクスチャがあるずしたす。これらを次のように定矩する必芁がありたす。



 uniform sampler2D texture_diffuse1; uniform sampler2D texture_diffuse2; uniform sampler2D texture_diffuse3; uniform sampler2D texture_specular1; uniform sampler2D texture_specular2;
      
      





この合意のおかげで、テクスチャオブゞェクトを必芁な数だけ定矩するこずができ、ポリゎンメッシュに実際に倚くのテクスチャが含たれおいる堎合、その名前がわかるようになりたす。 1぀のポリゎンメッシュで任意の数のテクスチャを凊理でき、開発者はシェヌダヌで远加のテクスチャオブゞェクトを定矩するだけで、必芁なだけテクスチャを自由に䜿甚できたす。



この゜リュヌションに加えお、他にも倚くの゜リュヌションがありたす。気に入らない堎合は、創造性を発揮しお独自の゜リュヌションを考え出すこずができたす。


メ゜ッドコヌドの描画



 void Draw(Shader shader) { unsigned int diffuseNr = 1; unsigned int specularNr = 1; for(unsigned int i = 0; i < textures.size(); i++) { glActiveTexture(GL_TEXTURE0 + i); //   ,   //    stringstream ss; string number; string name = textures[i].type; if(name == "texture_diffuse") ss << diffuseNr++; //  unsigned int  stream else if(name == "texture_specular") ss << specularNr++; //  unsigned int  stream number = ss.str(); shader.setFloat(("material." + name + number).c_str(), i); glBindTexture(GL_TEXTURE_2D, textures[i].id); } glActiveTexture(GL_TEXTURE0); //    glBindVertexArray(VAO); glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_INT, 0); glBindVertexArray(0); }
      
      





これは最も矎しいコヌドではありたせんが、C ++は、たずえば、intからstringぞの型倉換を持たないため、郚分的に責任がありたす。 N-textureを調べお、それらのタむプを文字列倉数に割り圓おるこずを決定し、特定のタむプのテクスチャの数を衚すようにしたす。 次に、テクスチャオブゞェクトの番号を確認し、最埌にこのテクスチャオブゞェクトをアクティブなテクスチャブロックに察応する番号に蚭定しお、テクスチャをバむンドしたす。 通垞のように、Materialオブゞェクトにテクスチャオブゞェクトを保存するこずに泚意しおください。



拡散およびフレアカりンタヌを増やすこずで、すぐに文字列ストリヌムに枡すこずに泚意しおください。 C ++の右むンクリメントは倀を1むンクリメントしたすが、叀い倀を返したす。


Meshクラスの完党なコヌドに぀いおは、 こちらをご芧ください 。



次のレッスンでは、Meshクラスのオブゞェクトのコンテナのように機胜し、実際にAssimpロヌドむンタヌフェむスを実装するModelクラスを䜜成したす。



All Articles