Ağ Örgüsü (Mesh)

Assimp ile uygulamaya birçok farklı model yükleyebiliriz, ancak bir kez yüklendikten sonra hepsi Assimp' in veri yapılarında saklanabilirler. Sonunda istediğimiz şey, bu verileri OpenGL' in anlayabileceği bir formata dönüştürmektir. Bir meshtek bir çekilebilir varlığı temsil ettiği önceki bölümden öğrendik, bu yüzden kendi mesh sınıfımızı tanımlayarak başlayalım.

Bir ağın, bir ağın minimum olarak verisi olarak ne yapması gerektiğini düşünmek için bugüne kadar öğrendiğimizden birini gözden geçirelim. Bir ağ, en azından her bir köşe bir konum vektörü, normal bir vektör ve bir doku koordinat vektörü içerdiği bir dizi köşeye ihtiyacınız olmalıdır. Bir örgü ayrıca endeksli çizim için endeksler içermeli ve dokular şeklinde (yaygın / speküler haritalar) malzeme verileri içermelidir.

Şimdi bir mesh sınıfı için minimum gereksinimleri belirledik, OpenGL' de bir vertex tanımlayabiliriz:

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

Gerekli vertex özniteliklerinin her birini, Vertex denilen bir struct'a kaydeceğiz. Bir Vertex struct' ının yanı sıra, doku verilerini de bir Texture struct'ında düzenlemek istiyoruz:

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

Dokunun id bilgisini ve tipini saklıyoruz (örneğin; dağıtılmış ya da yansıtıcı doku).

Bir vertex ve dokunun gerçek temsilini bilirsek, Mesh sınıfının yapısını tanımlamaya başlayabiliriz:

class Mesh {
    public:
        // mesh verileri
        vector<Vertex>       vertices;
        vector<unsigned int> indices;
        vector<Texture>      textures;

        Mesh(vector<Vertex> vertices, vector<unsigned int> indices, vector<Texture> textures);
        void Draw(Shader &shader);
    private:
        //  sahneleme
        unsigned int VAO, VBO, EBO;

        void setupMesh();
};  

Gördüğünüz gibi, sınıf çok karmaşık değil. Kurucu işlevde, gerekli tüm verileri veriyoruz, SetupMesh işlevindeki tamponları başlatıyoruz ve son olarak Draw işlevi ile çizdiriyoruz. Draw işlevine bir tonlandırıcıyı verdiğimizi unutmayın; Shader' ı mesh'e ileterek, çizimden önce birkaç uniform değişken ayarlayabiliriz (örnekleyicileri doku birimlerine bağlamak gibi).

Kurucu işlevin içeriği oldukça basittir. Sınıfın public değişkenlerini kurucunun ilgili argüman değişkenleriyle ayarlıyoruz. Ayrıca kurucuda setupMesh işlevini de çağırıyoruz:

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

    setupMesh();
}

Burada başka özel açıklanacak bir şey yok Şimdi setupMesh işlevine girelim.

İlklendirme

Kurucu sayesinde, şimdi sahneleme için kullanabileceğimiz büyük mesh listesine sahibiz. Uygun tamponları ayarlamamız ve Vertex Shader Düzenini Vertex Özniteliği işaretçileri üzerinden belirlememiz gerekir. Şimdiye kadar bu kavramlarla ilgili herhangi bir sorun yaşamamalısınız, ancak yapılardaki Vertex verilerinin tanıtılmasıyla bu kez biraz heyecanlı hale getirdik:

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 konumları
    glEnableVertexAttribArray(0);	
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)0);
    // vertex normalleri
    glEnableVertexAttribArray(1);	
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, Normal));
    // vertex doku koordinatları
    glEnableVertexAttribArray(2);	
    glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, TexCoords));

    glBindVertexArray(0);
}  

Kod, beklediğinizden çok farklı değil, ancak Vertex yapısının yardımıyla birkaç küçük püf noktası kullanılmıştır.

Yapılar, bellek düzenlerinin sıralı olduğu C++ 'da harika bir özelliğe sahiptir. Yani, bir yapıyı bir dizi veri olarak temsil edebildiydik, yalnızca bir dizi tamponu için istediğimiz bir float (aslında bayt) dizisini doğrudan çeviren sırayla değişkenlerini içerir. Örneğin, doldurulmuş bir köşe yapımız varsa, bellek düzeni aşağıdakilere eşit olacaktır.

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];

Orijinal Kaynak: Mesh

Last updated