virtual bool importerTest() { Assimp::Importer importer; const aiScene *scene = importer.ReadFile( ASSIMP_TEST_MODELS_DIR "/OBJ/spider.obj", 0 ); return nullptr != scene; }
IndexedMesh * MeshLoader::LoadMesh(const std::string &path) { // Load the file Assimp::Importer importer; const aiScene* scene = importer.ReadFile( path, aiProcess_Triangulate | aiProcess_JoinIdenticalVertices | aiProcess_OptimizeGraph | aiProcess_OptimizeMeshes | aiProcess_RemoveRedundantMaterials | aiProcess_GenSmoothNormals ); if (scene->HasMeshes()) { // Get the model mesh aiMesh &mesh = *scene->mMeshes[0]; if (!mesh.HasPositions() || !mesh.HasFaces()) return NULL; // Initialize the model vector<glm::vec3> vertices; vector<GLuint> indices; vector<glm::vec4> colors; vector<glm::vec3> normals; // Get mesh properties for (unsigned int i=0; i<mesh.mNumVertices; ++i) { // Get vertices vertices.push_back(glm::vec3(mesh.mVertices[i].x, mesh.mVertices[i].y, mesh.mVertices[i].z)); // Get colors if(mesh.HasVertexColors(0)) { colors.push_back(glm::vec4(mesh.mColors[0][i].r, mesh.mColors[0][i].g, mesh.mColors[0][i].b, mesh.mColors[0][i].a)); } else { colors.push_back(glm::vec4(1,1,1,1)); } // Get normals normals.push_back(glm::vec3(mesh.mNormals[i].x, mesh.mNormals[i].y, mesh.mNormals[i].z)); } // Normalize vertices normalizeVertices(vertices); // Get indices for (unsigned int i=0; i<mesh.mNumFaces; ++i) { aiFace face = mesh.mFaces[i]; indices.push_back(face.mIndices[0]); indices.push_back(face.mIndices[1]); indices.push_back(face.mIndices[2]); } return new IndexedMesh(vertices, indices, colors, normals); } return NULL; }
virtual bool importerTest() { Assimp::Importer importer; const aiScene *scene = importer.ReadFile( ASSIMP_TEST_MODELS_DIR "/glTF2/BoxTextured-glTF/BoxTextured.gltf", aiProcess_ValidateDataStructure); return nullptr != scene; }
Mesh::Mesh(const std::string& fileName) : m_fileName(fileName), m_meshData(0) { std::map<std::string, MeshData*>::const_iterator it = s_resourceMap.find(fileName); if(it != s_resourceMap.end()) { m_meshData = it->second; m_meshData->AddReference(); } else { Assimp::Importer importer; const aiScene* scene = importer.ReadFile(("./res/models/" + fileName).c_str(), aiProcess_Triangulate | aiProcess_GenSmoothNormals | aiProcess_FlipUVs | aiProcess_CalcTangentSpace); if(!scene) { std::cout << "Mesh load failed!: " << fileName << std::endl; assert(0 == 0); } const aiMesh* model = scene->mMeshes[0]; std::vector<Vector3f> positions; std::vector<Vector2f> texCoords; std::vector<Vector3f> normals; std::vector<Vector3f> tangents; std::vector<unsigned int> indices; const aiVector3D aiZeroVector(0.0f, 0.0f, 0.0f); for(unsigned int i = 0; i < model->mNumVertices; i++) { const aiVector3D pos = model->mVertices[i]; const aiVector3D normal = model->mNormals[i]; const aiVector3D texCoord = model->HasTextureCoords(0) ? model->mTextureCoords[0][i] : aiZeroVector; const aiVector3D tangent = model->mTangents[i]; positions.push_back(Vector3f(pos.x, pos.y, pos.z)); texCoords.push_back(Vector2f(texCoord.x, texCoord.y)); normals.push_back(Vector3f(normal.x, normal.y, normal.z)); tangents.push_back(Vector3f(tangent.x, tangent.y, tangent.z)); } for(unsigned int i = 0; i < model->mNumFaces; i++) { const aiFace& face = model->mFaces[i]; assert(face.mNumIndices == 3); indices.push_back(face.mIndices[0]); indices.push_back(face.mIndices[1]); indices.push_back(face.mIndices[2]); } m_meshData = new MeshData(IndexedModel(indices, positions, texCoords, normals, tangents)); s_resourceMap.insert(std::pair<std::string, MeshData*>(fileName, m_meshData)); } }
S3DModel* CAssParser::Load(const std::string& modelFilePath) { LOG_SL(LOG_SECTION_MODEL, L_INFO, "Loading model: %s", modelFilePath.c_str()); const std::string& modelPath = FileSystem::GetDirectory(modelFilePath); const std::string& modelName = FileSystem::GetBasename(modelFilePath); // Load the lua metafile. This contains properties unique to Spring models and must return a table std::string metaFileName = modelFilePath + ".lua"; if (!CFileHandler::FileExists(metaFileName, SPRING_VFS_ZIP)) { // Try again without the model file extension metaFileName = modelPath + '/' + modelName + ".lua"; } if (!CFileHandler::FileExists(metaFileName, SPRING_VFS_ZIP)) { LOG_SL(LOG_SECTION_MODEL, L_INFO, "No meta-file '%s'. Using defaults.", metaFileName.c_str()); } LuaParser metaFileParser(metaFileName, SPRING_VFS_MOD_BASE, SPRING_VFS_ZIP); if (!metaFileParser.Execute()) { LOG_SL(LOG_SECTION_MODEL, L_INFO, "'%s': %s. Using defaults.", metaFileName.c_str(), metaFileParser.GetErrorLog().c_str()); } // Get the (root-level) model table const LuaTable& modelTable = metaFileParser.GetRoot(); if (!modelTable.IsValid()) { LOG_SL(LOG_SECTION_MODEL, L_INFO, "No valid model metadata in '%s' or no meta-file", metaFileName.c_str()); } // Create a model importer instance Assimp::Importer importer; // Give the importer an IO class that handles Spring's VFS importer.SetIOHandler(new AssVFSSystem()); // Speed-up processing by skipping things we don't need importer.SetPropertyInteger(AI_CONFIG_PP_RVC_FLAGS, ASS_IMPORTER_OPTIONS); #ifndef BITMAP_NO_OPENGL { importer.SetPropertyInteger(AI_CONFIG_PP_SLM_VERTEX_LIMIT, maxVertices); importer.SetPropertyInteger(AI_CONFIG_PP_SLM_TRIANGLE_LIMIT, maxIndices / 3); } #endif // Read the model file to build a scene object LOG_SL(LOG_SECTION_MODEL, L_INFO, "Importing model file: %s", modelFilePath.c_str()); const aiScene* scene = nullptr; { // ASSIMP spams many SIGFPEs atm in normal & tangent generation ScopedDisableFpuExceptions fe; scene = importer.ReadFile(modelFilePath, ASS_POSTPROCESS_OPTIONS); } if (scene != nullptr) { LOG_SL(LOG_SECTION_MODEL, L_INFO, "Processing scene for model: %s (%d meshes / %d materials / %d textures)", modelFilePath.c_str(), scene->mNumMeshes, scene->mNumMaterials, scene->mNumTextures); } else { throw content_error("[AssimpParser] Model Import: " + std::string(importer.GetErrorString())); } ModelPieceMap pieceMap; ParentNameMap parentMap; S3DModel* model = new S3DModel(); model->name = modelFilePath; model->type = MODELTYPE_ASS; // Load textures FindTextures(model, scene, modelTable, modelPath, modelName); LOG_SL(LOG_SECTION_MODEL, L_INFO, "Loading textures. Tex1: '%s' Tex2: '%s'", model->texs[0].c_str(), model->texs[1].c_str()); texturehandlerS3O->PreloadTexture(model, modelTable.GetBool("fliptextures", true), modelTable.GetBool("invertteamcolor", true)); // Load all pieces in the model LOG_SL(LOG_SECTION_MODEL, L_INFO, "Loading pieces from root node '%s'", scene->mRootNode->mName.data); LoadPiece(model, scene->mRootNode, scene, modelTable, pieceMap, parentMap); // Update piece hierarchy based on metadata BuildPieceHierarchy(model, pieceMap, parentMap); CalculateModelProperties(model, modelTable); // Verbose logging of model properties LOG_SL(LOG_SECTION_MODEL, L_DEBUG, "model->name: %s", model->name.c_str()); LOG_SL(LOG_SECTION_MODEL, L_DEBUG, "model->numobjects: %d", model->numPieces); LOG_SL(LOG_SECTION_MODEL, L_DEBUG, "model->radius: %f", model->radius); LOG_SL(LOG_SECTION_MODEL, L_DEBUG, "model->height: %f", model->height); LOG_SL(LOG_SECTION_MODEL, L_DEBUG, "model->mins: (%f,%f,%f)", model->mins[0], model->mins[1], model->mins[2]); LOG_SL(LOG_SECTION_MODEL, L_DEBUG, "model->maxs: (%f,%f,%f)", model->maxs[0], model->maxs[1], model->maxs[2]); LOG_SL(LOG_SECTION_MODEL, L_INFO, "Model %s Imported.", model->name.c_str()); return model; }
virtual bool importerTest() { Assimp::Importer importer; const aiScene *scene = importer.ReadFile( ASSIMP_TEST_MODELS_DIR "/X3D/ComputerKeyboard.x3d", aiProcess_ValidateDataStructure ); return nullptr != scene; }
TEST_F( utSTLImporterExporter, test_with_two_solids ) { Assimp::Importer importer; const aiScene *scene = importer.ReadFile( ASSIMP_TEST_MODELS_DIR "/STL/triangle_with_two_solids.stl", aiProcess_ValidateDataStructure ); EXPECT_NE( nullptr, scene ); }
int main(int argc, char** argv) { if ( argc < 2 ) { fprintf(stderr, "Usage: %s filename format\n" " format = minimal|simple\n", argv[0]); return 42; } VertexType format = VERTEXTYPE_SIMPLE; if ( argc >= 3 ) { static const u32 nbFormats = sizeof(formats)/sizeof(formats[0]); u32 i = 0; for ( ; i < nbFormats ; i++ ) { if ( strcmp(formats[i], argv[2]) == 0 ) { format = (VertexType)i; break; } } if ( i == nbFormats ) { fprintf(stderr, "Unknown format %s\n", argv[2]); return 42; } } Assimp::Importer importer; importer.SetPropertyInteger(AI_CONFIG_PP_SBP_REMOVE, aiPrimitiveType_POINT | aiPrimitiveType_LINE); static u32 removeComponents[VERTEXTYPE_COUNT] = { // VERTEXTYPE_MINIMAL aiComponent_COLORS | aiComponent_TEXCOORDS | aiComponent_NORMALS | aiComponent_TANGENTS_AND_BITANGENTS | aiComponent_BONEWEIGHTS | aiComponent_ANIMATIONS | aiComponent_TEXTURES | aiComponent_LIGHTS | aiComponent_CAMERAS | aiComponent_MATERIALS, // VERTEXTYPE_SIMPLE aiComponent_COLORS | aiComponent_TEXCOORDSn(1) | aiComponent_TEXCOORDSn(2) | aiComponent_TEXCOORDSn(3) | aiComponent_BONEWEIGHTS | aiComponent_ANIMATIONS | aiComponent_TEXTURES | aiComponent_LIGHTS | aiComponent_CAMERAS | aiComponent_MATERIALS, }; importer.SetPropertyInteger(AI_CONFIG_PP_RVC_FLAGS, removeComponents[format]); static u32 preProcess[VERTEXTYPE_COUNT] = { // VERTEXTYPE_MINIMAL aiProcess_Triangulate | aiProcess_RemoveComponent | aiProcess_JoinIdenticalVertices | aiProcess_ImproveCacheLocality | aiProcess_OptimizeMeshes | aiProcess_FindInstances | aiProcess_FindInvalidData | aiProcess_RemoveRedundantMaterials | aiProcess_FindDegenerates | aiProcess_ValidateDataStructure, // VERTEXTYPE_SIMPLE aiProcess_CalcTangentSpace | aiProcess_GenNormals | aiProcess_Triangulate | aiProcess_RemoveComponent | aiProcess_JoinIdenticalVertices | aiProcess_ImproveCacheLocality | aiProcess_OptimizeMeshes | aiProcess_FindInstances | aiProcess_FindInvalidData | aiProcess_RemoveRedundantMaterials | aiProcess_FindDegenerates | aiProcess_ValidateDataStructure, // VERTEXTYPE_SPRITE aiProcess_Triangulate | aiProcess_RemoveComponent | aiProcess_JoinIdenticalVertices | aiProcess_ImproveCacheLocality | aiProcess_OptimizeMeshes | aiProcess_FindInstances | aiProcess_FindInvalidData | aiProcess_RemoveRedundantMaterials | aiProcess_FindDegenerates | aiProcess_ValidateDataStructure, }; const aiScene* scene = importer.ReadFile(argv[1], preProcess[format]); if ( scene == 0 ) { fprintf(stderr, "Couldn't load %s.\n", argv[1]); fprintf(stderr, importer.GetErrorString()); return 42; } RemoveExtension(argv[1]); for ( u32 i = 0 ; i < scene->mNumMeshes ; i++ ) { aiMesh* mesh = scene->mMeshes[i]; static char filename[4096]; if ( mesh->mName.length != 0 ) { sprintf(filename, "%s-%s.mesh", argv[1], mesh->mName.data); } else { sprintf(filename, "%s-%d.mesh", argv[1], i + 1); } printf("Exporting %d:\"%s\" to %s...\n", i + 1, mesh->mName.data, filename); ExportMesh(mesh, filename, format); } return 0; }
void MultiLightDemo::Initialize() { glEnable(GL_DEPTH_TEST); glClearColor(0.3f, 0.2f, 0.7f, 1.0f); program.AddShaderFile(ShaderType::Vertex, "Assets/Shaders/Vertex/multiLight.vert"); program.AddShaderFile(ShaderType::Fragment, "Assets/Shaders/Fragment/multiLight.frag"); program.Build(); program.AddUniformBlock({ "TransformBlock",{ { "TransformBlock.view",&camera->GetView()[0][0], sizeof(camera->GetView()) }, { "TransformBlock.projection",&camera->GetProjection()[0][0], sizeof(camera->GetProjection()) }, { "TransformBlock.eyePosition",&camera->GetPosition()[0], sizeof(camera->GetPosition()) }, } }); lights[0].position = glm::vec3(0.0f, 0.0f, -2.0f); lights[1].position = glm::vec3(-2.0f, -3.0f, -2.0f); lights[2].position = glm::vec3(4.0f, 7.0f, -2.0f); lights[0].color = glm::vec3(0.9f,0.5f,0.3f); lights[1].color = glm::vec3(0.2f,0.9f,0.2f); lights[2].color = glm::vec3(0.2f,0.4f,0.9f); program.AddUniform("lights[0].position", &lights[0].position[0], UniformType::VEC3); program.AddUniform("lights[0].color", &lights[0].color[0], UniformType::VEC3); program.AddUniform("lights[1].position", &lights[1].position[0], UniformType::VEC3); program.AddUniform("lights[1].color", &lights[1].color[0], UniformType::VEC3); program.AddUniform("lights[2].position", &lights[2].position[0], UniformType::VEC3); program.AddUniform("lights[2].color", &lights[2].color[0], UniformType::VEC3); input->addBinding(GLFW_KEY_LEFT, [this](InputInfo info) { camera->MoveLeft(); program.UpdateUniformBlock("TransformBlock"); }); input->addBinding(GLFW_KEY_RIGHT, [this](InputInfo info) { camera->MoveRight(); program.UpdateUniformBlock("TransformBlock"); }); input->addBinding(GLFW_KEY_UP, [this](InputInfo info) { camera->MoveForward(); program.UpdateUniformBlock("TransformBlock"); }); input->addBinding(GLFW_KEY_DOWN, [this](InputInfo info) { camera->MoveBack(); program.UpdateUniformBlock("TransformBlock"); }); //program.AddUniform("light[0].position", &lights[0].position[0], UniformType::VEC3); //program.AddUniform("light[0].color", &lights[0].color[0], UniformType::VEC3); //program.AddUniform("light[1].position", &lights[1].position[0], UniformType::VEC3); //program.AddUniform("light[1].color", &lights[1].color[0], UniformType::VEC3); //program.AddUniform("light[2].position", &lights[2].position[0], UniformType::VEC3); //program.AddUniform("light[2].color", &lights[2].color[0], UniformType::VEC3); using std::unique_ptr; monkey = unique_ptr<GameObject>(new GameObject()); monkey->GetTransform()->SetPosition({ 0.0f,0.0f,-5.0f }); monkey->Update(); Assimp::Importer importer; auto scene = importer.ReadFile("Assets/Models/Obj/monkey.obj", aiProcess_Triangulate); if (scene && scene->HasMeshes()) { mesh = unique_ptr<MeshComponent>(new MeshComponent(monkey.get())); mesh->Initialize(scene->mMeshes[0], program, { { "world", UniformType::MAT4, &monkey->GetWorld()[0][0] }, { "material.ambient", UniformType::VEC3, &mesh->GetMaterial().ambient[0] }, { "material.diffuse", UniformType::VEC3, &mesh->GetMaterial().diffuse[0] }, { "material.specular", UniformType::VEC4, &mesh->GetMaterial().specular[0] }, }); monkey->AddComponent(mesh.get()); } mesh->GetMaterial().ambient = glm::vec3(0.6f, 0.7f, 0.1f); mesh->GetMaterial().diffuse = glm::vec3(0.5f, 0.2f, 0.8f); mesh->GetMaterial().specular = glm::vec4(0.3f, 0.2f, 0.2f, 10.0f); importer.FreeScene(); }
virtual bool importerTest() { Assimp::Importer importer; const aiScene *scene = importer.ReadFile( ASSIMP_TEST_MODELS_DIR "/STL/Spider_ascii.stl", aiProcess_ValidateDataStructure ); return nullptr != scene; }
std::shared_ptr<gameplay::Model> OBJWriter::readModel(const boost::filesystem::path& path, const std::shared_ptr<gameplay::ShaderProgram>& shaderProgram, const glm::vec3& ambientColor) const { Assimp::Importer importer; const aiScene* scene = importer.ReadFile((m_basePath / path).string(), aiProcess_JoinIdenticalVertices | aiProcess_Triangulate | aiProcess_ValidateDataStructure | aiProcess_FlipUVs); BOOST_ASSERT(scene != nullptr); auto renderModel = std::make_shared<gameplay::Model>(); for( unsigned int mi = 0; mi < scene->mNumMeshes; ++mi ) { BOOST_LOG_TRIVIAL(info) << "Converting mesh " << mi + 1 << " of " << scene->mNumMeshes << " from " << m_basePath / path; const aiMesh* mesh = scene->mMeshes[mi]; if( mesh->mPrimitiveTypes != aiPrimitiveType_TRIANGLE ) BOOST_THROW_EXCEPTION(std::runtime_error("Mesh does not consist of triangles only")); if( !mesh->HasTextureCoords(0) ) BOOST_THROW_EXCEPTION(std::runtime_error("Mesh does not have UV coordinates")); if( mesh->mNumUVComponents[0] != 2 ) BOOST_THROW_EXCEPTION(std::runtime_error("Mesh does not have a 2D UV channel")); if( !mesh->HasFaces() ) BOOST_THROW_EXCEPTION(std::runtime_error("Mesh does not have faces")); if( !mesh->HasPositions() ) BOOST_THROW_EXCEPTION(std::runtime_error("Mesh does not have positions")); std::shared_ptr<gameplay::Mesh> renderMesh; if( mesh->HasNormals() ) { std::vector<VDataNormal> vbuf(mesh->mNumVertices); for( unsigned int i = 0; i < mesh->mNumVertices; ++i ) { vbuf[i].position = glm::vec3{mesh->mVertices[i].x, mesh->mVertices[i].y, mesh->mVertices[i].z} * static_cast<float>(SectorSize); vbuf[i].normal = glm::vec3{mesh->mNormals[i].x, mesh->mNormals[i].y, mesh->mNormals[i].z}; vbuf[i].uv = glm::vec2{mesh->mTextureCoords[0][i].x, mesh->mTextureCoords[0][i].y}; if( mesh->HasVertexColors(0) ) vbuf[i].color = glm::vec4(mesh->mColors[0][i].r, mesh->mColors[0][i].g, mesh->mColors[0][i].b, mesh->mColors[0][i].a); else vbuf[i].color = glm::vec4(ambientColor, 1); } renderMesh = std::make_shared<gameplay::Mesh>(VDataNormal::getFormat(), mesh->mNumVertices, false); renderMesh->rebuild(reinterpret_cast<const float*>(vbuf.data()), mesh->mNumVertices); } else { std::vector<VData> vbuf(mesh->mNumVertices); for( unsigned int i = 0; i < mesh->mNumVertices; ++i ) { vbuf[i].position = glm::vec3{mesh->mVertices[i].x, mesh->mVertices[i].y, mesh->mVertices[i].z} * static_cast<float>(SectorSize); vbuf[i].uv = glm::vec2{mesh->mTextureCoords[0][i].x, mesh->mTextureCoords[0][i].y}; if( mesh->HasVertexColors(0) ) vbuf[i].color = glm::vec4(mesh->mColors[0][i].r, mesh->mColors[0][i].g, mesh->mColors[0][i].b, mesh->mColors[0][i].a); else vbuf[i].color = glm::vec4(ambientColor, 1); } renderMesh = std::make_shared<gameplay::Mesh>(VData::getFormat(), mesh->mNumVertices, false); renderMesh->rebuild(reinterpret_cast<const float*>(vbuf.data()), mesh->mNumVertices); } std::vector<uint32_t> faces; for( const aiFace& face : gsl::span<aiFace>(mesh->mFaces, mesh->mNumFaces) ) { BOOST_ASSERT(face.mNumIndices == 3); faces.push_back(face.mIndices[0]); faces.push_back(face.mIndices[1]); faces.push_back(face.mIndices[2]); } auto part = renderMesh->addPart(gameplay::Mesh::TRIANGLES, gameplay::Mesh::INDEX32, mesh->mNumFaces * 3, false); part->setIndexData(faces.data(), 0, faces.size()); const aiMaterial* material = scene->mMaterials[mesh->mMaterialIndex]; aiString textureName; if( material->GetTexture(aiTextureType_DIFFUSE, 0, &textureName) != aiReturn_SUCCESS ) BOOST_THROW_EXCEPTION(std::runtime_error("Failed to get diffuse texture path from mesh")); part->setMaterial(readMaterial(textureName.C_Str(), shaderProgram)); renderModel->addMesh(renderMesh); } return renderModel; }
void ObjLoader::LoadAssimp( const std::string &FileName ) { auto t0 = std::chrono::high_resolution_clock::now(); Assimp::Importer Importer; const aiScene *scene = Importer.ReadFile( FileName, aiProcessPreset_TargetRealtime_Quality ); if( !scene ) { std::cout << "ASSIMP cos poszlo nie tak\n"; std::cout << "ASSIMP ERROR: " << Importer.GetErrorString() << std::endl; } //w petli przez wszystkie meshe const aiMesh * mesh = scene->mMeshes[0]; for( uint t = 0; t < mesh->mNumFaces ; t++ ) { const aiFace *face = &mesh->mFaces[ t ] ; mGpuIndices.push_back( face->mIndices[ 0 ] ); mGpuIndices.push_back( face->mIndices[ 1 ] ); mGpuIndices.push_back( face->mIndices[ 2 ] ); } // verteksy if( mesh->HasPositions() ) { mVertex.resize( mesh->mNumVertices ); memcpy( &mVertex[0], mesh->mVertices, 3*4* mesh->mNumVertices ); } if( mesh->HasNormals() ) { mNormals.resize( mesh->mNumVertices ); memcpy( &mNormals[0], mesh->mNormals, 3*4* mesh->mNumVertices ); } if( mesh->HasTextureCoords(0) ) { for( uint k = 0; k < mesh->mNumVertices; ++k ) { glm::vec2 tmp; tmp.x = mesh->mTextureCoords[0][k].x; tmp.y = mesh->mTextureCoords[0][k].y; mTexcoords.push_back( tmp ); } } mGpuBuffer.resize( mesh->mNumVertices*8); for( uint i = 0; i < mesh->mNumVertices; ++i ) { mGpuBuffer[ i*8 ] = mVertex[ i ].x; mGpuBuffer[ i*8 +1 ] = mVertex[ i ].y; mGpuBuffer[ i*8 +2] = mVertex[ i ].z; mGpuBuffer[ i*8 +3] = mNormals[ i ].x; mGpuBuffer[ i*8 +4] = mNormals[ i ].y; mGpuBuffer[ i*8 +5] = mNormals[ i ].z; if( mesh->HasTextureCoords(0) ) { mGpuBuffer[i * 8 + 6] = mTexcoords[i].s; mGpuBuffer[i * 8 + 7] = mTexcoords[i].t; } } auto t1 = std::chrono::high_resolution_clock::now(); std::chrono::milliseconds total_ms = std::chrono::duration_cast<std::chrono::milliseconds>(t1 - t0); std::cout << "Time: " << total_ms.count() << " ms " << std::endl; Surface *pSurface = new Surface(); VertexBufferManager &VBOMan = VertexBufferManager::GetSingleton(); IndexBuffer *pIndex = VBOMan.CreateIndexBuffer(); pIndex->SetIndexData( mGpuIndices ); pIndex->Prepare(); VertexDeclaration *pDecl = VBOMan.GetVertexDeclaration( "Default" ); VertexSettings( PT_TRIANGLE, UT_STATIC_DRAW, pIndex, pDecl ); VertexBuffer *pVertex = VBOMan.CreateVertexBuffer( VertexSettings( PT_TRIANGLE, UT_STATIC_DRAW, pIndex, pDecl ) ); pVertex->SetVertexData( mGpuBuffer ); pVertex->Prepare(); pSurface->SetVertexBuffer( pVertex ); mSurfaces.push_back( pSurface ); }
// Load a model from file using the ASSIMP model loader and generate all resources required to render the model void loadModel(std::string filename) { // Load the model from file using ASSIMP const aiScene* scene; Assimp::Importer Importer; // Flags for loading the mesh static const int assimpFlags = aiProcess_FlipWindingOrder | aiProcess_Triangulate | aiProcess_PreTransformVertices; #if defined(__ANDROID__) // Meshes are stored inside the apk on Android (compressed) // So they need to be loaded via the asset manager AAsset* asset = AAssetManager_open(androidApp->activity->assetManager, filename.c_str(), AASSET_MODE_STREAMING); assert(asset); size_t size = AAsset_getLength(asset); assert(size > 0); void *meshData = malloc(size); AAsset_read(asset, meshData, size); AAsset_close(asset); scene = Importer.ReadFileFromMemory(meshData, size, assimpFlags); free(meshData); #else scene = Importer.ReadFile(filename.c_str(), assimpFlags); #endif // Generate vertex buffer from ASSIMP scene data float scale = 1.0f; std::vector<Vertex> vertexBuffer; // Iterate through all meshes in the file and extract the vertex components for (uint32_t m = 0; m < scene->mNumMeshes; m++) { for (uint32_t v = 0; v < scene->mMeshes[m]->mNumVertices; v++) { Vertex vertex; // Use glm make_* functions to convert ASSIMP vectors to glm vectors vertex.pos = glm::make_vec3(&scene->mMeshes[m]->mVertices[v].x) * scale; vertex.normal = glm::make_vec3(&scene->mMeshes[m]->mNormals[v].x); // Texture coordinates and colors may have multiple channels, we only use the first [0] one vertex.uv = glm::make_vec2(&scene->mMeshes[m]->mTextureCoords[0][v].x); // Mesh may not have vertex colors vertex.color = (scene->mMeshes[m]->HasVertexColors(0)) ? glm::make_vec3(&scene->mMeshes[m]->mColors[0][v].r) : glm::vec3(1.0f); // Vulkan uses a right-handed NDC (contrary to OpenGL), so simply flip Y-Axis vertex.pos.y *= -1.0f; vertexBuffer.push_back(vertex); } } size_t vertexBufferSize = vertexBuffer.size() * sizeof(Vertex); // Generate index buffer from ASSIMP scene data std::vector<uint32_t> indexBuffer; for (uint32_t m = 0; m < scene->mNumMeshes; m++) { uint32_t indexBase = static_cast<uint32_t>(indexBuffer.size()); for (uint32_t f = 0; f < scene->mMeshes[m]->mNumFaces; f++) { // We assume that all faces are triangulated for (uint32_t i = 0; i < 3; i++) { indexBuffer.push_back(scene->mMeshes[m]->mFaces[f].mIndices[i] + indexBase); } } } size_t indexBufferSize = indexBuffer.size() * sizeof(uint32_t); model.indices.count = static_cast<uint32_t>(indexBuffer.size()); // Static mesh should always be device local bool useStaging = true; if (useStaging) { struct { VkBuffer buffer; VkDeviceMemory memory; } vertexStaging, indexStaging; // Create staging buffers // Vertex data VK_CHECK_RESULT(vulkanDevice->createBuffer( VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, vertexBufferSize, &vertexStaging.buffer, &vertexStaging.memory, vertexBuffer.data())); // Index data VK_CHECK_RESULT(vulkanDevice->createBuffer( VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, indexBufferSize, &indexStaging.buffer, &indexStaging.memory, indexBuffer.data())); // Create device local buffers // Vertex buffer VK_CHECK_RESULT(vulkanDevice->createBuffer( VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, vertexBufferSize, &model.vertices.buffer, &model.vertices.memory)); // Index buffer VK_CHECK_RESULT(vulkanDevice->createBuffer( VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, indexBufferSize, &model.indices.buffer, &model.indices.memory)); // Copy from staging buffers VkCommandBuffer copyCmd = VulkanExampleBase::createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true); VkBufferCopy copyRegion = {}; copyRegion.size = vertexBufferSize; vkCmdCopyBuffer( copyCmd, vertexStaging.buffer, model.vertices.buffer, 1, ©Region); copyRegion.size = indexBufferSize; vkCmdCopyBuffer( copyCmd, indexStaging.buffer, model.indices.buffer, 1, ©Region); VulkanExampleBase::flushCommandBuffer(copyCmd, queue, true); vkDestroyBuffer(device, vertexStaging.buffer, nullptr); vkFreeMemory(device, vertexStaging.memory, nullptr); vkDestroyBuffer(device, indexStaging.buffer, nullptr); vkFreeMemory(device, indexStaging.memory, nullptr); } else { // Vertex buffer VK_CHECK_RESULT(vulkanDevice->createBuffer( VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, vertexBufferSize, &model.vertices.buffer, &model.vertices.memory, vertexBuffer.data())); // Index buffer VK_CHECK_RESULT(vulkanDevice->createBuffer( VK_BUFFER_USAGE_INDEX_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, indexBufferSize, &model.indices.buffer, &model.indices.memory, indexBuffer.data())); } }
BumpedTexturedMesh * MeshLoader::LoadBumpedMesh(const std::string &path, const string &texturePath, const string &normalPath) { // Load the file Assimp::Importer importer; const aiScene* scene = importer.ReadFile( path, aiProcess_Triangulate | aiProcess_JoinIdenticalVertices | aiProcess_OptimizeGraph | aiProcess_OptimizeMeshes | aiProcess_RemoveRedundantMaterials | aiProcess_GenSmoothNormals | aiProcess_CalcTangentSpace ); if (scene->HasMeshes()) { // Get the model mesh aiMesh &mesh = *scene->mMeshes[0]; if (!mesh.HasPositions() || !mesh.HasFaces()) return NULL; // Initialize the model vector<glm::vec3> vertices; vector<GLuint> indices; vector<glm::vec3> normals; vector<glm::vec2> uvs; vector<glm::vec4> tangents; // Get mesh properties for (unsigned int i=0; i<mesh.mNumVertices; ++i) { // Get vertices vertices.push_back(glm::vec3(mesh.mVertices[i].x, mesh.mVertices[i].y, mesh.mVertices[i].z)); //vertices[vertices.size()-1] /= 38; // Get normals normals.push_back(glm::vec3(mesh.mNormals[i].x, mesh.mNormals[i].y, mesh.mNormals[i].z)); // Get UVs uvs.push_back(glm::vec2(mesh.mTextureCoords[0][i].x, mesh.mTextureCoords[0][i].y)); if (mesh.HasTangentsAndBitangents()) { const aiVector3D tangent = mesh.mTangents[i]; const aiVector3D bitangent = mesh.mBitangents[i]; // put the three vectors into my vec3 struct format for doing maths vec3 t (tangent.x, tangent.y, tangent.z); vec3 b (bitangent.x, bitangent.y, bitangent.z); // orthogonalise and normalise the tangent so we can use it in something // approximating a T,N,B inverse matrix vec3 t_i = t - normals[i] * dot (normals[i], t); //5std::cout << i << ": " << t_i.x << " " << t_i.y << " " << t_i.z << std::endl; if(!isnan(t_i.x)) t_i = normalize(t_i); // get determinant of T,B,N 3x3 matrix by dot*cross method float det = (dot (cross (normals[i], t), b)); if (det < 0.0f) { det = -1.0f; } else { det = 1.0f; } tangents.push_back(vec4(t_i, det)); } } // Normalize vertices normalizeVertices(vertices); // Get indices for (unsigned int i=0; i<mesh.mNumFaces; ++i) { aiFace face = mesh.mFaces[i]; indices.push_back(face.mIndices[0]); indices.push_back(face.mIndices[1]); indices.push_back(face.mIndices[2]); } BumpedTexturedMesh * modelMesh = new BumpedTexturedMesh(vertices, indices, normals, uvs, tangents); modelMesh->SetTexture(loadTexture(texturePath)); modelMesh->SetNormalTexture(loadTexture(normalPath)); return modelMesh; } return NULL; }
bool Mesh::Load ( const char* filePath ) { Assimp::Importer importer; const aiScene* scene = importer.ReadFile ( filePath, aiProcess_Triangulate | aiProcess_JoinIdenticalVertices | aiProcess_FlipWindingOrder | aiProcess_CalcTangentSpace ); if ( !scene || scene->mFlags == AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode ) { return false; } for ( unsigned int i = 0; i < scene->mNumMeshes; ++i ) { SubMesh* submesh = new SubMesh; const aiMesh* aimesh = scene->mMeshes[i]; ///// VERTEX BUFFER ///// submesh->m_vertexCount = aimesh->mNumVertices; submesh->m_verts = malloc( sizeof( Vertex ) * submesh->m_vertexCount ); Vertex* vertBuffer = ( Vertex* )submesh->m_verts; for ( unsigned int j = 0; j < aimesh->mNumVertices; ++j ) { Vertex v; v.pos[0] = aimesh->mVertices[j].x; v.pos[1] = aimesh->mVertices[j].y; v.pos[2] = aimesh->mVertices[j].z; if ( aimesh->mNormals ) { v.norm[0] = aimesh->mNormals[j].x; v.norm[1] = aimesh->mNormals[j].y; v.norm[2] = aimesh->mNormals[j].z; } else { v.norm[0] = 0; v.norm[1] = 0; v.norm[2] = 0; } if ( aimesh->mTextureCoords[0] ) { v.uv[0] = aimesh->mTextureCoords[0][j].x; v.uv[1] = aimesh->mTextureCoords[0][j].y; } else { v.uv[0] = 0; v.uv[1] = 0; } if ( aimesh->mTangents ) { v.tanget[0] = aimesh->mTangents[j].x; v.tanget[1] = aimesh->mTangents[j].y; v.tanget[2] = aimesh->mTangents[j].z; } else { v.tanget[0] = 0; v.tanget[1] = 0; v.tanget[2] = 0; } if ( aimesh->mBitangents ) { v.bitangent[0] = aimesh->mBitangents[j].x; v.bitangent[1] = aimesh->mBitangents[j].y; v.bitangent[2] = aimesh->mBitangents[j].z; } else { v.bitangent[0] = 0; v.bitangent[1] = 0; v.bitangent[2] = 0; } vertBuffer[j] = v; } submesh->m_vertexHandle = GraphicsManager::Instance().CreateVertexBuffer( submesh->m_verts, sizeof( Vertex ) * submesh->m_vertexCount ); ///// INDEX BUFFER ///// submesh->m_indexCount = aimesh->mNumFaces * 3; // 3 verts per face submesh->m_indices = ( uint16_t* )malloc( submesh->m_indexCount * sizeof( uint16_t ) ); uint16_t idx = 0; for ( unsigned int j = 0; j < aimesh->mNumFaces; ++j ) { const aiFace& face = aimesh->mFaces[j]; if ( face.mNumIndices != 3 ) return false; for ( uint8_t k = 0; k < 3; ++k ) { dDAssert( idx < aimesh->mNumFaces * 3 ); submesh->m_indices[idx++] = face.mIndices[k]; } } submesh->m_indexBufferHandle = GraphicsManager::Instance().CreateIndexBuffer( submesh->m_indices, ( uint16_t )sizeof( uint16_t ) * submesh->m_indexCount ); //// DECLARATION //// submesh->m_decl = *VertexDeclaration::GetDefaultDeclaration(); m_subMeshes.push_back ( submesh ); } return true; }
TexturedIndexedMesh * MeshLoader::LoadMesh(const std::string &path, const string &texturePath) { // Load the file Assimp::Importer importer; const aiScene* scene = importer.ReadFile( path, aiProcess_Triangulate | aiProcess_JoinIdenticalVertices | aiProcess_OptimizeGraph | aiProcess_OptimizeMeshes | aiProcess_RemoveRedundantMaterials | aiProcess_GenSmoothNormals ); if (scene->HasMeshes()) { // Get the model mesh aiMesh &mesh = *scene->mMeshes[0]; if (!mesh.HasPositions() || !mesh.HasFaces()) return NULL; // Initialize the model vector<glm::vec3> vertices; vector<GLuint> indices; vector<glm::vec3> normals; vector<glm::vec2> uvs; // Get mesh properties for (unsigned int i=0; i<mesh.mNumVertices; ++i) { // Get vertices vertices.push_back(glm::vec3(mesh.mVertices[i].x, mesh.mVertices[i].y, mesh.mVertices[i].z)); //vertices[vertices.size()-1] /= 38; // Get normals normals.push_back(glm::vec3(mesh.mNormals[i].x, mesh.mNormals[i].y, mesh.mNormals[i].z)); // Get UVs uvs.push_back(glm::vec2(mesh.mTextureCoords[0][i].x, mesh.mTextureCoords[0][i].y)); } // Normalize vertices normalizeVertices(vertices); // Get indices for (unsigned int i=0; i<mesh.mNumFaces; ++i) { aiFace face = mesh.mFaces[i]; indices.push_back(face.mIndices[0]); indices.push_back(face.mIndices[1]); indices.push_back(face.mIndices[2]); } TexturedIndexedMesh * modelMesh = new TexturedIndexedMesh(vertices, indices, normals, uvs); modelMesh->SetTexture(loadTexture(texturePath)); return modelMesh; } return NULL; }
/** load the mesh from file * \param model_name is the model file name */ bool CLoadedObject::loadMesh( std::string model_name ) { //m_model_name = model_name; Assimp::Importer imp; const aiScene * scn = imp.ReadFile(model_name.c_str(), aiProcess_Triangulate | aiProcess_GenSmoothNormals | aiProcess_GenUVCoords); if(!scn) { std::cerr << imp.GetErrorString() << std::endl; return false; } if(scn->mNumMeshes < 1) { std::cerr << "no meshes found in scene " << model_name << std::endl; return false; } std::cout << "loaded " << scn->mNumMeshes << " meshes" << std::endl; // merge all sub-meshes to one big mesh m_nVertices = 0; for(unsigned m = 0; m < scn->mNumMeshes; ++m) m_nVertices += scn->mMeshes[m]->mNumVertices; float * vertices = new float[7 * m_nVertices]; // 7 floats per vertex (xyz + RGBA) float * cur_vert = vertices; // all vertices first float * cur_col = vertices + 3 * m_nVertices; // than all colors for(unsigned m = 0; m < scn->mNumMeshes; ++m) { aiMesh * mesh = scn->mMeshes[m]; memcpy(cur_vert, mesh->mVertices, mesh->mNumVertices * sizeof(float) * 3); aiMaterial * material = scn->mMaterials[mesh->mMaterialIndex]; // copy mesh material color to all mesh vertices for(unsigned v = 0; v < mesh->mNumVertices; ++v) { aiColor4D color; material->Get<aiColor4D>(AI_MATKEY_COLOR_DIFFUSE, color); *cur_col++ = color.r; *cur_col++ = color.g; *cur_col++ = color.b; *cur_col++ = color.a; } cur_vert += mesh->mNumVertices * 3; } // create vertex buffer glBindBuffer(GL_ARRAY_BUFFER, m_vertexBufferObject); //glBufferData( GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); glBufferData(GL_ARRAY_BUFFER, m_nVertices * sizeof(float) * 7, vertices, GL_STATIC_DRAW); glBindBuffer(GL_ARRAY_BUFFER, 0); delete [] vertices; // create VAO glBindVertexArray( m_vertexArrayObject ); glBindBuffer(GL_ARRAY_BUFFER, m_vertexBufferObject); glEnableVertexAttribArray(m_posLoc); glEnableVertexAttribArray(m_colLoc); glVertexAttribPointer(m_posLoc, 3, GL_FLOAT, GL_FALSE, 0, (void*)0); glVertexAttribPointer(m_colLoc, 4, GL_FLOAT, GL_FALSE, 0, (void*)(3 * sizeof(float) * m_nVertices)); glBindVertexArray( 0 ); return true; }
allocated_memory_handle LoadModel(const char* path, model_definition* outModelDefinition) { Assimp::Importer importer; ZeroMemory(outModelDefinition, sizeof(*outModelDefinition)); const aiScene* scene = importer.ReadFile(path, aiProcess_CalcTangentSpace | aiProcess_Triangulate | aiProcess_JoinIdenticalVertices | aiProcess_SortByPType | aiProcess_ImproveCacheLocality | aiProcess_OptimizeMeshes | aiProcess_OptimizeGraph | aiProcess_ValidateDataStructure | aiProcess_ConvertToLeftHanded | aiProcess_LimitBoneWeights | aiProcess_CalcTangentSpace | aiProcess_GenSmoothNormals ); if (!scene) { outModelDefinition->loadResult = IMPORT_ERROR; outModelDefinition->loadErrorMessage = importer.GetErrorString(); return nullptr; } ModelMemory *modelData = new ModelMemory(); auto& imported = *modelData; // submeshes uint32_t baseVertex = 0; uint32_t startIndex = 0; for (auto i = 0u; i< scene->mNumMeshes; ++i) { auto mesh = scene->mMeshes[i]; auto submesh = submesh_definition(); sprintf_s(submesh.name, mesh->mName.C_Str()); submesh.baseVertex = baseVertex; submesh.indexCount = mesh->mNumFaces * 3; submesh.startIndex = startIndex; submesh.materialId = mesh->mMaterialIndex; imported.submeshes.push_back(submesh); startIndex += mesh->mNumFaces * 3; baseVertex += mesh->mNumVertices; } // materials for (auto i = 0u; i < scene->mNumMaterials; ++i) { auto material = scene->mMaterials[i]; material_definition mat_def = {}; aiString str; if (material->GetTextureCount(aiTextureType_DIFFUSE)) { material->GetTexture(aiTextureType_DIFFUSE, 0, &str); sprintf_s(mat_def.diffuseTexture, "%s", str.C_Str()); } if (material->GetTextureCount(aiTextureType_AMBIENT)) { material->GetTexture(aiTextureType_AMBIENT, 0, &str); sprintf_s(mat_def.metallicnessTexture, "%s", str.C_Str()); } if (material->GetTextureCount(aiTextureType_HEIGHT)) { material->GetTexture(aiTextureType_HEIGHT, 0, &str); sprintf_s(mat_def.normalmapTexture, "%s", str.C_Str()); } if (material->GetTextureCount(aiTextureType_SHININESS)) { material->GetTexture(aiTextureType_SHININESS, 0, &str); sprintf_s(mat_def.roughnessTexture, "%s", str.C_Str()); } if (material->GetTextureCount(aiTextureType_OPACITY)) { material->GetTexture(aiTextureType_OPACITY, 0, &str); sprintf_s(mat_def.alphaTexture, "%s", str.C_Str()); } } // bones, collect phase std::unordered_map<u64, aiNode*> nodeByBoneNameHash; for (auto i = 0u; i < scene->mNumMeshes; ++i) { auto mesh = scene->mMeshes[i]; if (mesh->HasBones()) { auto B = mesh->mNumBones; for (auto b = 0u; b < B;++b) { auto bone = mesh->mBones[b]; auto name_hash = Hash::MurmurHash2_64(bone->mName.C_Str(), bone->mName.length, 0); nodeByBoneNameHash[name_hash] = scene->mRootNode->FindNode(bone->mName.C_Str()); } } } // animations, channels std::unordered_map<u64, u32> channelIndexByNameHash; u32 positionsKeys = 0; u32 rotationKeys = 0; using namespace DirectX; // if any animations, collect channels if (scene->mNumAnimations) { auto sceneAnimation = scene->mAnimations[0]; for (auto c = 0u; c < sceneAnimation->mNumChannels; ++c) { auto channel = sceneAnimation->mChannels[c]; auto nameHash = Hash::MurmurHash2_64(channel->mNodeName.C_Str(), channel->mNodeName.length, 0); channelIndexByNameHash[nameHash] = c; /*animation_channel_t anim_channel = {}; anim_channel.positions_offset = (u32)imported.animationPositions.size(); anim_channel.positions_num = channel->mNumPositionKeys; anim_channel.rotations_offset = (u32)imported.animationRotations.size(); anim_channel.rotations_num = channel->mNumRotationKeys;*/ assert(channel->mNodeName.C_Str()); /*imported.animationChannels.push_back(anim_channel); for (auto k = 0u; k < channel->mNumPositionKeys; ++k) { auto v = channel->mPositionKeys[k].mValue; position_key_t key; key.value = XMFLOAT3A((float)v.x, (float)v.y, (float)v.z); key.time = (float)channel->mPositionKeys[k].mTime; imported.animationPositions.push_back(key); } for (auto k = 0u; k < channel->mNumRotationKeys; ++k) { auto v = channel->mRotationKeys[k].mValue; rotation_key_t key; key.value = XMFLOAT4((float)v.x, (float)v.y, (float)v.z, (float)v.w); key.time = (float)channel->mRotationKeys[k].mTime; imported.animationRotations.push_back(key); } for (auto k = 0u; k < channel->mNumScalingKeys; ++k) { auto v = channel->mScalingKeys[k].mValue; assert(v.x >= 0.98f && v.y >= 0.98f && v.z >= 0.98f); }*/ } // verify channels for (auto a = 1u; a < scene->mNumAnimations; ++a) { auto sceneAnimation = scene->mAnimations[a]; for (auto c = 0u; c < sceneAnimation->mNumChannels; ++c) { auto channel = sceneAnimation->mChannels[c]; auto nameHash = Hash::MurmurHash2_64(channel->mNodeName.C_Str(), channel->mNodeName.length, 0); auto entry = channelIndexByNameHash.find(nameHash); assert(entry != channelIndexByNameHash.end() && entry->second == c); } } } auto channelsCounter = 0; for (auto i = 0u; i < scene->mNumAnimations; ++i) { auto sceneAnimation = scene->mAnimations[i]; animation_t animation = {}; sprintf_s(animation.name, "%s", sceneAnimation->mName.C_Str()); animation.name_hash = Hash::MurmurHash2_64(sceneAnimation->mName.C_Str(), sceneAnimation->mName.length, 0); animation.duration = (float)sceneAnimation->mDuration; animation.ticks_per_second = sceneAnimation->mTicksPerSecond != 0 ? (float)sceneAnimation->mTicksPerSecond : 25.f; animation.channels_offset = channelsCounter; animation.channels_num = sceneAnimation->mNumChannels; channelsCounter += animation.channels_num; auto position_keys_num = (u32)imported.animationPositions.size(); auto rotation_keys_num = (u32)imported.animationRotations.size(); for (auto c = 0u; c < sceneAnimation->mNumChannels; ++c) { auto channel = sceneAnimation->mChannels[c]; animation_channel_t anim_channel = {}; anim_channel.positions_offset = (u32)imported.animationPositions.size(); anim_channel.positions_num = channel->mNumPositionKeys; anim_channel.rotations_offset = (u32)imported.animationRotations.size(); anim_channel.rotations_num = channel->mNumRotationKeys; assert(channel->mNodeName.C_Str()); imported.animationChannels.push_back(anim_channel); for (auto k = 0u; k < channel->mNumPositionKeys; ++k) { auto v = channel->mPositionKeys[k].mValue; position_key_t key; key.value = XMFLOAT3A((float)v.x, (float)v.y, (float)v.z); key.time = (float)channel->mPositionKeys[k].mTime; imported.animationPositions.push_back(key); } for (auto k = 0u; k < channel->mNumRotationKeys; ++k) { auto v = channel->mRotationKeys[k].mValue; rotation_key_t key; key.value = XMFLOAT4((float)v.x, (float)v.y, (float)v.z, (float)v.w); key.time = (float)channel->mRotationKeys[k].mTime; imported.animationRotations.push_back(key); } for (auto k = 0u; k < channel->mNumScalingKeys; ++k) { auto v = channel->mScalingKeys[k].mValue; assert(v.x >= 0.98f && v.y >= 0.98f && v.z >= 0.98f); } } animation.position_keys_num = (u32)imported.animationPositions.size() - position_keys_num; animation.rotation_keys_num = (u32)imported.animationRotations.size() - rotation_keys_num; imported.animations.push_back(animation); } // nodes, skeleton hierarchy auto startNode = scene->mRootNode; auto currentNode = scene->mRootNode; using namespace DirectX; std::unordered_map<u64, u32> nodeIndexBoneNameHash; auto make_node = [&](aiNode* inNode, u32 parent_index) { animation_node_t node = {}; node.parent_index = parent_index; sprintf_s(node.name, "%s", inNode->mName.C_Str()); auto localTransform = XMFLOAT4X4(&inNode->mTransformation.a1); XMStoreFloat4x4(&node.local_transform, XMMatrixTranspose(XMLoadFloat4x4(&localTransform))); auto nameHash = Hash::MurmurHash2_64(inNode->mName.C_Str(), inNode->mName.length, 0); node.name_hash = nameHash; auto findResult = channelIndexByNameHash.find(nameHash); node.channel_index = findResult != channelIndexByNameHash.end() ? findResult->second : NULL_INDEX; return node; }; std::queue<decltype(scene->mRootNode)> nodesQueue; nodesQueue.push(scene->mRootNode); u32 parent_index = NULL_INDEX; imported.animationNodes.push_back(make_node(nodesQueue.front(), parent_index)); nodeIndexBoneNameHash[imported.animationNodes.back().name_hash] = (u32)imported.animationNodes.size() - 1; while (!nodesQueue.empty()) { auto currentNode = nodesQueue.front(); nodesQueue.pop(); ++parent_index; for (auto c = 0u; c < currentNode->mNumChildren; ++c) { auto nodeChild = currentNode->mChildren[c]; nodesQueue.push(nodeChild); imported.animationNodes.push_back(make_node(nodeChild, parent_index)); nodeIndexBoneNameHash[imported.animationNodes.back().name_hash] = (u32)imported.animationNodes.size() - 1; } } imported.indices.reserve(startIndex); imported.positions.resize(baseVertex); imported.texcoords.resize(baseVertex); imported.normals.resize(baseVertex); imported.tangents.resize(baseVertex); imported.bitangents.resize(baseVertex); imported.boneIndices.resize(baseVertex, XMUINT4(0, 0, 0, 0)); imported.boneWeights.resize(baseVertex, XMFLOAT4(0, 0, 0, 0)); using namespace DirectX; bool hasPositions = true; bool hasNormals = true; bool hasTangents = true; bool hasTextureCoords = true; u32 bone_offset = 0; for (auto i = 0u; i< scene->mNumMeshes; ++i) { auto mesh = scene->mMeshes[i]; if (i == 0) { hasPositions = mesh->HasPositions(); hasNormals = mesh->HasNormals(); hasTangents = mesh->HasTangentsAndBitangents(); hasTextureCoords = mesh->HasTextureCoords(0); } auto V = mesh->mNumVertices; auto vertex_offset = imported.submeshes[i].baseVertex; if (mesh->HasPositions() && hasPositions) { for (auto v = 0u; v < V; ++v) { imported.positions[vertex_offset + v] = XMFLOAT3(mesh->mVertices[v].x, mesh->mVertices[v].y, mesh->mVertices[v].z); } } if (mesh->HasNormals() && hasNormals) { for (auto v = 0u; v < V; ++v) { imported.normals[vertex_offset + v] = XMFLOAT3(mesh->mNormals[v].x, mesh->mNormals[v].y, mesh->mNormals[v].z); } } if (mesh->HasTangentsAndBitangents() && hasTangents) { for (auto v = 0u; v < V; ++v) { imported.tangents[vertex_offset + v] = XMFLOAT3(mesh->mTangents[v].x, mesh->mTangents[v].y, mesh->mTangents[v].z); imported.bitangents[vertex_offset + v] = XMFLOAT3(mesh->mBitangents[v].x, mesh->mBitangents[v].y, mesh->mBitangents[v].z); } } if (mesh->HasTextureCoords(0) && hasTextureCoords) { for (auto v = 0u; v < V; ++v) { imported.texcoords[vertex_offset + v] = XMFLOAT2(mesh->mTextureCoords[0][v].x, mesh->mTextureCoords[0][v].y); } } if (mesh->HasBones()) { /*imported.boneIndices.resize(V); imported.boneWeights.resize(V);*/ std::vector<int> vertexBonesCtr(V); vertexBonesCtr.resize(V); auto vertexOffset = imported.submeshes[i].baseVertex; auto B = mesh->mNumBones; for (auto b = 0u; b < B;++b) { auto bone = mesh->mBones[b]; bone_definition bone_def = {}; sprintf_s(bone_def.name, "%s", bone->mName.C_Str()); bone_def.name_hash = Hash::MurmurHash2_64(bone_def.name, strlen(bone_def.name), 0); auto offsetMatrix = XMFLOAT4X4(&bone->mOffsetMatrix.a1); XMStoreFloat4x4(&bone_def.offset_matrix, XMMatrixTranspose(XMLoadFloat4x4(&offsetMatrix))); assert(nodeIndexBoneNameHash.find(bone_def.name_hash) != nodeIndexBoneNameHash.end()); bone_def.node_index = nodeIndexBoneNameHash[bone_def.name_hash]; imported.bones.push_back(bone_def); auto W = bone->mNumWeights; for (auto w = 0u; w < W; ++w) { auto vertexId = bone->mWeights[w].mVertexId + vertex_offset; auto weight = bone->mWeights[w].mWeight; auto innerIndex = vertexBonesCtr[bone->mWeights[w].mVertexId]++; assert(innerIndex < 4); switch (innerIndex) { case 0: imported.boneIndices[vertexId].x = b + bone_offset; imported.boneWeights[vertexId].x = weight; break; case 1: imported.boneIndices[vertexId].y = b + bone_offset; imported.boneWeights[vertexId].y = weight; break; case 2: imported.boneIndices[vertexId].z = b + bone_offset; imported.boneWeights[vertexId].z = weight; break; case 3: imported.boneIndices[vertexId].w = b + bone_offset; imported.boneWeights[vertexId].w = weight; break; } } } bone_offset += B; } auto F = mesh->mNumFaces; for (auto f = 0u; f < F; ++f) { for (auto k = 0u; k<mesh->mFaces[f].mNumIndices; ++k) { imported.indices.push_back(mesh->mFaces[f].mIndices[k]); assert(mesh->mFaces[f].mNumIndices == 3); } } } XMVECTOR vmin, vmax; vmin = XMLoadFloat3(imported.positions.data() + 0); vmax = vmin; for (auto i = 0u; i<imported.positions.size(); ++i) { vmin = XMVectorMin(vmin, XMLoadFloat3(imported.positions.data() + i)); vmax = XMVectorMax(vmax, XMLoadFloat3(imported.positions.data() + i)); } outModelDefinition->verticesNum = baseVertex; outModelDefinition->indicesNum = startIndex; outModelDefinition->trianglesNum = startIndex / 3; outModelDefinition->submeshesNum = (uint32_t)imported.submeshes.size(); outModelDefinition->submeshes = imported.submeshes.data(); outModelDefinition->indices = imported.indices.data(); outModelDefinition->positions = imported.positions.data(); outModelDefinition->normals = imported.normals.data(); outModelDefinition->tangents = imported.tangents.data(); outModelDefinition->bitangents = imported.bitangents.data(); outModelDefinition->texcoords = imported.texcoords.data(); outModelDefinition->boneIndices = imported.boneIndices.data(); outModelDefinition->boneWeights = imported.boneWeights.data(); outModelDefinition->bonesNum = (u32)imported.bones.size(); outModelDefinition->bones = imported.bones.data(); outModelDefinition->materialsNum = (u32)imported.materials.size(); outModelDefinition->materials = imported.materials.data(); outModelDefinition->animationNodes = imported.animationNodes.data(); outModelDefinition->animationNodesNum = (u32)imported.animationNodes.size(); outModelDefinition->animations = imported.animations.data(); outModelDefinition->animationsNum = (u32)imported.animations.size(); outModelDefinition->animationChannels = imported.animationChannels.data(); outModelDefinition->animationPositionKeys = imported.animationPositions.data(); outModelDefinition->animationRotationKeys = imported.animationRotations.data(); XMStoreFloat3(&outModelDefinition->boundingBoxMin, vmin); XMStoreFloat3(&outModelDefinition->boundingBoxMax, vmax); return modelData; }
bool loadObj(const char *filename, Vertex* &obj, int &vertexCount) { Assimp::Importer importer; bool hasColor = false; if(obj) { std::cerr << "[F] loadObj function used incorrectly." << std::endl; return false; } //load the file and make sure all polygons are triangles const aiScene *scene = importer.ReadFile(filename,aiProcess_Triangulate | aiProcess_GenNormals); if(!scene) return false; //get vertices from assimp aiVector3D *vertices = (*scene->mMeshes)->mVertices; //get normals from assimp aiVector3D *vertexNormals = (*scene->mMeshes)->mNormals; //get color information from assimp if exists aiColor4t<float> *colors = NULL; if((*scene->mMeshes)->HasVertexColors(0)) { hasColor = true; colors = (*scene->mMeshes)->mColors[0]; } //get vertex count from assimp vertexCount = (*scene->mMeshes)->mNumVertices; //allocate memory for obj obj = new Vertex[vertexCount]; //add vertex, normals, and UVs to mesh object for(int i=0;i<vertexCount;++i) { obj[i].position[0] = vertices[i].x; obj[i].position[1] = vertices[i].y; obj[i].position[2] = vertices[i].z; obj[i].normal[0] = vertexNormals[i].x; obj[i].normal[1] = vertexNormals[i].y; obj[i].normal[2] = vertexNormals[i].z; if(hasColor) { obj[i].color[0] = colors[i].r; obj[i].color[1] = colors[i].g; obj[i].color[2] = colors[i].b; } else { obj[i].color[0] = 0.0; obj[i].color[1] = 1.0; obj[i].color[2] = 1.0; } } return true; }
bool loadMesh_assimp( const char * path, std::vector<unsigned short> & out_indices, std::vector<glm::vec3> & out_vertices, std::vector<glm::vec2> & out_uvs, std::vector<glm::vec3> & out_normals) { Assimp::Importer importer; const aiScene* scene=importer.ReadFile( path, aiProcess_GenSmoothNormals | aiProcess_Triangulate | aiProcess_CalcTangentSpace | aiProcess_FlipUVs); if(!scene || scene->mFlags==AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode) { std::cout << "The file wasn't successfuly opened: " << path << std::endl; return false; } aiMesh* mesh=scene->mMeshes[0]; for(int i=0; i<mesh->mNumVertices; ++i) { glm::vec3 tmpVec; //position tmpVec.x=mesh->mVertices[i].x; tmpVec.y=mesh->mVertices[i].y; tmpVec.z=mesh->mVertices[i].z; out_vertices.push_back(tmpVec); //normals tmpVec.x=mesh->mNormals[i].x; tmpVec.y=mesh->mNormals[i].y; tmpVec.z=mesh->mNormals[i].z; out_normals.push_back(tmpVec); /* //tangent if(mesh->mTangents) { tmpVec.x=mesh->mTangents[i].x; tmpVec.y=mesh->mTangents[i].y; tmpVec.z=mesh->mTangents[i].z; }else{ tmpVec.x=1.0; tmpVec.y=tmpVec.z=0; } //colors if(mesh->mColors[0]) { //!= material color tmpVec.x=mesh->mColors[0][i].r; tmpVec.y=mesh->mColors[0][i].g; tmpVec.z=mesh->mColors[0][i].b; }else{ tmpVec=defaultColor; } tmp.color=tmpVec; */ //Textures if(mesh->mTextureCoords[0]) { tmpVec.x=mesh->mTextureCoords[0][i].x; tmpVec.y=mesh->mTextureCoords[0][i].y; }else{ tmpVec.x=tmpVec.y=tmpVec.z=0.0; } out_uvs.push_back(glm::vec2(tmpVec.x, tmpVec.y)); } for(int i=0;i<mesh->mNumFaces; ++i) { aiFace face=mesh->mFaces[i]; for(int j=0;j<face.mNumIndices;++j) //0..2 { out_indices.push_back(face.mIndices[j]); } } return true; }
int run(int argc, char* argv[]) { Arguments args; args.add("help", 'h').description("Shows this help message.").flag(true); args.add("input", 'i').description("Input filename").required(true); args.add("output", 'o').description("Output filename").required(true); args.add("format", 'f').description("Output format. Overrides file extension."); args.add("axis", 'x').description("Change axis order of the cordinate system and polarity. (like +x+y+z, +x-z+y, ... )"); args.add("textures", 't').description("Strip path from texture filenames").flag(true); // parse args if (!args.evaluate(argc, argv)) { cout << args.getErrorMessage() << endl; cout << args.getHelpMessage() << endl; return 1; } // print help if (argc == 1 || args.get("help").isFound()) { cout << args.getHelpMessage() << endl; return 0; } string inFileName = args.get("input").value(); string outFileName = args.get("output").value(); string outExtension; // determine file format if (!args.get("format").isFound()) { string::size_type n; string s = outFileName; n = s.find_last_of('.'); if (n != string::npos) { s = s.substr(n + 1); } if (s.empty()) { outExtension = "assbin"; cout << "WARNING: No file extension was given. Using assbin format for default." << endl; } else { outExtension = s; } } else { outExtension = args.get("format").value(); } // import scene Assimp::Importer aiImporter; aiScene const * scene = aiImporter.ReadFile(inFileName.c_str(), aiProcessPreset_TargetRealtime_Quality | aiProcess_ConvertToLeftHanded | 0); if (scene == nullptr) { cout << "Could not load model file" << inFileName << endl; cout << aiImporter.GetErrorString() << endl; return 1; } // flip axes if (args.get("axis").isFound() && scene->HasMeshes()) { string axesOrder = args.get("axis").value(); if (axesOrder.length() != 6) { cout << args.getHelpMessage() << endl; return 1; } char order[3]; char polarity[3]; uint k = 3; while (k--) { char c = axesOrder.at(2*k), b = -1; char a = axesOrder.at(2*k+1), d = 1; switch (a) { case 'x': case 'X': b = 0; break; case 'y': case 'Y': b = 1; break; case 'z': case 'Z': b = 2; break; default: cout << args.getHelpMessage() << endl; return 1; } switch (c) { case '+': d = +1; break; case '-': d = -1; break; default: cout << args.getHelpMessage() << endl; return 1; } order[k] = b; polarity[k] = d; } for (uint i = 0; i < scene->mNumMeshes; i++) { aiMesh * const mesh = scene->mMeshes[i]; for (uint j = 0; j < mesh->mNumVertices; j++) { swap_vertices(&mesh->mVertices[j], order, polarity); swap_vertices(&mesh->mNormals[j], order, polarity); } } } // strip texture filenames if (args.get("textures").isFound() && scene->HasMaterials()) { for (uint i = 0; i < scene->mNumMaterials; i++) { aiMaterial const * material = scene->mMaterials[i]; for (uint j = 0; j < sizeof(textureTypes) / sizeof(textureTypes[0]); j++) { aiTextureType tt = textureTypes[j]; for (uint k = 0; k < material->GetTextureCount(tt); k++) { aiString aiPath; material->GetTexture(tt, k, &aiPath); string path = aiPath.C_Str(); { string s = path; string::size_type n, m; n = s.find_last_of('/'); m = s.find_last_of('\\'); if (n != string::npos) { s = s.substr(n + 1); } else if (m != string::npos) { s = s.substr(m + 1); } if (!s.empty()) { path = s; } } // textura filenev vissza const aiMaterialProperty* pp = nullptr; if (aiGetMaterialProperty(material, AI_MATKEY_TEXTURE(tt, k), &pp) == AI_SUCCESS) { aiMaterialProperty* pProp = const_cast<aiMaterialProperty*>(pp); if (aiPTI_String == pProp->mType) { size_t newLen = path.length() + 4; char* newData = (char*)malloc(newLen); (*(uint*)(&newData[0])) = path.length(); memcpy_s(&newData[4], newLen, path.c_str(), path.length()); free(pProp->mData); pProp->mData = newData; pProp->mDataLength = newLen; } } } } } } // save Assimp::Exporter aiExporter; if (aiExporter.Export(scene, outExtension, outFileName) != aiReturn_SUCCESS) { cout << "Could not save model file" << endl; cout << aiExporter.GetErrorString() << endl; return 1; } return 0; }
S3DModel* CAssParser::Load(const std::string& modelFilePath) { logOutput.Print (LOG_MODEL, "Loading model: %s\n", modelFilePath.c_str() ); std::string modelPath = modelFilePath.substr(0, modelFilePath.find_last_of('/')); std::string modelFileNameNoPath = modelFilePath.substr(modelPath.length()+1, modelFilePath.length()); std::string modelName = modelFileNameNoPath.substr(0, modelFileNameNoPath.find_last_of('.')); std::string modelExt = modelFileNameNoPath.substr(modelFileNameNoPath.find_last_of('.'), modelFilePath.length()); //! LOAD METADATA //! Load the lua metafile. This contains properties unique to Spring models and must return a table std::string metaFileName = modelFilePath + ".lua"; CFileHandler* metaFile = new CFileHandler(metaFileName); if (!metaFile->FileExists()) { //! Try again without the model file extension metaFileName = modelPath + '/' + modelName + ".lua"; metaFile = new CFileHandler(metaFileName); } LuaParser metaFileParser(metaFileName, SPRING_VFS_MOD_BASE, SPRING_VFS_ZIP); if (!metaFileParser.Execute()) { if (!metaFile->FileExists()) { logOutput.Print(LOG_MODEL, "No meta-file '%s'. Using defaults.", metaFileName.c_str()); } else { logOutput.Print(LOG_MODEL, "ERROR in '%s': %s. Using defaults.", metaFileName.c_str(), metaFileParser.GetErrorLog().c_str()); } } //! Get the (root-level) model table const LuaTable& metaTable = metaFileParser.GetRoot(); if (metaTable.IsValid()) logOutput.Print(LOG_MODEL, "Found valid model metadata in '%s'", metaFileName.c_str()); //! LOAD MODEL DATA //! Create a model importer instance Assimp::Importer importer; //! Create a logger for debugging model loading issues Assimp::DefaultLogger::create("",Assimp::Logger::VERBOSE); const unsigned int severity = Assimp::Logger::Debugging|Assimp::Logger::Info|Assimp::Logger::Err|Assimp::Logger::Warn; Assimp::DefaultLogger::get()->attachStream( new AssLogStream(), severity ); //! Give the importer an IO class that handles Spring's VFS importer.SetIOHandler( new AssVFSSystem() ); //! Speed-up processing by skipping things we don't need importer.SetPropertyInteger(AI_CONFIG_PP_RVC_FLAGS, aiComponent_CAMERAS|aiComponent_LIGHTS|aiComponent_TEXTURES|aiComponent_ANIMATIONS); #ifndef BITMAP_NO_OPENGL //! Optimize VBO-Mesh sizes/ranges GLint maxIndices = 1024; GLint maxVertices = 1024; glGetIntegerv(GL_MAX_ELEMENTS_INDICES, &maxIndices); glGetIntegerv(GL_MAX_ELEMENTS_VERTICES, &maxVertices); //FIXME returns not optimal data, at best compute it ourself! (pre-TL cache size!) importer.SetPropertyInteger(AI_CONFIG_PP_SLM_VERTEX_LIMIT, maxVertices); importer.SetPropertyInteger(AI_CONFIG_PP_SLM_TRIANGLE_LIMIT, maxIndices/3); #endif //! Read the model file to build a scene object logOutput.Print(LOG_MODEL, "Importing model file: %s\n", modelFilePath.c_str() ); const aiScene* scene = importer.ReadFile( modelFilePath, ASS_POSTPROCESS_OPTIONS ); if (scene != NULL) { logOutput.Print(LOG_MODEL, "Processing scene for model: %s (%d meshes / %d materials / %d textures)", modelFilePath.c_str(), scene->mNumMeshes, scene->mNumMaterials, scene->mNumTextures ); } else { logOutput.Print (LOG_MODEL, "Model Import Error: %s\n", importer.GetErrorString()); } SAssModel* model = new SAssModel; model->name = modelFilePath; model->type = MODELTYPE_ASS; model->scene = scene; //model->meta = &metaTable; //! Gather per mesh info CalculatePerMeshMinMax(model); //! Assign textures //! The S3O texture handler uses two textures. //! The first contains diffuse color (RGB) and teamcolor (A) //! The second contains glow (R), reflectivity (G) and 1-bit Alpha (A). if (metaTable.KeyExists("tex1")) { model->tex1 = metaTable.GetString("tex1", "default.png"); } else { //! Search for a texture std::vector<std::string> files = CFileHandler::FindFiles("unittextures/", modelName + ".*"); for(std::vector<std::string>::iterator fi = files.begin(); fi != files.end(); ++fi) { std::string texPath = std::string(*fi); model->tex1 = texPath.substr(texPath.find('/')+1, texPath.length()); break; //! there can be only one! } } if (metaTable.KeyExists("tex2")) { model->tex2 = metaTable.GetString("tex2", ""); } else { //! Search for a texture std::vector<std::string> files = CFileHandler::FindFiles("unittextures/", modelName + "2.*"); for(std::vector<std::string>::iterator fi = files.begin(); fi != files.end(); ++fi) { std::string texPath = std::string(*fi); model->tex2 = texPath.substr(texPath.find('/')+1, texPath.length()); break; //! there can be only one! } } model->flipTexY = metaTable.GetBool("fliptextures", true); //! Flip texture upside down model->invertTexAlpha = metaTable.GetBool("invertteamcolor", true); //! Reverse teamcolor levels //! Load textures logOutput.Print(LOG_MODEL, "Loading textures. Tex1: '%s' Tex2: '%s'", model->tex1.c_str(), model->tex2.c_str()); texturehandlerS3O->LoadS3OTexture(model); //! Load all pieces in the model logOutput.Print(LOG_MODEL, "Loading pieces from root node '%s'", scene->mRootNode->mName.data); LoadPiece(model, scene->mRootNode, metaTable); //! Update piece hierarchy based on metadata BuildPieceHierarchy( model ); //! Simplified dimensions used for rough calculations model->radius = metaTable.GetFloat("radius", model->radius); model->height = metaTable.GetFloat("height", model->height); model->relMidPos = metaTable.GetFloat3("midpos", model->relMidPos); model->mins = metaTable.GetFloat3("mins", model->mins); model->maxs = metaTable.GetFloat3("maxs", model->maxs); //! Calculate model dimensions if not set if (!metaTable.KeyExists("mins") || !metaTable.KeyExists("maxs")) CalculateMinMax( model->rootPiece ); if (model->radius < 0.0001f) CalculateRadius( model ); if (model->height < 0.0001f) CalculateHeight( model ); //! Verbose logging of model properties logOutput.Print(LOG_MODEL_DETAIL, "model->name: %s", model->name.c_str()); logOutput.Print(LOG_MODEL_DETAIL, "model->numobjects: %d", model->numPieces); logOutput.Print(LOG_MODEL_DETAIL, "model->radius: %f", model->radius); logOutput.Print(LOG_MODEL_DETAIL, "model->height: %f", model->height); logOutput.Print(LOG_MODEL_DETAIL, "model->mins: (%f,%f,%f)", model->mins[0], model->mins[1], model->mins[2]); logOutput.Print(LOG_MODEL_DETAIL, "model->maxs: (%f,%f,%f)", model->maxs[0], model->maxs[1], model->maxs[2]); logOutput.Print (LOG_MODEL, "Model %s Imported.", model->name.c_str()); return model; }
bool LoadAssimp( string file, vector <vec3> &vertices, vector <vec2> &uvs, vector <vec3> &normals, vector <GLuint> &indices ){ /* Dane wyjściowe dla wierzchołków */ vertices.clear(); /* Dane wyjściowe dla UV Map */ uvs.clear(); /* Dane wyjściowe dla Normalnych */ normals.clear(); /* Dane wyjściowe dla kolejności trójkątów */ indices.clear(); /* Tworzenie importer dla ładowania danych. */ Assimp::Importer importer; /* Wczytywanie pliku file (.obj) */ const aiScene* scene = importer.ReadFile( file.c_str(), 0 ); /* Sprawdzenie czy nie ma błedu. */ if( !scene ){ cout<<"importer.ReadFile ("<<file<<"): "<<importer.GetErrorString()<<"\n"; return false; } /* Wczytujemy tylko pierwszą część obiektu, inne pomijamy(występuje w obiektach kilku elementowych/częściowych). */ const aiMesh* mesh = scene->mMeshes[0]; unsigned int i = 0; /* Wektor dla pobierania danych. */ aiVector3D tmp; //vertices: /* Wierzchołki obiektu. */ vertices.reserve( mesh->mNumVertices ); for( i = 0; i < mesh->mNumVertices; ++i ){ tmp = mesh->mVertices[i]; vertices.push_back( vec3( tmp.x, tmp.y, tmp.z ) ); } //uvs: /* UV Mapy */ uvs.reserve( mesh->mNumVertices ); for( i = 0; i < mesh->mNumVertices; ++i ){ tmp = mesh->mTextureCoords[0][i]; //important! //This is done because most images have the top y-axis inversed with OpenGL's top y-axis. //or conver in shader uvs.push_back( glm::vec2( tmp.x, 1.0 - tmp.y ) ); } //normals: /* Normalne */ normals.reserve( mesh->mNumVertices ); for( i = 0; i < mesh->mNumVertices; ++i ){ tmp = mesh->mNormals[i]; normals.push_back( vec3( tmp.x, tmp.y, tmp.z ) ); } //indices: /* Kolejność rysowania trójkątów oraz jak każdy jest reprezentowany przez wierzchołki. */ indices.reserve( 3*mesh->mNumFaces ); for( i = 0; i < mesh->mNumFaces; ++i ){ indices.push_back( mesh->mFaces[i].mIndices[0] ); indices.push_back( mesh->mFaces[i].mIndices[1] ); indices.push_back( mesh->mFaces[i].mIndices[2] ); } return true; }
virtual bool binaryImporterTest() { Assimp::Importer importer; const aiScene *scene = importer.ReadFile( ASSIMP_TEST_MODELS_DIR "/glTF2/2CylinderEngine-glTF-Binary/2CylinderEngine.glb", aiProcess_ValidateDataStructure); return nullptr != scene; }
Mesh::Mesh(string modelPath) : Resource(modelPath, MY_TYPE_INDEX) { Assimp::Importer importer; const aiScene* scene = importer.ReadFile(modelPath, aiProcess_CalcTangentSpace | aiProcess_JoinIdenticalVertices | aiProcess_FindInvalidData | aiProcess_GenNormals | aiProcess_ImproveCacheLocality | aiProcess_Triangulate | aiProcess_FlipWindingOrder | aiProcess_SortByPType); size_t vertCount = 0, faceCount = 0; for (size_t i = 0; i < scene->mNumMeshes; ++i) { vertCount += scene->mMeshes[i]->mNumVertices; faceCount += scene->mMeshes[i]->mNumFaces * 3; } vec3 upper, lower; size_t vertOffset = 0, faceOffset = 0; vertex* verts = new vertex[vertCount]; unsigned int* faces = new unsigned int[faceCount]; lower.x = std::min(lower.x, scene->mMeshes[0]->mVertices[0].x); lower.y = std::min(lower.y, scene->mMeshes[0]->mVertices[0].y); lower.z = std::min(lower.z, scene->mMeshes[0]->mVertices[0].z); upper.x = std::max(upper.x, scene->mMeshes[0]->mVertices[0].x); upper.y = std::max(upper.y, scene->mMeshes[0]->mVertices[0].y); upper.z = std::max(upper.z, scene->mMeshes[0]->mVertices[0].z); for (size_t m = 0; m < scene->mNumMeshes; ++m) { aiMesh* mesh = scene->mMeshes[m]; for (size_t i = 0; i < mesh->mNumVertices; ++i) { vertex vert = { DirectX::XMFLOAT3(mesh->mVertices[i].v), DirectX::XMFLOAT3(mesh->mNormals[i].v), DirectX::XMFLOAT3(mesh->mTangents[i].v), DirectX::XMFLOAT2(mesh->mTextureCoords[0][i].x, 1 - mesh->mTextureCoords[0][i].y) }; verts[vertOffset + i] = vert; upper = vec3(mesh->mVertices[i].x, mesh->mVertices[i].y, mesh->mVertices[i].z); lower = upper; } for (size_t i = 0; i < mesh->mNumFaces; ++i) { faces[faceOffset + i * 3] = vertOffset + mesh->mFaces[i].mIndices[0]; faces[faceOffset + i * 3 + 1] = vertOffset + mesh->mFaces[i].mIndices[1]; faces[faceOffset + i * 3 + 2] = vertOffset + mesh->mFaces[i].mIndices[2]; } vertOffset += mesh->mNumVertices; faceOffset += mesh->mNumFaces * 3; } bounds.halfSize = vec3(upper.x - lower.x, upper.y - lower.y, upper.z - lower.z); bounds.halfSize /= 2.0f; bounds.center.x = lower.x + bounds.halfSize.x; bounds.center.y = lower.y + bounds.halfSize.y; bounds.center.z = lower.z + bounds.halfSize.z; float dist = 0; vec3 furthest; for (size_t i = 0; i < vertCount; ++i) { float distanceCheck = distanceSquared(vec3(verts[i].position.x, verts[i].position.y, verts[i].position.z), bounds.center); if (distanceCheck > dist) { furthest = vec3(verts[i].position.x, verts[i].position.y, verts[i].position.z); dist = distanceCheck; } } dist = 0; vec3 furthest2; for (size_t i = 0; i < vertCount; ++i) { float distanceCheck = distanceSquared(vec3(verts[i].position.x, verts[i].position.y, verts[i].position.z), furthest); if (distanceCheck > dist) { furthest2 = vec3(verts[i].position.x, verts[i].position.y, verts[i].position.z); dist = distanceCheck; } } bounds.sphere = furthest2 - furthest; bounds.radius = length(bounds.sphere) / 2.0f; bounds.sphere = furthest + normalize(bounds.sphere) * bounds.radius; D3D11_BUFFER_DESC vbd; vbd.Usage = D3D11_USAGE_IMMUTABLE; vbd.ByteWidth = sizeof(vertex) * vertCount; vbd.BindFlags = D3D11_BIND_VERTEX_BUFFER; vbd.CPUAccessFlags = 0; vbd.MiscFlags = 0; vbd.StructureByteStride = 0; D3D11_SUBRESOURCE_DATA initialVertexData; initialVertexData.pSysMem = verts; HR(DEVICE->CreateBuffer(&vbd, &initialVertexData, &vertexBuffer)); D3D11_BUFFER_DESC ibd; ibd.Usage = D3D11_USAGE_IMMUTABLE; ibd.ByteWidth = sizeof(unsigned int) * faceCount; ibd.BindFlags = D3D11_BIND_INDEX_BUFFER; ibd.CPUAccessFlags = 0; ibd.MiscFlags = 0; ibd.StructureByteStride = 0; D3D11_SUBRESOURCE_DATA initialIndexData; initialIndexData.pSysMem = faces; HR(DEVICE->CreateBuffer(&ibd, &initialIndexData, &indexBuffer)); elementArraySize = faceCount; delete[] verts; delete[] faces; }