I've been following the OpenGL tutorials from ThinMatrix and I've been able to load and render his stall.obj model along with his stall.png texture just fine. But when I try with my own models and textures from Blender, the texture appears "distorted" and I can't seem to find the problem. I'm guessing the problem is with my texture, but I can't find anything that would cause this problem. What could be the cause of this problem?
Here's how I load the .obj file:
void OBJLoader::load_file(const std::string& filename, std::vector<float>& vertices, std::vector<float>& uvs, std::vector<float>& normals, std::vector<int>& indices) { std::vector<float> temp_uvs; std::vector<float> temp_normals; std::ifstream myfile(filename); std::string line; if(myfile.is_open()) { while(std::getline(myfile, line)) { if(std::string("#os").find(line.front()) != std::string::npos) // Ignore lines which starts with #, o, s continue; std::vector<std::string> line_split = split(line, ' '); std::string data_type = line_split[0]; line_split.erase(line_split.begin()); // Keep only numerical data if(data_type == "v") { store_float_in_vector(vertices, line_split); } else if(data_type == "vt") { store_float_in_vector(temp_uvs, line_split); } else if(data_type == "vn") { store_float_in_vector(temp_normals, line_split); } if(data_type == "f") { for(std::string& vertex: line_split) { std::vector<std::string> data_split = split(vertex, '/'); int v = std::stoi(data_split[0]); int vt = std::stoi(data_split[1]); int vn = std::stoi(data_split[2]); if(uvs.size() < (unsigned)(v-1)*2+2) uvs.resize((v-1)*2+2); if(normals.size() < (unsigned)(v-1)*3+3) normals.resize((v-1)*3+3); indices.push_back(v-1); // Indices in .obj files start at 1 uvs[(v-1)*2] = temp_uvs[(vt-1)*2]; uvs[(v-1)*2+1] = 1.0f - temp_uvs[(vt-1)*2+1]; // Blender ¯\_(ツ)_/¯ normals[(v-1)*3] = temp_normals[(vn-1)*3]; normals[(v-1)*3+1] = temp_normals[(vn-1)*3+1]; normals[(v-1)*3+2] = temp_normals[(vn-1)*3+2]; } } } myfile.close(); } else std::cout << "Can't open: " << filename << std::endl; } Here's the obj file:
# Blender v2.82 (sub 7) OBJ File: '' # www.blender.org o Cube v 1.000000 1.000000 -1.000000 v 1.000000 -1.000000 -1.000000 v 1.000000 1.000000 1.000000 v 1.000000 -1.000000 1.000000 v -1.000000 1.000000 -1.000000 v -1.000000 -1.000000 -1.000000 v -1.000000 1.000000 1.000000 v -1.000000 -1.000000 1.000000 vt 0.875000 0.500000 vt 0.625000 0.750000 vt 0.625000 0.500000 vt 0.375000 1.000000 vt 0.375000 0.750000 vt 0.625000 0.000000 vt 0.375000 0.250000 vt 0.375000 0.000000 vt 0.375000 0.500000 vt 0.125000 0.750000 vt 0.125000 0.500000 vt 0.625000 0.250000 vt 0.875000 0.750000 vt 0.625000 1.000000 vn 0.0000 1.0000 0.0000 vn 0.0000 0.0000 1.0000 vn -1.0000 0.0000 0.0000 vn 0.0000 -1.0000 0.0000 vn 1.0000 0.0000 0.0000 vn 0.0000 0.0000 -1.0000 s off f 5/1/1 3/2/1 1/3/1 f 3/2/2 8/4/2 4/5/2 f 7/6/3 6/7/3 8/8/3 f 2/9/4 8/10/4 6/11/4 f 1/3/5 4/5/5 2/9/5 f 5/12/6 2/9/6 6/7/6 f 5/1/1 7/13/1 3/2/1 f 3/2/2 7/14/2 8/4/2 f 7/6/3 5/12/3 6/7/3 f 2/9/4 4/5/4 8/10/4 f 1/3/5 3/2/5 4/5/5 f 5/12/6 1/3/6 2/9/6 And here's the png file I used for the texture: 
And here's how I load the texture with SDL:
void Texture::load(const std::string& filename) { glBindTexture(GL_TEXTURE_2D, texture_id); GLenum gl_format; SDL_Surface* surface_texture = IMG_Load(filename.c_str()); if(surface_texture == nullptr) std::cout << "IMG_Load error: " << IMG_GetError() << std::endl; if(surface_texture->format->BytesPerPixel == 4) { if(surface_texture->format->Rmask == 0x000000FF) gl_format = GL_RGBA; else gl_format = GL_BGRA; } else { if(surface_texture->format->Rmask == 0x000000FF) gl_format = GL_RGB; else gl_format = GL_BGR; } glTexImage2D(GL_TEXTURE_2D, 0, gl_format, surface_texture->w, surface_texture->h, 0, gl_format, GL_UNSIGNED_BYTE, surface_texture->pixels); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); SDL_FreeSurface(surface_texture); // Free SDL_Surface memory glBindTexture(GL_TEXTURE_2D, 0); // Unbind texture } Here's the code for rendering the model:
void Model::create_EBO(int indices[], size_t s_indices) { glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo); glBufferData(GL_ELEMENT_ARRAY_BUFFER, s_indices, indices, GL_STATIC_DRAW); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); // Unbind buffer } void Model::create_VBO(float data[], size_t s_data, unsigned int index, unsigned int coord_format) { vbos.push_back(0); // Declare new vbo GLuint& vbo = vbos.back(); glGenBuffers(1, &vbo); glBindBuffer(GL_ARRAY_BUFFER, vbo); glBufferData(GL_ARRAY_BUFFER, s_data, data, GL_STATIC_DRAW); glVertexAttribPointer(index, coord_format, GL_FLOAT, GL_FALSE, 0, (void*)0); glBindBuffer(GL_ARRAY_BUFFER, 0); // Unbind buffer } void Model::load(float vertices[], size_t s_vertices, float uvs[], size_t s_uvs, float normals[], size_t s_normals, int indices[], size_t s_indices) { glBindVertexArray(vao); create_EBO(indices, s_indices); create_VBO(vertices, s_vertices, 0, 3); create_VBO(uvs, s_uvs, 1, 2); create_VBO(normals, s_normals, 2, 3); glBindVertexArray(0); // Unbind VAO and associated VBOs vertex_count = s_indices/sizeof(indices[0]); } void Model::render() { glBindVertexArray(vao); glEnableVertexAttribArray(0); glEnableVertexAttribArray(1); glEnableVertexAttribArray(2); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo); glDrawElements(GL_TRIANGLES, vertex_count, GL_UNSIGNED_INT, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); // Unbind EBO glDisableVertexAttribArray(0); glDisableVertexAttribArray(1); glDisableVertexAttribArray(2); glBindVertexArray(0); // Unbind VAO } 
