// // Created by karl on 12.01.20. // #ifndef ECSGAME_OBJMESH_H #define ECSGAME_OBJMESH_H #include "../../Util/OBJ_Loader.h" #include "Mesh.h" struct ObjMesh : public Mesh { struct Settings { Settings() = default; Settings(float minDistanceForRender, float maxDistanceForRender, float diffuse, float specular) : minDistanceForRender(minDistanceForRender), maxDistanceForRender(maxDistanceForRender) {} float minDistanceForRender = 0.0; float maxDistanceForRender = 1000.0; }; explicit ObjMesh(const std::string &path, const Settings &settings) : Mesh(getVerticesFromFile(path), getIndicesFromFile(path)), minDistance(settings.minDistanceForRender), maxDistance(settings.maxDistanceForRender) {} float minDistance; float maxDistance; private: static std::vector getVerticesFromFile(const std::string &path) { objl::Loader loader; bool loadout = loader.LoadFile(path); if (loadout) { // TODO: Currently only the first mesh is used objl::Mesh curMesh = loader.LoadedMeshes[0]; std::vector vertexData = std::vector(); auto tangents = getTangentsFromVertices(curMesh.Vertices, getIndicesFromFile(path)); for (int i = 0; i <= curMesh.Vertices.size(); i++) { auto vertex = curMesh.Vertices[i]; auto tangent = tangents.first[i]; auto bitangent = tangents.second[i]; vertexData.emplace_back(vertex.Position.X); vertexData.emplace_back(vertex.Position.Y); vertexData.emplace_back(vertex.Position.Z); vertexData.emplace_back(vertex.Normal.X); vertexData.emplace_back(vertex.Normal.Y); vertexData.emplace_back(vertex.Normal.Z); vertexData.emplace_back(vertex.TextureCoordinate.X); vertexData.emplace_back(vertex.TextureCoordinate.Y); vertexData.emplace_back(tangent.x); vertexData.emplace_back(tangent.y); vertexData.emplace_back(tangent.z); vertexData.emplace_back(bitangent.x); vertexData.emplace_back(bitangent.y); vertexData.emplace_back(bitangent.z); } return vertexData; } else { // Output Error std::cout << "Failed to Load File. May have failed to find it or it was not an .obj file.\n"; } } static std::pair, std::vector> getTangentsFromVertices(const std::vector &vertices, const std::vector indices) { // These vectors hold tangents and bitangents in the same way in which the vertices vectors // holds vertices: Their index in the vector corresponds to indices in the indices vector. std::vector tangents(vertices.size()); std::vector bitangents(vertices.size()); // Iterate over all triangles for (uint index = 0; index < indices.size(); index += 3) { // Index in vertex buffer uint i0 = indices[index]; uint i1 = indices[index + 1]; uint i2 = indices[index + 2]; // Inputs glm::vec3 vertex0 = glm::vec3(vertices[i0].Position.X, vertices[i0].Position.Y, vertices[i0].Position.Z); glm::vec3 vertex1 = glm::vec3(vertices[i1].Position.X, vertices[i1].Position.Y, vertices[i1].Position.Z); glm::vec3 vertex2 = glm::vec3(vertices[i2].Position.X, vertices[i2].Position.Y, vertices[i2].Position.Z); glm::vec2 uv0 = glm::vec2(vertices[i0].TextureCoordinate.X, vertices[i0].TextureCoordinate.Y); glm::vec2 uv1 = glm::vec2(vertices[i1].TextureCoordinate.X, vertices[i1].TextureCoordinate.Y); glm::vec2 uv2 = glm::vec2(vertices[i2].TextureCoordinate.X, vertices[i2].TextureCoordinate.Y); glm::vec3 normal0 = glm::vec3(vertices[i0].Normal.X, vertices[i0].Normal.Y, vertices[i0].Normal.Z); glm::vec3 normal1 = glm::vec3(vertices[i1].Normal.X, vertices[i1].Normal.Y, vertices[i1].Normal.Z); glm::vec3 normal2 = glm::vec3(vertices[i2].Normal.X, vertices[i2].Normal.Y, vertices[i2].Normal.Z); // Edges of the triangle : position delta glm::vec3 deltaPos1 = vertex1 - vertex0; glm::vec3 deltaPos2 = vertex2 - vertex0; // UV delta glm::vec2 deltaUV1 = uv1 - uv0; glm::vec2 deltaUV2 = uv2 - uv0; float r = 1.0f / (deltaUV1.x * deltaUV2.y - deltaUV1.y * deltaUV2.x); glm::vec3 tangent = (deltaPos1 * deltaUV2.y - deltaPos2 * deltaUV1.y) * r; glm::vec3 bitangent = (deltaPos2 * deltaUV1.x - deltaPos1 * deltaUV2.x) * r; // Add the tangent and bitangent to the current value in the array. // This is done to get an average in the end. tangents[i0] += tangent; tangents[i1] += tangent; tangents[i2] += tangent; bitangents[i0] += bitangent; bitangents[i1] += bitangent; bitangents[i2] += bitangent; } return std::pair, std::vector>(tangents, bitangents); } static std::vector getIndicesFromFile(const std::string &path) { objl::Loader loader; bool loadout = loader.LoadFile(path); if (loadout) { // TODO: Currently only the first mesh is used objl::Mesh curMesh = loader.LoadedMeshes[0]; std::vector indices = std::vector(); // Emplace indices into the float vector for (int j = 0; j < curMesh.Indices.size(); j++) { indices.emplace_back(curMesh.Indices[j]); } return indices; } else { // Output Error std::cout << "Failed to Load File. May have failed to find it or it was not an .obj file.\n"; } } // TODO: Only prints at the moment static std::vector getMaterialFromFile(const std::string &path) { objl::Loader loader; bool loadout = loader.LoadFile(path); if (loadout) { // TODO: Currently only the first mesh is used objl::Mesh curMesh = loader.LoadedMeshes[0]; std::vector vertexData = std::vector(); // Print Material std::cout << "Material: " << curMesh.MeshMaterial.name << "\n"; std::cout << "Ambient Color: " << curMesh.MeshMaterial.Ka.X << ", " << curMesh.MeshMaterial.Ka.Y << ", " << curMesh.MeshMaterial.Ka.Z << "\n"; std::cout << "Diffuse Color: " << curMesh.MeshMaterial.Kd.X << ", " << curMesh.MeshMaterial.Kd.Y << ", " << curMesh.MeshMaterial.Kd.Z << "\n"; std::cout << "Specular Color: " << curMesh.MeshMaterial.Ks.X << ", " << curMesh.MeshMaterial.Ks.Y << ", " << curMesh.MeshMaterial.Ks.Z << "\n"; std::cout << "Specular Exponent: " << curMesh.MeshMaterial.Ns << "\n"; std::cout << "Optical Density: " << curMesh.MeshMaterial.Ni << "\n"; std::cout << "Dissolve: " << curMesh.MeshMaterial.d << "\n"; std::cout << "Illumination: " << curMesh.MeshMaterial.illum << "\n"; std::cout << "Ambient Texture Map: " << curMesh.MeshMaterial.map_Ka << "\n"; std::cout << "Diffuse Texture Map: " << curMesh.MeshMaterial.map_Kd << "\n"; std::cout << "Specular Texture Map: " << curMesh.MeshMaterial.map_Ks << "\n"; std::cout << "Alpha Texture Map: " << curMesh.MeshMaterial.map_d << "\n"; std::cout << "Bump Map: " << curMesh.MeshMaterial.map_bump << "\n"; return vertexData; } else { // Output Error std::cout << "Failed to Load File. May have failed to find it or it was not an .obj file.\n"; } } }; #endif // ECSGAME_OBJMESH_H