Рендеринг объектов с несколькими VAO и VBO
Я изучаю OpenGL. Моя задача - разработать программу для рендеринга множества различных объектов, загруженных в виде файлов.obj. Моя идея состоит в том, чтобы создать класс для хранения 3 VBO (вершины, текстуры, нормали), VAO и типа объекта вместе в одном объекте класса. Таким образом, похожие объекты (для рендеринга) будут использовать только один объект класса с соответствующими VAO и VBO. Я кодировал его, но он не работает: объект загружается из файла, все объекты класса создаются, но на экране ничего не отображается.
Класс для хранения VAO и VBO, конструктор для этого класса:
modelMemory(char* typeT)
{
this->modelType = typeT;
if (this->modelType == "Suzanne") loadOBJ("suzanne.obj", this->vertices, this->uvs, this->normals);
glGenVertexArrays(1, &this->VAO_id);
glBindVertexArray(this->VAO_id);
glGenBuffers(1, &this->VBO_vertex);
glBindBuffer(GL_ARRAY_BUFFER, this->VBO_vertex);
glBufferData(GL_ARRAY_BUFFER, this->vertices.size() * sizeof(glm::vec3), &this->vertices[0], GL_STATIC_DRAW);
/**/glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
glGenBuffers(1, &this->VBO_uv);
glBindBuffer(GL_ARRAY_BUFFER, this->VBO_uv);
glBufferData(GL_ARRAY_BUFFER, this->uvs.size() * sizeof(glm::vec2), &this->uvs[0], GL_STATIC_DRAW);
/**/glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, (void*)0);
glGenBuffers(1, &this->VBO_normal);
glBindBuffer(GL_ARRAY_BUFFER, this->VBO_normal);
glBufferData(GL_ARRAY_BUFFER, this->normals.size() * sizeof(glm::vec3), &this->normals[0], GL_STATIC_DRAW);
/**/glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
glBindVertexArray(0);
}
/*DESTRUCTOR*/
~modelMemory()
{
/**/if (toDel)
{
glDeleteBuffers(1, &VBO_vertex);
glDeleteBuffers(1, &VBO_uv);
glDeleteBuffers(1, &VBO_normal);
glDeleteVertexArrays(1, &VAO_id);
}
}
Класс для хранения моделей, конструктор:
Model2 (char* Type, float x, float y, float z, std::vector<modelMemory>* M, GLuint programID)
{
this->type = Type;
this->programID = programID;
unsigned int k = 0;
if ((*M).size() > 0){
while(this->type != (*M)[k].modelType && k < (*M).size()) k++;
if (k < (*M).size()) this->mem = &((*M)[k]);
}
if ((*M).size() == 0 || k == (*M).size()){
//modelMemory newModel(this->type);
//(*M).push_back(newModel);
/**/(*M).emplace_back(this->type);
this->mem = &((*M)[(*M).size()-1]);
}
ModelPosition[0] += x;
ModelPosition[1] += y;
ModelPosition[2] += z;
MatrixID = glGetUniformLocation(programID, "MVP");
ViewMatrixID = glGetUniformLocation(programID, "V");
ModelMatrixID = glGetUniformLocation(programID, "M");
TextureID = glGetUniformLocation(programID, "myTextureSampler");
Texture = loadDDS("uvmap.DDS");
}
И функция для рисования:
void Draw()
{
glUseProgram(programID);
computeMatricesFromInputs();
glm::mat4 ProjectionMatrix = getProjectionMatrix();
glm::mat4 ViewMatrix = getViewMatrix();
glm::mat4 ModelMatrix = glm::translate(glm::mat4(1.0), ModelPosition);
glm::mat4 MVP = ProjectionMatrix * ViewMatrix * ModelMatrix;
glUniformMatrix4fv(this->MatrixID, 1, GL_FALSE, &MVP[0][0]);
glUniformMatrix4fv(this->ModelMatrixID, 1, GL_FALSE, &ModelMatrix[0][0]);
glUniformMatrix4fv(this->ViewMatrixID, 1, GL_FALSE, &ViewMatrix[0][0]);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, this->Texture);
glUniform1i(this->TextureID, 0);
glBindVertexArray(this->mem->VAO_id);
glDrawArrays(GL_TRIANGLES, 0, this->mem->vertices.size());
glBindVertexArray(0);
}
Я создаю вектор в main.cpp:
std::vector<modelMemory> Memory;
std::vector<Model2> ModelList;
И призывает создавать и рисовать в main.cpp:
ModelList.emplace_back((char*)"Field", 0.0f, 0.0f, -5.0f, &Memory, programID);
ModelList.emplace_back((char*)"Suzanne", 0.0f, 0.0f, 0.0f, &Memory, programID);
ModelList.emplace_back((char*)"Suzanne", 4.0f, 1.0f, 1.0f, &Memory, programID);
for (int i = 0; i < ModelList.size(); i++)
ModelList[i].Draw();
Шейдеры (на самом деле, я не настолько хорош, насколько это возможно в шейдерах, они зависят от уроков OpenGL). Вершинный шейдер:
#version 330 core
layout(location = 0) in vec3 vertexPosition_modelspace;
layout(location = 1) in vec2 vertexUV;
layout(location = 2) in vec3 vertexNormal_modelspace;
out vec2 UV;
out vec3 Position_worldspace;
out vec3 Normal_cameraspace;
out vec3 EyeDirection_cameraspace;
out vec3 LightDirection_cameraspace;
uniform mat4 MVP;
uniform mat4 V;
uniform mat4 M;
uniform vec3 LightPosition_worldspace;
void main(){
gl_Position = MVP * vec4(vertexPosition_modelspace,1);
Position_worldspace = (M * vec4(vertexPosition_modelspace,1)).xyz;
vec3 vertexPosition_cameraspace = ( V * M * vec4(vertexPosition_modelspace,1)).xyz;
EyeDirection_cameraspace = vec3(0,0,0) - vertexPosition_cameraspace;
vec3 LightPosition_cameraspace = ( V * vec4(LightPosition_worldspace,1)).xyz;
LightDirection_cameraspace = LightPosition_cameraspace + EyeDirection_cameraspace;
Normal_cameraspace = ( V * M * vec4(vertexNormal_modelspace,0)).xyz;
UV = vertexUV;
}
Фрагмент шейдера:
#version 330 core
vec2 UV;
in vec3 Position_worldspace;
in vec3 Normal_cameraspace;
in vec3 EyeDirection_cameraspace;
in vec3 LightDirection_cameraspace;
out vec3 color;
uniform sampler2D myTextureSampler;
uniform mat4 MV;
uniform vec3 LightPosition_worldspace;
void main(){
vec3 LightColor = vec3(1,1,1);
float LightPower = 10.0f;
vec3 MaterialDiffuseColor = texture( myTextureSampler, UV ).rgb;
vec3 MaterialAmbientColor = vec3(0.1,0.1,0.1) * MaterialDiffuseColor;
vec3 MaterialSpecularColor = vec3(0.3,0.3,0.3);
float distance = length( LightPosition_worldspace - Position_worldspace );
vec3 n = normalize( Normal_cameraspace );
vec3 l = normalize( LightDirection_cameraspace );
float cosTheta = clamp( dot( n,l ), 0.1,1 );
vec3 E = normalize(EyeDirection_cameraspace);
vec3 R = reflect(-l,n);
float cosAlpha = clamp( dot( E,R ), 0.4,1 );
color =
MaterialAmbientColor +
MaterialDiffuseColor * LightColor * LightPower * cosTheta / (distance*distance) +
MaterialSpecularColor * LightColor * LightPower * pow(cosAlpha,6) / (distance*distance);
}