void SubMesh::DrawImmediate() { if (!loaded) return; glBegin(GL_TRIANGLES); for (int i = 0; i < meshInfo.triCount; ++i) { Triangle t = GetTriangle(i); if (HasTextureCoords()) { for (int j = 0; j < 3; ++j) { VertexPositionTexcoord* vpt = GetVertexData<VertexPositionTexcoord>(t.index[j]); glVertex3fv(vpt->position); glTexCoord2fv(vpt->texCoord); } } else { for (int j = 0; j < 3; ++j) { VertexPositionNormalTexcoord* vpnt = GetVertexData<VertexPositionNormalTexcoord>(t.index[j]); glVertex3fv(vpnt->position); if (HasNormals()) glNormal3fv(vpnt->normal); if (HasTextureCoords()) glTexCoord2fv(vpnt->texCoord); } } } glEnd(); }
void Mesh::loadMeshdata(const std::string& a_Filepath) { Assimp::Importer importer; const auto scene = importer.ReadFile(a_Filepath, aiPostProcessSteps::aiProcess_CalcTangentSpace | aiPostProcessSteps::aiProcess_Triangulate | aiPostProcessSteps::aiProcess_JoinIdenticalVertices | aiPostProcessSteps::aiProcess_SortByPType); auto error = importer.GetErrorString(); auto mesh = scene->mMeshes[0]; m_Vertices.reserve(mesh->mNumVertices); for (auto i = 0u; i < mesh->mNumVertices; i++) { m_Vertices.emplace_back(toXMFloat3(mesh->mVertices[i]), mesh->HasVertexColors(i) ? toXMFloat4(mesh->mColors[0][i]) : XMFLOAT4(1.0f, 1.0f, 1.0f, 1.0f), mesh->HasTextureCoords(i) ? toXMFloat2(mesh->mTextureCoords[0][i]) : XMFLOAT2(0.0f, 0.0f)); } m_Indices.reserve(mesh->mNumFaces * 3); for (auto i = 0u; i < mesh->mNumFaces; ++i) { aiFace currentFace = mesh->mFaces[i]; for (auto j = 0u; j < currentFace.mNumIndices; ++j) { m_Indices.push_back(currentFace.mIndices[j]); } } }
void SubMesh::InitialiseVAO() { glGenVertexArrays(1, &vaoID); glGenBuffers(1, &bufID); glGenBuffers(1, &indexBufID); glBindVertexArray(vaoID); glBindBuffer(GL_ARRAY_BUFFER, bufID); glBufferData(GL_ARRAY_BUFFER, meshInfo.vertexSize * meshInfo.vertexCount , meshData, GL_STATIC_DRAW); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBufID); switch (meshInfo.indexFormat) { case GL_UNSIGNED_INT: glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned int) * meshInfo.triCount * 3, longIndexData, GL_STATIC_DRAW); break; case GL_UNSIGNED_SHORT: glBufferData(GL_ELEMENT_ARRAY_BUFFER, meshInfo.triCount * 3 * sizeof(unsigned short), indexData, GL_STATIC_DRAW); break; case GL_UNSIGNED_BYTE: glBufferData(GL_ELEMENT_ARRAY_BUFFER, meshInfo.triCount * 3 * sizeof(unsigned char), byteIndexData, GL_STATIC_DRAW); break; } glEnableVertexAttribArray(0); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, meshInfo.vertexSize, (void*)0); if (HasNormals()) { glEnableVertexAttribArray(1); glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, meshInfo.vertexSize, (void*)(3 * sizeof(float))); if (HasTextureCoords()) { glEnableVertexAttribArray(2); glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, meshInfo.vertexSize, (char*)0 + 6 * sizeof(float)); } } else if (HasTextureCoords()) { glEnableVertexAttribArray(1); glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, meshInfo.vertexSize, (char*)0 + 3 * sizeof(float)); } glBindVertexArray(0); loaded = true; }
// Assuming the metallic-roughness material model of models loaded with GLTF. std::pair<ID, std::vector<std::pair<Texture::Type, std::string>>> MeshManager::load_mesh(const std::string& directory, const std::string& file) { MeshInformation mesh_info; mesh_info.loaded_from_filepath = directory + file; Assimp::Importer importer; auto scene = importer.ReadFile(mesh_info.loaded_from_filepath.c_str(), aiProcess_Triangulate | aiProcess_JoinIdenticalVertices); if (scene == nullptr || scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE) { Log::error(std::string(importer.GetErrorString())); return {0, {}}; } std::vector<std::pair<Texture::Type, std::string>> texture_info; if (scene->HasMaterials()) { Log::info("Number of materials: " + std::to_string(scene->mNumMaterials)); for (size_t i = 0; i < scene->mNumMaterials; i++) { auto material = scene->mMaterials[i]; aiString material_name; material->Get(AI_MATKEY_NAME, material_name); Log::info("Material name: " + std::string(material_name.C_Str())); aiString diffuse_filepath; if (material->GetTexture(aiTextureType_DIFFUSE, 0, &diffuse_filepath) == AI_SUCCESS) { Log::info("Diffuse texture name: " + std::string(directory.c_str()) + std::string(diffuse_filepath.data)); std::string texture_filepath(diffuse_filepath.data); texture_filepath.insert(0, directory); texture_info.push_back({Texture::Type::Diffuse, texture_filepath}); } aiString specular_filepath; if (material->GetTexture(aiTextureType_SPECULAR, 0, &specular_filepath) == AI_SUCCESS) { Log::info("Specular texture name: " + std::string(directory.c_str()) + std::string(specular_filepath.data)); } aiString ambient_filepath; if (material->GetTexture(aiTextureType_AMBIENT, 0, &ambient_filepath) == AI_SUCCESS) { Log::info("Ambient occlusion texture name: " + std::string(directory.c_str()) + std::string(ambient_filepath.data)); } aiString shininess_filepath; if (material->GetTexture(aiTextureType_SHININESS, 0, &shininess_filepath) == AI_SUCCESS) { Log::info("Shininess texture name: " + std::string(directory.c_str()) + std::string(shininess_filepath.data)); } aiString emissive_filepath; if (material->GetTexture(aiTextureType_EMISSIVE, 0, &emissive_filepath) == AI_SUCCESS) { Log::info("Emissive texture name: " + std::string(directory.c_str()) + std::string(emissive_filepath.data)); std::string texture_filepath(emissive_filepath.data); texture_filepath.insert(0, directory); texture_info.push_back({Texture::Type::Emissive, texture_filepath}); // TODO: Fetch emissive factor as well } aiString displacement_filepath; if (material->GetTexture(aiTextureType_DISPLACEMENT, 0, &displacement_filepath) == AI_SUCCESS) { Log::info("Displacement texture name: " + std::string(directory.c_str()) + std::string(displacement_filepath.data)); } aiString height_filepath; if (material->GetTexture(aiTextureType_HEIGHT, 0, &height_filepath) == AI_SUCCESS) { Log::info("Bumpmap texture name: " + std::string(directory.c_str()) + std::string(height_filepath.data)); } // Lightmap is usually the ambient occlusion map ... aiString lightmap_filepath; if (material->GetTexture(aiTextureType_LIGHTMAP, 0, &lightmap_filepath) == AI_SUCCESS) { Log::info("Lightmap texture name: " + std::string(directory.c_str()) + std::string(lightmap_filepath.data)); std::string texture_filepath(lightmap_filepath.data); texture_filepath.insert(0, directory); texture_info.push_back({Texture::Type::AmbientOcclusion, texture_filepath}); } aiString normals_filepath; if (material->GetTexture(aiTextureType_NORMALS, 0, &normals_filepath) == AI_SUCCESS) { Log::info("Normals texture name: " + std::string(directory.c_str()) + std::string(normals_filepath.data)); } aiString reflection_filepath; if (material->GetTexture(aiTextureType_REFLECTION, 0, &reflection_filepath) == AI_SUCCESS) { Log::info("Reflection texture name: " + std::string(directory.c_str()) + std::string(reflection_filepath.data)); } aiString opacity_filepath; if (material->GetTexture(aiTextureType_OPACITY, 0, &opacity_filepath) == AI_SUCCESS) { Log::info("Opacity texture name: " + std::string(directory.c_str()) + std::string(opacity_filepath.data)); } // NOTE: Roughness metallic textures are not detected so here we are assuming this is the unknown texture of the material. aiString unknown_filepath; if (material->GetTexture(aiTextureType_UNKNOWN, 0, &unknown_filepath) == AI_SUCCESS) { Log::info("Unknown texture name: " + std::string(directory.c_str()) + std::string(unknown_filepath.data)); std::string texture_filepath(normals_filepath.data); texture_filepath.insert(0, directory); texture_info.push_back({Texture::Type::MetallicRoughness, texture_filepath}); } } } if (scene->HasMeshes()) { // FIXME: Assumes the mesh is a single mesh and not a hierarchy Log::info("Scene: # meshes " + std::to_string(scene->mNumMeshes)); for (size_t i = 0; i < scene->mNumMeshes; i++) { auto mesh = scene->mMeshes[i]; Log::info("Loading mesh with name: " + std::string(mesh->mName.data)); for (size_t j = 0; j < mesh->mNumVertices; j++) { Vertex vertex; auto pos = mesh->mVertices[j]; vertex.position = {pos.x, pos.y, pos.z}; if (mesh->HasTextureCoords(0)) { auto tex_coord = mesh->mTextureCoords[0][j]; vertex.tex_coord = {tex_coord.x, -tex_coord.y}; // glTF (& .obj) has a flipped texture coordinate system compared to OpenGL } if (mesh->HasNormals()) { auto normal = mesh->mNormals[j]; vertex.normal = {normal.x, normal.y, normal.z}; } mesh_info.mesh.vertices.push_back(vertex); } for (size_t j = 0; j < mesh->mNumFaces; j++) { auto face = &mesh->mFaces[j]; if (face->mNumIndices != 3) { Log::warn("Not 3 vertices per face in model."); return {0, {}}; } for (size_t k = 0; k < 3; k++) { auto index = face->mIndices[k]; mesh_info.mesh.indices.push_back(index); } } } } // FIXME: Mesh id is worthless since it does not change or anything ... loaded_meshes.push_back(mesh_info.mesh); return {loaded_meshes.size() - 1, texture_info}; }
MeshPtr AssimpMeshIO::load(const std::string &mesh_name, const std::string &file_name, unsigned int mesh_index, const BufferManagerPtr &buffer_manager, const VaoManagerPtr &vao_manager) { auto scene = importer->ReadFile(file_name, aiProcessPreset_TargetRealtime_MaxQuality | aiProcess_ConvertToLeftHanded); if (scene == nullptr) { throw clan::Exception(clan::string_format("Unable to locate (%1) for (%2)", file_name, mesh_name)); } if (scene->mNumMeshes <= mesh_index) throw clan::Exception(clan::string_format("The mesh index (%1) was out of bounds for mesh %2.", mesh_index, mesh_name)); auto scene_mesh = scene->mMeshes[mesh_index]; unsigned int stride = 0; std::vector<Core::VertexAttribute> interleaved_spec; Core::VaoLayout vao_layout; Core::RenderCommand render_command; // vectors to store bounds position and size in. glm::vec3 mesh_bounds_pos = glm::vec3(0); glm::vec3 mesh_bounds_size = glm::vec3(0); if (scene_mesh->HasPositions() && scene_mesh->mNumVertices > 0) { mesh_bounds_pos = glm::vec3(scene_mesh->mVertices[0].x, scene_mesh->mVertices[0].y, scene_mesh->mVertices[0].z); mesh_bounds_size = mesh_bounds_pos; } // // Set up vertices // // Set up the interleaved vertex attributes if (scene_mesh->HasPositions()) { stride += sizeof(glm::vec3); interleaved_spec.push_back(Core::VaoArg<glm::vec3>(Core::ShaderConstants::Position)); } if (scene_mesh->HasNormals()) { stride += sizeof(glm::vec3); interleaved_spec.push_back(Core::VaoArg<glm::vec3>(Core::ShaderConstants::Normal)); } if (scene_mesh->HasTextureCoords(0)) { stride += sizeof(glm::vec2); interleaved_spec.push_back(Core::VaoArg<glm::vec2>(Core::ShaderConstants::TexCoord)); } if (scene_mesh->HasTangentsAndBitangents()) { stride += 2*sizeof(glm::vec3); interleaved_spec.push_back(Core::VaoArg<glm::vec3>(Core::ShaderConstants::Tangent)); interleaved_spec.push_back(Core::VaoArg<glm::vec3>(Core::ShaderConstants::Bitangent)); } std::vector<float> vertices; vertices.reserve(scene_mesh->mNumVertices * stride / sizeof(float)); // This is how many floats we have for (unsigned int i = 0; i < scene_mesh->mNumVertices; i++) { // This may be made into a lambda for BuffeOperations::unsafe_upload if (scene_mesh->HasPositions()) { auto position = scene_mesh->mVertices[i]; vertices.push_back(position.x); vertices.push_back(position.y); vertices.push_back(position.z); // check for new min-max component in vertex, and update bounds. check_if_new_min_or_max_vertex(glm::vec3(position.x, position.y, position.z), mesh_bounds_pos, mesh_bounds_size); } if (scene_mesh->HasNormals()) { auto normal = scene_mesh->mNormals[i]; vertices.push_back(normal.x); vertices.push_back(normal.y); vertices.push_back(normal.z); } if (scene_mesh->HasTextureCoords(0)) { auto texcoord = scene_mesh->mTextureCoords[0][i]; vertices.push_back(texcoord.x); vertices.push_back(texcoord.y); } if (scene_mesh->HasTangentsAndBitangents()) { auto tangent = scene_mesh->mTangents[i]; vertices.push_back(tangent.x); vertices.push_back(tangent.y); vertices.push_back(tangent.z); auto bitangent = scene_mesh->mBitangents[i]; vertices.push_back(bitangent.x); vertices.push_back(bitangent.y); vertices.push_back(bitangent.z); } } auto vertex_allocation = buffer_manager->allocate(vertices.size()*stride, stride); vertex_allocation.upload(vertices); vao_layout .for_buffer(vertex_allocation) .use_as(GL_ARRAY_BUFFER) .bind_interleaved(0, 0, interleaved_spec); render_command.set_draw_mode(GL_TRIANGLES); render_command.set_vertices(vertex_allocation, scene_mesh->mNumVertices, stride); // // Set up indices // if (scene_mesh->HasFaces()) { std::vector<unsigned int> indices; for (unsigned int i = 0; i < scene_mesh->mNumFaces; i++) { auto face = scene_mesh->mFaces[i]; for (unsigned int j = 0; j < face.mNumIndices; j++) { indices.push_back(face.mIndices[j]); } } auto index_allocation = buffer_manager->allocate_and_upload(indices); vao_layout .for_buffer(index_allocation) .use_as(GL_ELEMENT_ARRAY_BUFFER); render_command.set_indices(index_allocation, indices); } // Ensure that mesh_bounds_size is the distance from mesh_bounds_pos to upper-right-back-corner of the bounds mesh_bounds_size = glm::vec3( mesh_bounds_size.x - mesh_bounds_pos.x, mesh_bounds_size.y - mesh_bounds_pos.y, mesh_bounds_size.z - mesh_bounds_pos.z ); return std::make_shared<Mesh>(render_command, vao_layout, vao_manager, mesh_name, mesh_bounds_pos, mesh_bounds_size); }
std::vector<Vertex> ModelLoader::load(int& numTriangles, int& numTextures) { std::ifstream fileCheck(filename); Vertex tempVert; std::vector<Vertex> geometry; std::deque<aiVector3D> texCoord; numTriangles = 0; numTextures = 0; for(int i = 0; i < 3; i++) tempVert.color[i] = 1.0; if(!fileCheck) { std::cerr << "Error: Unable to open object file" << std::endl; exit(-1); } fileCheck.close(); Assimp::Importer importer; auto scene = importer.ReadFile(filename, aiProcessPreset_TargetRealtime_Fast); if(!scene) { std::cerr << "Error: " << importer.GetErrorString() << std::endl; exit(-1); } std::cout << "Material Count: " << scene->mNumMaterials << std::endl; if(scene->HasMaterials()) { const auto& material = scene->mMaterials[0]; aiColor3D color(0.0f,0.0f,0.0); material->Get(AI_MATKEY_COLOR_DIFFUSE, color); tempVert.color[0] = color.r; tempVert.color[1] = color.g; tempVert.color[2] = color.b; } for(unsigned int i = 0; i < scene->mNumMeshes; i++) { auto mesh = scene->mMeshes[i]; if(scene->mNumMaterials > i+1) { auto material = scene->mMaterials[i+1]; aiColor3D color(1.0f,1.0f,1.0f); material->Get(AI_MATKEY_COLOR_DIFFUSE, color); tempVert.color[0] = color.r; tempVert.color[1] = color.g; tempVert.color[2] = color.b; if(material->GetTextureCount(aiTextureType_DIFFUSE) > 0) { aiString path; if(material->GetTexture(aiTextureType_DIFFUSE, 0, &path, NULL, NULL, NULL, NULL, NULL) == AI_SUCCESS) { std::cout << "Texture Path: " << path.C_Str() << std::endl; numTextures++; loadTexture(path.C_Str()); /* for(unsigned int j = 0; j < mesh->mNumVertices; j++) { const auto textureCoords = mesh->HasTextureCoords(0) ? mesh->mTextureCoords[0][j] : aiVector3D(0.0f,0.0f,0.0f); //texCoord.emplace_back(textureCoords); } */ } } } numTriangles += mesh->mNumFaces; for(unsigned int j = 0; j < mesh->mNumFaces; j++) { const auto& face = mesh->mFaces[j]; for(unsigned int k = 0; k < face.mNumIndices; k++) { const auto& vertex = mesh->mVertices[face.mIndices[k]]; tempVert.position[0] = vertex.x; tempVert.position[1] = vertex.y; tempVert.position[2] = vertex.z; const auto& textureVertex = mesh->HasTextureCoords(0) ? mesh->mTextureCoords[0][face.mIndices[k]] : aiVector3D(0,0,0); tempVert.textCoord[0] = textureVertex[0]; tempVert.textCoord[1] = textureVertex[1]; geometry.push_back(tempVert); } } } //loadTexture("checkerboard.jpg"); std::cout << "size: " << geometry.size() << std::endl << "bytes: " << sizeof(tempVert) * geometry.size() << std::endl; return geometry; }