StaticModel * ModelLoader::LoadModel(VulkanBase* vulkanBase, std::string filename) { // Check if the model already is loaded if (mModelMap.find(filename) != mModelMap.end()) return mModelMap[filename]; StaticModel* model = nullptr; Assimp::Importer importer; // Load scene from the file. const aiScene* scene = importer.ReadFile(filename, aiProcess_FlipWindingOrder | aiProcess_Triangulate | aiProcess_PreTransformVertices | aiProcess_CalcTangentSpace | aiProcess_GenSmoothNormals | aiProcess_JoinIdenticalVertices); if (scene != nullptr) { model = new StaticModel; // Loop over all meshes for (int meshId = 0; meshId < scene->mNumMeshes; meshId++) { aiMesh* assimpMesh = scene->mMeshes[meshId]; // Get the diffuse color aiColor3D color(0.f, 0.f, 0.f); scene->mMaterials[assimpMesh->mMaterialIndex]->Get(AI_MATKEY_COLOR_DIFFUSE, color); Mesh mesh; // Load vertices for (int vertexId = 0; vertexId < assimpMesh->mNumVertices; vertexId++) { aiVector3D v = assimpMesh->mVertices[vertexId]; aiVector3D n = assimpMesh->mNormals[vertexId]; aiVector3D t = aiVector3D(0, 0, 0); if (assimpMesh->HasTextureCoords(0)) t = assimpMesh->mTextureCoords[0][vertexId]; n = n.Normalize(); Vertex vertex(v.x, v.y, v.z, n.x, n.y, n.z, 0, 0, 0, t.x, t.y, color.r, color.g, color.b); mesh.vertices.push_back(vertex); } // Load indices for (int faceId = 0; faceId < assimpMesh->mNumFaces; faceId++) { for (int indexId = 0; indexId < assimpMesh->mFaces[faceId].mNumIndices; indexId++) mesh.indices.push_back(assimpMesh->mFaces[faceId].mIndices[indexId]); } model->AddMesh(mesh); } // Add the model to the model map model->BuildBuffers(vulkanBase); // Build the models buffers here mModelMap[filename] = model; } else { // Loading of model failed assert(scene); } return model; }
//! Loads and returns a static model from a file. StaticModel* ModelImporter::LoadStaticModel(string filename) { // Is the model already loaded? if(mStaticModelMap.find(filename) != mStaticModelMap.end()) return mStaticModelMap[filename]; Assimp::Importer importer; mFilename = filename; StaticModel* model = NULL; // Important! Makes sure that if the angle between two face normals is > 80 they are not smoothed together. // Since the angle between a cubes face normals is 90 the lighting looks very bad if we don't specify this. importer.SetPropertyFloat(AI_CONFIG_PP_GSN_MAX_SMOOTHING_ANGLE, 80.0f); importer.SetPropertyInteger(AI_CONFIG_IMPORT_TER_MAKE_UVS, 1); importer.SetPropertyInteger(AI_CONFIG_PP_SBP_REMOVE, aiPrimitiveType_LINE); // Load scene from the file. const aiScene* scene = importer.ReadFile(filename, aiProcess_CalcTangentSpace | aiProcess_Triangulate | aiProcess_GenSmoothNormals | aiProcess_SplitLargeMeshes | aiProcess_ConvertToLeftHanded | aiProcess_SortByPType); // Successfully loaded the scene. if(scene) { // Create the model that is getting filled out. model = new StaticModel(); // Loop through all meshes. for(int i = 0; i < scene->mNumMeshes; i++) { aiMesh* assimpMesh = scene->mMeshes[i]; vector<Vertex> vertices; vector<UINT> indices; // Add vertices to the vertex list. for(int i = 0; i < assimpMesh->mNumVertices; i++) { aiVector3D v = assimpMesh->mVertices[i]; aiVector3D n = assimpMesh->mNormals[i]; aiVector3D t = aiVector3D(0, 0, 0); if(assimpMesh->HasTextureCoords(0)) t = assimpMesh->mTextureCoords[0][i]; n = n.Normalize(); Vertex vertex(v.x, v.y, v.z, n.x, n.y, n.z, 0, 0, 0, t.x, t.y); vertices.push_back(vertex); } // Add indices to the index list. for(int i = 0; i < assimpMesh->mNumFaces; i++) for(int j = 0; j < assimpMesh->mFaces[i].mNumIndices; j++) indices.push_back(assimpMesh->mFaces[i].mIndices[j]); // Get the path to the texture in the directory. aiString path; aiMaterial* material = scene->mMaterials[assimpMesh->mMaterialIndex]; material->Get(AI_MATKEY_TEXTURE_DIFFUSE(0), path); FindValidPath(&path); // Extract all the ambient, diffuse and specular colors. aiColor4D ambient, diffuse, specular; material->Get(AI_MATKEY_COLOR_AMBIENT, ambient); material->Get(AI_MATKEY_COLOR_DIFFUSE, diffuse); material->Get(AI_MATKEY_COLOR_SPECULAR, specular); // Create the mesh and its primitive. StaticMesh* mesh = new StaticMesh(); Primitive* primitive = new Primitive(GlobalApp::GetD3DDevice(), vertices, indices); mesh->SetPrimitive(primitive); mesh->SetVertices(vertices); mesh->SetIndices(indices); mPrimtiveFactory->AddPrimitive(path.C_Str(), primitive); // Any texture? if(_stricmp(path.C_Str(), "") != 0) mesh->LoadTexture(path.C_Str()); // Any normal map? aiString nmap; material->Get(AI_MATKEY_TEXTURE_HEIGHT(0), nmap); FindValidPath(&nmap); if(_stricmp(nmap.C_Str(), "") != 0) mesh->SetNormalMap(GlobalApp::GetGraphics()->LoadTexture(nmap.C_Str())); // [NOTE] The material is set to white. mesh->SetMaterial(Material(Colors::White)); // Was before [NOTE] model->SetFilename(filename); // Add the mesh to the model. model->AddMesh(mesh); } // Add to the model map and return it. mStaticModelMap[filename] = model; return mStaticModelMap[filename]; } else { char buffer[246]; sprintf(buffer, "Error loading model: %s", filename.c_str()); MessageBox(0, buffer, "Error!", 0); mStaticModelMap[filename] = LoadStaticModel("models/box.obj"); return mStaticModelMap[filename]; } }
StaticModel* ModelLoader::GenerateTerrain(VulkanBase* vulkanBase, std::string filename) { // Check if the model already is loaded if (mModelMap.find(filename) != mModelMap.end()) return mModelMap[filename]; // Load the terrain froma .tga file TextureData texture; LoadTGATextureData((char*)filename.c_str(), &texture); StaticModel* terrain = new StaticModel; Mesh mesh; int vertexCount = texture.width * texture.height; int triangleCount = (texture.width - 1) * (texture.height - 1) * 2; int x, z; mesh.vertices.resize(vertexCount); mesh.indices.resize(triangleCount * 3); printf("bpp %d\n", texture.bpp); for (x = 0; x < texture.width; x++) for (z = 0; z < texture.height; z++) { // Vertex array. You need to scale this properly float height = texture.imageData[(x + z * texture.width) * (texture.bpp / 8)] / 15.0f; vec3 pos = vec3(x / 1.0, height, z / 1.0); vec3 normal = vec3(0, 0, 0); vec2 uv = vec2(x / (float)texture.width, z / (float)texture.height); Vertex vertex = Vertex(pos, normal, uv, vec3(0, 0, 0), vec3(1.0, 1.0, 1.0)); mesh.vertices[x + z * texture.width] = vertex; } // Normal vectors. You need to calculate these. for (x = 0; x < texture.width; x++) { for (z = 0; z < texture.height; z++) { vec3 p1, p2, p3; vec3 edge = { 0.0f, 0.0f, 0.0f }; int i1; // p1 [x-1][z-1] if (x < 1 && z < 1) i1 = (x + 1 + (z + 1) * texture.width); else i1 = (x - 1 + (z - 1) * texture.width); // TODO: NOTE: HAX if (i1 < 0) i1 = 0; p1 = mesh.vertices[i1].Pos; // p1 [x-1][z] (if on the edge use [x+1] instead of [x-1]) int i2; if (x < 1) i2 = (x + 1 + (z)* texture.width); else i2 = (x - 1 + (z)* texture.width); p2 = mesh.vertices[i2].Pos; // p1 [x][z-1] int i3; if (z < 1) i3 = (x + (z + 1) * texture.width); else i3 = (x + (z - 1) * texture.width); p3 = mesh.vertices[i3].Pos; vec3 e1 = p2 - p1; vec3 e2 = p3 - p1; vec3 normal = glm::cross(e2, e1); if (normal != vec3(0, 0, 0)) int asda = 1; normal = glm::normalize(normal); //i = (x + 1 + (z + 1) * texture.width); mesh.vertices[i1].Normal += normal; mesh.vertices[i2].Normal += normal; mesh.vertices[i3].Normal += normal; // NOTE: Testing //mesh.vertices[i].Normal = vec3(0, 0, 0); } } for (x = 0; x < texture.width - 1; x++) { for (z = 0; z < texture.height - 1; z++) { // Triangle 1 mesh.indices[(x + z * (texture.width - 1)) * 6 + 0] = x + z * texture.width; mesh.indices[(x + z * (texture.width - 1)) * 6 + 1] = x + (z + 1) * texture.width; mesh.indices[(x + z * (texture.width - 1)) * 6 + 2] = x + 1 + z * texture.width; // Triangle 2 mesh.indices[(x + z * (texture.width - 1)) * 6 + 3] = x + 1 + z * texture.width; mesh.indices[(x + z * (texture.width - 1)) * 6 + 4] = x + (z + 1) * texture.width; mesh.indices[(x + z * (texture.width - 1)) * 6 + 5] = x + 1 + (z + 1) * texture.width; } } // Now loop through each vertex vector, and average out all the normals stored. for (int i = 0; i < mesh.vertices.size(); ++i) { mesh.vertices[i].Normal = glm::normalize(mesh.vertices[i].Normal); } terrain->AddMesh(mesh); terrain->BuildBuffers(vulkanBase); // Add to the map mModelMap[filename] = terrain; return terrain; }