diff --git a/src/gamelogic.cpp b/src/gamelogic.cpp index 0832e49..bf89e42 100644 --- a/src/gamelogic.cpp +++ b/src/gamelogic.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -34,7 +35,9 @@ uint previousKeyFrame = 0; SceneNode* rootNode; SceneNode* plainNode; +SceneNode* carNode; SceneNode* boxNode; +SceneNode* sphereNode; SceneNode* hudNode; SceneNode* textNode; @@ -113,6 +116,7 @@ void initGame(GLFWwindow* window, CommandLineOptions gameOptions) { default_shader->makeBasicShader("../res/shaders/simple.vert", "../res/shaders/simple.frag"); Mesh box = generateBox(50, 50, 50); + Mesh sphere = generateSphere(10, 100, 100); Mesh plain = generateSegmentedPlane(1000, 1000, 100, 100, 3); Mesh hello_world = generateTextGeometryBuffer("Skjer'a bagera?", 1.3, 2); t_perlin.repeat_mirrored = true; @@ -127,6 +131,28 @@ void initGame(GLFWwindow* window, CommandLineOptions gameOptions) { rootNode->children.push_back(lightNode[i]); } + + carNode = loadModelScene("../res/models/beetle/scene.gltf", { + {-1, Material::diffuse({0.3, 0.3, 1.0, 1.0}, 30)},// default + //{ 0, Material::diffuse({1.0, 1.0, 1.0, 1.0})},// Blue_Metal + //{ 1, Material::diffuse({1.0, 1.0, 1.0, 1.0})},// Metal + //{ 2, Material::diffuse({1.0, 1.0, 1.0, 1.0})},// Front_Light_Glass + { 3, Material::diffuse({0.2, 0.2, 0.2, 1.0})},// Black_Rubber + //{ 4, Material::diffuse({1.0, 1.0, 1.0, 1.0})},// Mirror + //{ 5, Material::diffuse({1.0, 1.0, 1.0, 1.0})},// Black_Metal + //{ 6, Material::diffuse({1.0, 1.0, 1.0, 1.0})},// Plastic + { 7, Material::diffuse({0.1, 0.1, 0.1, 1.0})},// Window_Glass + //{ 8, Material::diffuse({1.0, 1.0, 1.0, 1.0})},// Material + //{ 9, Material::diffuse({1.0, 1.0, 1.0, 1.0})},// Glossy_metal + //{10, Material::diffuse({1.0, 1.0, 1.0, 1.0})},// Rogh_Metal + //{11, Material::diffuse({1.0, 1.0, 1.0, 1.0})},// License_Plate_Metal + //{12, Material::diffuse({1.0, 1.0, 1.0, 1.0})},// License_Plate_Frame + //{13, Material::diffuse({1.0, 1.0, 1.0, 1.0})},// + }); + carNode->position = {500, 500, 100}; + carNode->scale *= 100; + rootNode->children.push_back(carNode); + //create the scene: plainNode = createSceneNode(); plainNode->setTexture(&t_plain_diff, &t_plain_normal, &t_perlin); @@ -136,6 +162,7 @@ void initGame(GLFWwindow* window, CommandLineOptions gameOptions) { plainNode->displacementCoefficient = 40; rootNode->children.push_back(plainNode); + /* boxNode = createSceneNode(); boxNode->setTexture(&t_cobble_diff, &t_cobble_normal); boxNode->setMesh(&box); @@ -145,7 +172,14 @@ void initGame(GLFWwindow* window, CommandLineOptions gameOptions) { boxNode->shininess = 20; boxNode->displacementCoefficient = 40; rootNode->children.push_back(boxNode); - + + sphereNode = createSceneNode(); + sphereNode->setTexture(&t_cobble_diff, &t_cobble_normal); + sphereNode->setMesh(&sphere); + sphereNode->scale *= 2; + sphereNode->scale.z *= 20; + //lightNode[1]->children.push_back(sphereNode); + */ lightNode[0]->position = {-600, 1400, 800}; lightNode[0]->color_emissive = vec3(0.35); diff --git a/src/utilities/modelLoader.cpp b/src/utilities/modelLoader.cpp new file mode 100644 index 0000000..b1495a1 --- /dev/null +++ b/src/utilities/modelLoader.cpp @@ -0,0 +1,180 @@ +#include "modelLoader.hpp" + +#include // C++ importer interface +#include // Post processing flags +#include // aiScene and aiNode +#include // aiMaterial +#include // aiMesh +#include // aiTexture +#include +#include +#include +#include +#include +#include +#include "mesh.h" +#include "imageLoader.hpp" + +typedef unsigned int uint; +using std::vector; +using std::map; +using std::cout; +using std::cerr; +using std::endl; + +SceneNode* buildSceneNodes( + const aiNode* node, + const vector& meshes, + const vector& textures, + const vector& mat_lookup) { + if (DEBUG) cout << "Building node from " << node->mName.C_Str() << "..." << endl; + + // filter semantic-only nodes + if (node->mTransformation.IsIdentity() + && node->mNumMeshes == 0 + && node->mNumChildren == 1) + return buildSceneNodes(node->mChildren[0], meshes, textures, mat_lookup); + + SceneNode* out = createSceneNode(); + + if (!node->mTransformation.IsIdentity()) { + aiQuaterniont rotation; + aiVector3t position, scaling; + node->mTransformation.Decompose(scaling, rotation, position); + for(uint i=0; i<3; i++) out->position[i] = position[i]; + for(uint i=0; i<3; i++) out->scale[i] = scaling[i]; + out->rotation = glm::eulerAngles(glm::quat( + rotation.w, rotation.x, rotation.y, rotation.z)); + } + + for (uint i = 0; i < node->mNumMeshes; i++) { + SceneNode* mesh_node = createSceneNode(); + out->children.push_back(mesh_node); + uint meshidx = node->mMeshes[i]; + + mesh_node->basecolor = mat_lookup[meshidx]->basecolor; + mesh_node->shininess = mat_lookup[meshidx]->shininess; + +// mesh_node.setTexture(&meshes[node->mMeshes[i]]); + mesh_node->setMesh(&meshes[meshidx]); + + } + + for (uint i=0; imNumChildren; i++) + out->children.push_back(buildSceneNodes(node->mChildren[i], meshes, textures, mat_lookup)); + + return out; +} + +SceneNode* loadModelScene(const std::string& filename, const map& overrides) { + Assimp::Importer importer; + + const aiScene* scene = importer.ReadFile(filename, + aiProcess_CalcTangentSpace + //| aiProcess_FlipWindingOrder + | aiProcess_Triangulate + | aiProcess_GenNormals + | aiProcess_ImproveCacheLocality + //| aiProcess_JoinIdenticalVertices + | aiProcess_SortByPType + ); + if (!scene) { + cerr << importer.GetErrorString() << endl; + throw 1; + } + + // read materials + uint j=0; + Material default_material = Material::diffuse({1, 1, 1, 1}); + vector materials(scene->mNumMaterials); + for (Material& material : materials) { + const aiMaterial* aimat = scene->mMaterials[j++]; + + // print material + aiString name; aimat->Get(AI_MATKEY_NAME, name); + if (DEBUG){ + cout << "Read material #" << j-1 << " '" << name.C_Str() << "':" << endl; + for (uint i=0; i < aimat->mNumProperties; i++) + cout << " " << aimat->mProperties[i]->mKey.C_Str() << endl; + } + + aiColor4D diffuse (1,1,1,1); + aimat->Get(AI_MATKEY_COLOR_DIFFUSE, diffuse); + //aiGetMaterialColor(aimat, "$mat.gltf.pbrMetallicRoughness.baseColorFactor", 0, 0, &diffuse); + //aiGetMaterialColor(aimat, "$mat.gltf.pbrMetallicRoughness.metallicFactor", 0, 0, &diffuse); + //aiGetMaterialColor(aimat, "$mat.gltf.pbrMetallicRoughness.roughnessFactor", 0, 0, &diffuse); + material.basecolor = {diffuse.r, diffuse.g, diffuse.b, diffuse.a}; + + aimat->Get(AI_MATKEY_SHININESS, material.shininess); + } + + for (auto override : overrides) + ((override.first>=0) + ? materials[override.first] + : default_material + ) = override.second; + + vector meshes( scene->mNumMeshes); + vector textures(scene->mNumTextures); + vector mat_lookup(scene->mNumMeshes); // to be passed to buildSceneNodes + + // read meshes + j=0; + for (Mesh& mesh : meshes) { + const aiMesh* aimesh = scene->mMeshes[j++]; + for (uint i=0; i < aimesh->mNumVertices; i++){ + mesh.vertices.push_back({ + aimesh->mVertices[i].x, + aimesh->mVertices[i].y, + aimesh->mVertices[i].z, + }); + mesh.normals.push_back({ + aimesh->mNormals[i].x, + aimesh->mNormals[i].y, + aimesh->mNormals[i].z, + }); + } + + mat_lookup[j-1] = (aimesh->mMaterialIndex) + ? &materials[aimesh->mMaterialIndex] + : &default_material; + + if (aimesh->GetNumUVChannels() >= 1) + for (uint i=0; i < aimesh->mNumVertices; i++){ + //assert(aimesh->mNumUVComponents[0] == 2); + mesh.textureCoordinates.push_back({ + aimesh->mTextureCoords[0][i].x, + aimesh->mTextureCoords[0][i].y, + }); + } + + if (aimesh->GetNumColorChannels() >= 1) + for (uint i=0; i < aimesh->mNumVertices; i++){ + mesh.colors.push_back({ + aimesh->mColors[0][i].r, + aimesh->mColors[0][i].g, + aimesh->mColors[0][i].b, + aimesh->mColors[0][i].a, + }); + } + + for (uint i=0; i < aimesh->mNumFaces; i++){ + assert(aimesh->mFaces[i].mNumIndices == 3); + mesh.indices.insert(mesh.indices.end(), { + aimesh->mFaces[i].mIndices[0], + aimesh->mFaces[i].mIndices[1], + aimesh->mFaces[i].mIndices[2], + }); + } + } + + // read textures + j=0; + for (PNGImage& texture : textures) { + const aiTexture* aitex = scene->mTextures[j++]; + // todo + } + SceneNode* out = buildSceneNodes(scene->mRootNode, meshes, textures, mat_lookup); + out->rotation.x += M_PI/2; // account for my weird coordinates. Z is upward damnit! + return out; +} diff --git a/src/utilities/modelLoader.hpp b/src/utilities/modelLoader.hpp new file mode 100644 index 0000000..dc70b6d --- /dev/null +++ b/src/utilities/modelLoader.hpp @@ -0,0 +1,24 @@ +#pragma once + +#include "../sceneGraph.hpp" +#include +#include + +#define DEBUG false + +struct Material { + vec4 basecolor; + float shininess = 10; + int texture_id = -1; + + static Material diffuse(vec4 color, float shininess = 10){ + Material out; + out.basecolor = color; + out.shininess = shininess; + return out; + } +}; + +SceneNode* loadModelScene( + const std::string& filename, + const std::map& overrides={});