View Full Version : Problem loading 3d Model

01-27-2017, 11:14 PM

I try to load the model in OpenGL with assimp.I copied and pasted the loading code from a tutorial and it builds.But when I run the application, the rendering window appears, but it's blocking and appears "ModelLoading.exe has stopped working".
What could be the problem ?

Thank you!

01-28-2017, 03:17 AM
everything. Why don't you share your code with use?? Did you try to find the crashing part with the debugger??

01-28-2017, 04:24 AM
Here it is.


#pragma once
// Std. Includes
#include <string>
#include <fstream>
#include <sstream>
#include <iostream>
#include <vector>
using namespace std;
// GL Includes
#include <glew.h> // Contains all the necessery OpenGL includes
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>

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

struct Texture {
GLuint id;
string type;
aiString path;

class Mesh {
/* Mesh Data */
vector<Vertex> vertices;
vector<GLuint> indices;
vector<Texture> textures;

/* Functions */
// Constructor
Mesh(vector<Vertex> vertices, vector<GLuint> indices, vector<Texture> textures)
this->vertices = vertices;
this->indices = indices;
this->textures = textures;

// Now that we have all the required data, set the vertex buffers and its attribute pointers.

// Render the mesh
void Draw(Shader shader)
// Bind appropriate textures
GLuint diffuseNr = 1;
GLuint specularNr = 1;
for (GLuint i = 0; i < this->textures.size(); i++)
glActiveTexture(GL_TEXTURE0 + i); // Active proper texture unit before binding
// Retrieve texture number (the N in diffuse_textureN)
stringstream ss;
string number;
string name = this->textures[i].type;
if (name == "texture_diffuse")
ss << diffuseNr++; // Transfer GLuint to stream
else if (name == "texture_specular")
ss << specularNr++; // Transfer GLuint to stream
number = ss.str();
// Now set the sampler to the correct texture unit
glUniform1i(glGetUniformLocation(shader.Program, (name + number).c_str()), i);
// And finally bind the texture
glBindTexture(GL_TEXTURE_2D, this->textures[i].id);

// Also set each mesh's shininess property to a default value (if you want you could extend this to another mesh property and possibly change this value)
glUniform1f(glGetUniformLocation(shader.Program, "material.shininess"), 16.0f);

// Draw mesh
glDrawElements(GL_TRIANGLES, this->indices.size(), GL_UNSIGNED_INT, 0);

// Always good practice to set everything back to defaults once configured.
for (GLuint i = 0; i < this->textures.size(); i++)
glActiveTexture(GL_TEXTURE0 + i);
glBindTexture(GL_TEXTURE_2D, 0);

/* Render data */

/* Functions */
// Initializes all the buffer objects/arrays
void setupMesh()
// Create buffers/arrays
glGenVertexArrays(1, &this->VAO);
glGenBuffers(1, &this->VBO);
glGenBuffers(1, &this->EBO);

// Load data into vertex buffers
glBindBuffer(GL_ARRAY_BUFFER, this->VBO);
// A great thing about structs is that their memory layout is sequential for all its items.
// The effect is that we can simply pass a pointer to the struct and it translates perfectly to a glm::vec3/2 array which
// again translates to 3/2 floats which translates to a byte array.
glBufferData(GL_ARRAY_BUFFER, this->vertices.size() * sizeof(Vertex), &this->vertices[0], GL_STATIC_DRAW);

glBufferData(GL_ELEMENT_ARRAY_BUFFER, this->indices.size() * sizeof(GLuint), &this->indices[0], GL_STATIC_DRAW);

// Set the vertex attribute pointers
// Vertex Positions
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)0);
// Vertex Normals
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)offsetof(Vertex, Normal));
// Vertex Texture Coords
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)offsetof(Vertex, TexCoords));


Model.h :

#pragma once
// Std. Includes
#include <string>
#include <fstream>
#include <sstream>
#include <iostream>
#include <map>
#include <vector>
using namespace std;
// GL Includes
#include <glew.h> // Contains all the necessery OpenGL includes
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <SOIL.h>
#include <assimp/Importer.hpp>
#include <assimp/scene.h>
#include <assimp/postprocess.h>

#include "Mesh.h"

GLint TextureFromFile(const char* path, string directory);

class Model
/* Functions */
// Constructor, expects a filepath to a 3D model.
Model(GLchar* path)

// Draws the model, and thus all its meshes
void Draw(Shader shader)
for (GLuint i = 0; i < this->meshes.size(); i++)

/* Model Data */
vector<Mesh> meshes;
string directory;
vector<Texture> textures_loaded; // Stores all the textures loaded so far, optimization to make sure textures aren't loaded more than once.

/* Functions */
// Loads a model with supported ASSIMP extensions from file and stores the resulting meshes in the meshes vector.
void loadModel(string path)
// Read file via ASSIMP
Assimp::Importer importer;
const aiScene* scene = importer.ReadFile(path, aiProcess_Triangulate | aiProcess_FlipUVs);
// Check for errors
if (!scene || scene->mFlags == AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode) // if is Not Zero
cout << "ERROR::ASSIMP:: " << importer.GetErrorString() << endl;
// Retrieve the directory path of the filepath
this->directory = path.substr(0, path.find_last_of('/'));

// Process ASSIMP's root node recursively
this->processNode(scene->mRootNode, scene);

// Processes a node in a recursive fashion. Processes each individual mesh located at the node and repeats this process on its children nodes (if any).
void processNode(aiNode* node, const aiScene* scene)
// Process each mesh located at the current node
for (GLuint i = 0; i < node->mNumMeshes; i++)
// The node object only contains indices to index the actual objects in the scene.
// The scene contains all the data, node is just to keep stuff organized (like relations between nodes).
aiMesh* mesh = scene->mMeshes[node->mMeshes[i]];
this->meshes.push_back(this->processMesh(mesh, scene));
// After we've processed all of the meshes (if any) we then recursively process each of the children nodes
for (GLuint i = 0; i < node->mNumChildren; i++)
this->processNode(node->mChildren[i], scene);


Mesh processMesh(aiMesh* mesh, const aiScene* scene)
// Data to fill
vector<Vertex> vertices;
vector<GLuint> indices;
vector<Texture> textures;

// Walk through each of the mesh's vertices
for (GLuint i = 0; i < mesh->mNumVertices; i++)
Vertex vertex;
glm::vec3 vector; // We declare a placeholder vector since assimp uses its own vector class that doesn't directly convert to glm's vec3 class so we transfer the data to this placeholder glm::vec3 first.
// Positions
vector.x = mesh->mVertices[i].x;
vector.y = mesh->mVertices[i].y;
vector.z = mesh->mVertices[i].z;
vertex.Position = vector;
// Normals
vector.x = mesh->mNormals[i].x;
vector.y = mesh->mNormals[i].y;
vector.z = mesh->mNormals[i].z;
vertex.Normal = vector;
// Texture Coordinates
if (mesh->mTextureCoords[0]) // Does the mesh contain texture coordinates?
glm::vec2 vec;
// A vertex can contain up to 8 different texture coordinates. We thus make the assumption that we won't
// use models where a vertex can have multiple texture coordinates so we always take the first set (0).
vec.x = mesh->mTextureCoords[0][i].x;
vec.y = mesh->mTextureCoords[0][i].y;
vertex.TexCoords = vec;
vertex.TexCoords = glm::vec2(0.0f, 0.0f);
// Now wak through each of the mesh's faces (a face is a mesh its triangle) and retrieve the corresponding vertex indices.
for (GLuint i = 0; i < mesh->mNumFaces; i++)
aiFace face = mesh->mFaces[i];
// Retrieve all indices of the face and store them in the indices vector
for (GLuint j = 0; j < face.mNumIndices; j++)
// Process materials
if (mesh->mMaterialIndex >= 0)
aiMaterial* material = scene->mMaterials[mesh->mMaterialIndex];
// We assume a convention for sampler names in the shaders. Each diffuse texture should be named
// as 'texture_diffuseN' where N is a sequential number ranging from 1 to MAX_SAMPLER_NUMBER.
// Same applies to other texture as the following list summarizes:
// Diffuse: texture_diffuseN
// Specular: texture_specularN
// Normal: texture_normalN

// 1. Diffuse maps
vector<Texture> diffuseMaps = this->loadMaterialTextures(material, aiTextureType_DIFFUSE, "texture_diffuse");
textures.insert(textures.end(), diffuseMaps.begin(), diffuseMaps.end());
// 2. Specular maps
vector<Texture> specularMaps = this->loadMaterialTextures(material, aiTextureType_SPECULAR, "texture_specular");
textures.insert(textures.end(), specularMaps.begin(), specularMaps.end());

// Return a mesh object created from the extracted mesh data
return Mesh(vertices, indices, textures);

// Checks all material textures of a given type and loads the textures if they're not loaded yet.
// The required info is returned as a Texture struct.
vector<Texture> loadMaterialTextures(aiMaterial* mat, aiTextureType type, string typeName)
vector<Texture> textures;
for (GLuint i = 0; i < mat->GetTextureCount(type); i++)
aiString str;
mat->GetTexture(type, i, &str);
// Check if texture was loaded before and if so, continue to next iteration: skip loading a new texture
GLboolean skip = false;
for (GLuint j = 0; j < textures_loaded.size(); j++)
if (textures_loaded[j].path == str)
skip = true; // A texture with the same filepath has already been loaded, continue to next one. (optimization)
if (!skip)
{ // If texture hasn't been loaded already, load it
Texture texture;
texture.id = TextureFromFile(str.C_Str(), this->directory);
texture.type = typeName;
texture.path = str;
this->textures_loaded.push_back(texture); // Store it as texture loaded for entire model, to ensure we won't unnecesery load duplicate textures.
return textures;

GLint TextureFromFile(const char* path, string directory)
//Generate texture ID and load texture data
string filename = string(path);
filename = directory + '/' + filename;
GLuint textureID;
glGenTextures(1, &textureID);
int width, height;
unsigned char* image = SOIL_load_image(filename.c_str(), &width, &height, 0, SOIL_LOAD_RGB);
// Assign texture to ID
glBindTexture(GL_TEXTURE_2D, textureID);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, image);

// Parameters
glBindTexture(GL_TEXTURE_2D, 0);
return textureID;


// Std. Includes
#include <string>

#include <glew.h>

#include <glfw3.h>

// GL includes
#include "Shader.h"
#include "Camera.h"
#include "Model.h"

// GLM Mathemtics
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>

// Other Libs
#include <SOIL.h>

// Properties
GLuint screenWidth = 800, screenHeight = 600;

// Function prototypes
void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode);
void scroll_callback(GLFWwindow* window, double xoffset, double yoffset);
void mouse_callback(GLFWwindow* window, double xpos, double ypos);
void Do_Movement();

// Camera
Camera camera(glm::vec3(0.0f, 0.0f, 3.0f));
bool keys[1024];
GLfloat lastX = 400, lastY = 300;
bool firstMouse = true;

GLfloat deltaTime = 0.0f;
GLfloat lastFrame = 0.0f;

// The MAIN function, from here we start our application and run our Game loop
int main()
// Init GLFW

GLFWwindow* window = glfwCreateWindow(screenWidth, screenHeight, "LearnOpenGL", nullptr, nullptr); // Windowed

// Set the required callback functions
glfwSetKeyCallback(window, key_callback);
glfwSetCursorPosCallback(window, mouse_callback);
glfwSetScrollCallback(window, scroll_callback);

// Options

// Initialize GLEW to setup the OpenGL Function pointers
glewExperimental = GL_TRUE;

// Define the viewport dimensions
glViewport(0, 0, screenWidth, screenHeight);

// Setup some OpenGL options

// Setup and compile our shaders
Shader shader("shader.vs", "shader.frag");

// Load models
Model ourModel("spaceship/Sample_Ship.obj");

// Draw in wireframe
//glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);

// Game loop
while (!glfwWindowShouldClose(window))
// Set frame time
GLfloat currentFrame = glfwGetTime();
deltaTime = currentFrame - lastFrame;
lastFrame = currentFrame;

// Check and call events

// Clear the colorbuffer
glClearColor(0.05f, 0.05f, 0.05f, 1.0f);

shader.Use(); // <-- Don't forget this one!
// Transformation matrices
glm::mat4 projection = glm::perspective(camera.Zoom, (float)screenWidth / (float)screenHeight, 0.1f, 100.0f);
glm::mat4 view = camera.GetViewMatrix();
glUniformMatrix4fv(glGetUniformLocation(shader.Pro gram, "projection"), 1, GL_FALSE, glm::value_ptr(projection));
glUniformMatrix4fv(glGetUniformLocation(shader.Pro gram, "view"), 1, GL_FALSE, glm::value_ptr(view));

// Draw the loaded model
glm::mat4 model;
model = glm::translate(model, glm::vec3(0.0f, -1.75f, 0.0f)); // Translate it down a bit so it's at the center of the scene
model = glm::scale(model, glm::vec3(0.2f, 0.2f, 0.2f)); // It's a bit too big for our scene, so scale it down
glUniformMatrix4fv(glGetUniformLocation(shader.Pro gram, "model"), 1, GL_FALSE, glm::value_ptr(model));

// Swap the buffers

return 0;

#pragma region "User input"

// Moves/alters the camera positions based on user input
void Do_Movement()
// Camera controls
if (keys[GLFW_KEY_W])
camera.ProcessKeyboard(FORWARD, deltaTime);
if (keys[GLFW_KEY_S])
camera.ProcessKeyboard(BACKWARD, deltaTime);
if (keys[GLFW_KEY_A])
camera.ProcessKeyboard(LEFT, deltaTime);
if (keys[GLFW_KEY_D])
camera.ProcessKeyboard(RIGHT, deltaTime);

// Is called whenever a key is pressed/released via GLFW
void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode)
if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
glfwSetWindowShouldClose(window, GL_TRUE);

if (action == GLFW_PRESS)
keys[key] = true;
else if (action == GLFW_RELEASE)
keys[key] = false;

void mouse_callback(GLFWwindow* window, double xpos, double ypos)
if (firstMouse)
lastX = xpos;
lastY = ypos;
firstMouse = false;

GLfloat xoffset = xpos - lastX;
GLfloat yoffset = lastY - ypos;

lastX = xpos;
lastY = ypos;

camera.ProcessMouseMovement(xoffset, yoffset);

void scroll_callback(GLFWwindow* window, double xoffset, double yoffset)

#pragma endregion


#ifndef SHADER_H
#define SHADER_H

#include <string>
#include <fstream>
#include <sstream>
#include <iostream>

#include <glew.h>
class Shader
// The Program ID
GLuint Program;
// Constructor reads and builds the shader
Shader(const GLchar* vertexPath, const GLchar* fragmentPath)
// 1. Retrieve the vertex/fragment source code from filePath
std::string vertexCode;
std::string fragmentCode;
std::ifstream vShaderFile;
std::ifstream fShaderFile;
std::stringstream vShaderStream, fShaderStream;
// Read file's buffer contents into streams
vShaderStream << vShaderFile.rdbuf();
fShaderStream << fShaderFile.rdbuf();
// Close file handlers
// Convert stream into GLchar array
vertexCode = vShaderStream.str();
fragmentCode = fShaderStream.str();
catch (std::ifstream::failure e)
std::cout << "ERROR::SHADER::FILE_NOT_SUCCESFULLY_READ" << std::endl;
const GLchar* vShaderCode = vertexCode.c_str();
const GLchar* fShaderCode = fragmentCode.c_str();

//Compile Shaders
GLuint vertex, fragment;
GLint success;
GLchar infoLog[512];

//Vertex Shader
vertex = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertex, 1, &vShaderCode, NULL);
// Print compile errors if any
glGetShaderiv(vertex, GL_COMPILE_STATUS, &success);
if (!success)
glGetShaderInfoLog(vertex, 512, NULL, infoLog);
std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl;

// Fragment Shader
fragment = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragment, 1, &fShaderCode, NULL);
// Print compile errors if any
glGetShaderiv(fragment, GL_COMPILE_STATUS, &success);
if (!success)
glGetShaderInfoLog(fragment, 512, NULL, infoLog);
std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << std::endl;

// Shader Program
this->Program = glCreateProgram();
glAttachShader(this->Program, vertex);
glAttachShader(this->Program, fragment);
// Print linking errors if any
glGetProgramiv(this->Program, GL_LINK_STATUS, &success);
if (!success)
glGetProgramInfoLog(this->Program, 512, NULL, infoLog);
std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << std::endl;
// Use the program
void Use()



#version 330 core
layout (location = 0) in vec3 position;
layout (location = 1) in vec3 normal;
layout (location = 2) in vec2 texCoords;

out vec2 TexCoords;

uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;

void main()
gl_Position = projection * view * model * vec4(position, 1.0f);
TexCoords = texCoords;


#version 330 core

in vec2 TexCoords;

out vec4 color;

uniform sampler2D texture_diffuse1;

void main()
color = vec4(texture(texture_diffuse1, TexCoords));

Ok...so I tried to use the debugger, but I didn't figure out what could it be.Maybe is not from the application.Maybe from graphics card.. ?
Maybe you can help me a little bit.
Thank you!

01-28-2017, 04:31 AM

I try to load the model in OpenGL with assimp.I copied and pasted the loading code from a tutorial and it builds.But when I run the application, the rendering window appears, but it's blocking and appears "ModelLoading.exe has stopped working".
What could be the problem ?

Thank you!

As the other poster said, this can be everything. But generally this kind of error has few chances to be related with OpenGL.
Most probably you have issues with dlls and/or misconfigurations within visual studio.

01-28-2017, 04:39 AM
I built the libraries for assimp. I reinstalled visual studio again but I had the same problem.Maybe it's from assimp's dll.I will try to see what I can do.
If you have any other ideas, please let me know. :)

02-05-2017, 09:34 PM
I am having a similar problem following learnopengl.com. I have been following the tutorial faithfully, but using ASSIMP has so far eluded me. My goal was to briefly go through each chapter, reading and familiarizing myself, then go back and complete the exercises and really cement in the knowledge.

I am possibly going to take a break from this, as the assimp library doesn't appear to have any compilation problems. And the command window doesn't display any errors. I tried debugging like you suggested, and it appears to be in the mesh parsing from the .obj file??? I could be wrong, but it looked like that was the problem.

I'm basically going to take a small break, and go back to the beginning and complete the exercises, and really understand all the things (so far...), hopefully, I can tinker with assimp and get it in the mean time.

Any advice with assimp would be greatly appreciated. I also tried to use their provided .dll, and .lib files. But I feel that CMake compiling my own .lib files, etc. worked well in this case.


Thanks in advance,

02-06-2017, 12:16 AM
Hi jeff,

I also took a break already from reading and started to build for the moment a snake game. :d
In the future, if I will manage something with the model loading I will let you know.Also if you will succeed please tell us.
Thank you!

02-11-2017, 03:09 PM
alx119. I found openframeworks.cc (http://www.openframeworks.cc)

Check it out, it's pretty awesome.

It is a wrapper for OpenGL and includes a BUNCH of 3rd part libraries including ASSIMP.

I'm going to use it, as well as, try to figure out how to get ASSIMP working in my own setup by following this as an example.


02-11-2017, 11:19 PM
Thank you Jeff, I'll have a look. :P

02-14-2017, 10:24 PM
Also, I'm making some tutorial videos with what I am learning. I just figured out that I can follow along in the OpenGL 4.5 Programming Guide (the red book), and I can do what I wanted to do when I bought the book......read about OpenGL and things to try tomorrow, before I go to bed each night. Anyways, my youtube channel is going to be my homemade forum signature, so check it out below if you want, I could use a few views! Alright, take care man, and never stop coding and exploring and seeking to learn more.