Example #1
0
std::vector<Ygg::ConverterData>* Ygg::Loader::LoadScene(const std::string filename, std::vector<Entity> *entity_list)
{
	Assimp::Importer importer;
	importer.SetPropertyInteger(AI_CONFIG_PP_SLM_VERTEX_LIMIT, 65536);
	importer.SetPropertyInteger(AI_CONFIG_PP_SBP_REMOVE, aiPrimitiveType_POINT | aiPrimitiveType_LINE);
	const aiScene* ascene = importer.ReadFile(filename,
		aiProcess_CalcTangentSpace |
		aiProcess_Triangulate |
		aiProcess_FindDegenerates |
		aiProcess_SplitLargeMeshes |
		aiProcess_JoinIdenticalVertices |
		aiProcess_SortByPType);

	if (!ascene)
	{
		std::fprintf(stderr, "%s\n", importer.GetErrorString());
		return &this->results;
	}

	// Get path for relative textures
	int split = (int)filename.rfind("/");
	std::string path = filename.substr(0, split + 1);

	// Now we can access the file's contents.
	this->ParseScene(ascene, entity_list);

	return &this->results;
}
Example #2
0
Node *Model::load(Scene &scene, Node &root, const std::string &prefix, const std::string &filename, const unsigned int options)
{
  unsigned int pflags;
  unsigned int remove_flags;
  std::string full_name = prefix + "/" + filename;
  this->prefix = prefix;


  if (!file_exists(full_name)) {
    std::cout << "Model file '" << full_name << "' does not exist. Exiting ..." << std::endl;
    exit(-1);
  }

  pflags = aiProcess_Triangulate | aiProcess_GenSmoothNormals | aiProcess_CalcTangentSpace | 
           aiProcess_FindDegenerates | aiProcess_JoinIdenticalVertices | aiProcess_FlipUVs | 
           aiProcess_LimitBoneWeights | aiProcess_RemoveComponent | aiProcess_FixInfacingNormals;
  
  remove_flags = aiComponent_COLORS | aiComponent_LIGHTS | aiComponent_CAMERAS;

  if (options & MODEL_IMPORT_OPTIMIZED) {
    pflags |= aiProcess_OptimizeGraph | aiProcess_OptimizeMeshes | aiProcess_RemoveComponent | aiProcess_FindInstances;
  }

  if (options & MODEL_IMPORT_LIGHTS) {
    remove_flags = aiComponent_COLORS | aiComponent_CAMERAS;
  }

  Assimp::Importer importer;
  importer.SetPropertyInteger(AI_CONFIG_PP_LBW_MAX_WEIGHTS, 3);
  importer.SetPropertyInteger(AI_CONFIG_PP_RVC_FLAGS, remove_flags);
  assimp_scene = importer.ReadFile(full_name.c_str(), pflags);

  if (!assimp_scene) {
    std::cout << "Error parsing '" <<  full_name.c_str() << "': " << importer.GetErrorString() << std::endl;
    exit(-1);
  }

  Node *rootPtr = node_map_create(scene, *assimp_scene->mRootNode, &root, root.tree_level_get(), options);
//  rootPtr->transform_update_global_recursive(*rootPtr);
  BoneForAssimpBone boneForAssimpBone;
  bone_map_create(scene, boneForAssimpBone, options);
  materials_parse(scene);
  lights_parse(scene);

  mesh_create_all(scene, *assimp_scene->mRootNode, boneForAssimpBone);
  key_frames_parse();

  return rootPtr;
}
Example #3
0
	int LoadScene(tchar const *filename, aiScene const **scene)
	{
		if(scene == null || filename == null)
		{
			return E_POINTER;
		}

		Assimp::Importer *importer = new Assimp::Importer();
		importer->SetIOHandler(new MyIOSystem());
		importer->SetPropertyInteger(AI_CONFIG_PP_SBP_REMOVE, aiPrimitiveType_LINE | aiPrimitiveType_POINT);

#if defined(_DEBUG)
		DefaultLogger::create("", Logger::VERBOSE, aiDefaultLogStream_DEBUGGER);
#endif
		importer->ReadFile(filename, aiProcess_Triangulate | aiProcess_SortByPType);

#if defined(_DEBUG)
		DefaultLogger::kill();
#endif
		if(importer->GetScene() == null)
		{
			TRACE("Error loading %s: %s\n", filename, importer->GetErrorString());
			return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
		}
		*scene = importer->GetScene();
		return S_OK;
	}
Example #4
0
	////////////////////////////////////////////////////////////////////////
	///
	/// @fn void Modele3D::charger(Path cheminFichier)
	///
	/// Cette fonction charge un modèle 3D à partir d'un fichier supporté
	/// par la librairie 'assimp'. Les textures OpenGL afférentes sont
	/// également chargées.
	///
	/// @param[in] nomFichier : nom du fichier modèle (normalement .obj
	///	ou .dae)
	///
	/// @return Aucune.
	///
	////////////////////////////////////////////////////////////////////////
	void Modele3D::charger(Path cheminFichier)
	{
		/// Ne pas charger le même fichier inutilement 
		if (cheminFichier_ == cheminFichier)
			return;

		cheminFichier_ = std::move(cheminFichier);

		/// Ne pas conserver les identifiants de texture d'un ancien modèle
		libererTextures();

		Assimp::Importer importer;

		/// Lors de l'importation, ne pas conserver les lignes et les points.
		importer.SetPropertyInteger(AI_CONFIG_PP_SBP_REMOVE, aiPrimitiveType_LINE | aiPrimitiveType_POINT);

		/// Le flag aiProcess_Triangulate, inclus dans aiProcessPreset_TargetRealtime_Quality,
		/// fera en sorte que les mesh ne comporteront que des triangles.
		const aiScene* scene{ importer.ReadFile(cheminFichier_, aiProcessPreset_TargetRealtime_Quality) };

		if (scene == nullptr) {
			utilitaire::afficherErreur(std::string{ "Impossible de charger l'objet 3d : " } +cheminFichier.filename() + std::string{ "." });
			return;
		}

		/// Charger l'ensemble des textures contenues dans le modèle :
		chargerTexturesExternes(scene);
		chargerTexturesIntegrees(scene);

		/// Chargement des données du modèle 3D
		racine_ = Noeud{ scene, scene->mRootNode };
	}
Example #5
0
SharedPointer< Group > SceneImporter::import( std::string filename )
{
	// check if file exists
	std::ifstream fin( filename );
	bool exists = !fin.fail();
	fin.close();
	if ( !exists ) {
		// Is it ok to throw exceptions?
		throw FileNotFoundException( filename );
	}

	Assimp::Importer importer;
	importer.SetPropertyInteger( AI_CONFIG_PP_SLM_VERTEX_LIMIT, 15000 );
	const aiScene* importedScene = importer.ReadFile( filename, aiProcessPreset_TargetRealtime_MaxQuality );
	if ( importedScene == nullptr ) {
		Log::error( CRIMILD_CURRENT_CLASS_NAME, "Error importing file ", filename, "\n", importer.GetErrorString() );
	 	return nullptr;
	}

	auto skinnedMesh = crimild::alloc< SkinnedMesh >();
	loadAnimations( importedScene, skinnedMesh );

	auto root = crimild::alloc< Group >( filename );
	auto basePath = FileSystem::getInstance().extractDirectory( filename ) + "/";
	recursiveSceneBuilder( root, importedScene, importedScene->mRootNode, basePath, skinnedMesh );

	if ( _skeleton != nullptr ) {
		Transformation globalInverseTransform;
		computeTransform( importedScene->mRootNode->mTransformation.Inverse(), globalInverseTransform );
		_skeleton->setGlobalInverseTransform( globalInverseTransform );
		root->attachComponent( _skeleton );
	}

	return root;
}
Example #6
0
bool SceneLoader::LoadScene(const std::string& file_name, Scene& scene,
                            std::string& status) {
    Assimp::Importer importer;
    importer.SetPropertyInteger(AI_CONFIG_PP_SBP_REMOVE,
                                aiPrimitiveType_POINT | aiPrimitiveType_LINE);
    const aiScene* assimp_scene = importer.ReadFile(file_name,
                                  aiProcess_Triangulate | aiProcess_JoinIdenticalVertices
                                  | aiProcess_FixInfacingNormals | aiProcess_FindDegenerates
                                  | aiProcess_ValidateDataStructure);
    // | aiProcess_ImproveCacheLocality
    //  | aiProcess_RemoveRedundantMaterials
    //  | aiProcess_FixInfacingNormals | aiProcess_FindDegenerates
    // | aiProcess_OptimizeGraph | aiProcess_OptimizeMeshes);
    status = std::string(importer.GetErrorString());
    if (!status.empty() || NULL == assimp_scene) {
        return false;
    }
    status = "OK";
    for (uint32_t i = 0; i < assimp_scene->mNumCameras; ++i) {
        ImportCamera(scene, assimp_scene->mCameras[i]);
    }
    for (uint32_t i = 0; i < assimp_scene->mNumLights; ++i) {
        ImportLight(scene, assimp_scene->mLights[i]);
    }
    std::cout << "mNumMaterials = " << assimp_scene->mNumMaterials << std::endl;
    for (uint32_t i = 0; i < assimp_scene->mNumMaterials; ++i) {
        ImportMaterial(scene, assimp_scene->mMaterials[i]);
    }
    std::cout << "mNumMeshes = " << assimp_scene->mNumMeshes << std::endl;
    for (uint32_t i = 0; i < assimp_scene->mNumMeshes; ++i) {
        ImportMesh(scene, assimp_scene->mMeshes[i]);
    }
    return true;
}
Example #7
0
void LoadMeshFromColladaAssimp(const char* relativeFileName, btAlignedObjectArray<GLInstanceGraphicsShape>& visualShapes, btAlignedObjectArray<ColladaGraphicsInstance>& visualShapeInstances,btTransform& upAxisTrans, float& unitMeterScaling)
{
	upAxisTrans.setIdentity();
	unitMeterScaling=1;

	GLInstanceGraphicsShape* shape = 0;
	
	
	FILE* file = fopen(relativeFileName,"rb");
	if (file)
	{
		int size=0;
		if (fseek(file, 0, SEEK_END) || (size = ftell(file)) == EOF || fseek(file, 0, SEEK_SET))
		{
			printf("Error: Cannot access file to determine size of %s\n", relativeFileName);
		} else
		{
			if (size)
			{
				printf("Open DAE file of %d bytes\n",size);
				
				Assimp::Importer importer;
				//importer.SetPropertyInteger(AI_CONFIG_PP_RVC_FLAGS, aiComponent_NORMALS | aiComponent_COLORS);
				importer.SetPropertyInteger(AI_CONFIG_PP_SBP_REMOVE, aiPrimitiveType_LINE | aiPrimitiveType_POINT);
			//	importer.SetPropertyInteger(AI_CONFIG_IMPORT_COLLADA_IGNORE_UP_DIRECTION, 1);
				aiScene const* scene = importer.ReadFile(relativeFileName,
						aiProcess_JoinIdenticalVertices |
						//aiProcess_RemoveComponent |
						aiProcess_SortByPType |
						aiProcess_Triangulate);
				if (scene)
				{
					shape = &visualShapes.expand();
					shape->m_scaling[0] = 1;
					shape->m_scaling[1] = 1;
					shape->m_scaling[2] = 1;
					shape->m_scaling[3] = 1;
					int index = 0;
					shape->m_indices = new b3AlignedObjectArray<int>();
					shape->m_vertices = new b3AlignedObjectArray<GLInstanceVertex>();

					aiMatrix4x4 ident;
					addMeshParts(scene, scene->mRootNode, shape, ident);
					 shape->m_numIndices = shape->m_indices->size();
					shape->m_numvertices = shape->m_vertices->size();
					ColladaGraphicsInstance& instance = visualShapeInstances.expand();
					instance.m_shapeIndex = visualShapes.size()-1;
				}
			}
		}
		
	}
	
}
Example #8
0
// Loads a model with supported ASSIMP extensions from file and stores the resulting meshes in the meshes vector.
void Model::loadModelFromFile(std::string path, bool flipUVs, bool forDistField)
{
  _filename = path.substr(path.find_last_of('/'), path.length());
  // Read file via ASSIMP
  Assimp::Importer importer;
  
  unsigned int flags = aiProcessPreset_TargetRealtime_Fast;
  if (forDistField)
  {
	  flags = aiProcess_JoinIdenticalVertices |
		  aiProcess_Triangulate |
		  aiProcess_PreTransformVertices |
		  aiProcess_ValidateDataStructure |
		  aiProcess_RemoveRedundantMaterials |
		  aiProcess_FindDegenerates |
		  aiProcess_SortByPType |
		  aiProcess_FixInfacingNormals | 
		  aiProcess_GenSmoothNormals;
	   //This with aiProcess_FindDegenerates and aiProcess_SortByPType will get rid of all degenerate triangles and not create lines or points.
	  importer.SetPropertyInteger(AI_CONFIG_PP_SBP_REMOVE, aiPrimitiveType::aiPrimitiveType_POINT | aiPrimitiveType::aiPrimitiveType_LINE);
	  //Configures the #aiProcess_PretransformVertices step to normalize all vertex components into the[-1, 1] range.
	  //importer.SetPropertyInteger(AI_CONFIG_PP_PTV_NORMALIZE, 1);

  }
  if (flipUVs)
  {
    flags |= aiProcess_FlipUVs;
  }
  const aiScene* scene = importer.ReadFile(path, flags);

  // Check for errors
  if (!scene || scene->mFlags == AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode) // if is Not Zero
  {
    std::cout << "ERROR::ASSIMP:: " << importer.GetErrorString() << std::endl;
    return;
  }
  // Retrieve the directory path of the filepath
  this->_directory = path.substr(0, path.find_last_of('/'));

  //Process the materials
  this->processMaterials(scene);

  // Process ASSIMP's root node recursively
  glm::mat4 identity;
  this->processNode(scene->mRootNode, scene, identity);

  for (auto m : _meshes)
  {
    m->bindAttributesToVAO();
  }
}
Example #9
0
ModelInterface::ModelInterface(TextureManager* manager, const QString filename)
: has_animations(false)
, meshes(0)
, animations(0)
, bones(0)
, textureManager(manager)
{
    if(filename.contains("/"))
    {
        int index = filename.lastIndexOf("/") + 1;

        filePath = filename.left(index);
        fileName = filename.right(filename.size() - index);
    }
    else
        fileName = filename;

    Assimp::Importer importer;
    importer.SetPropertyInteger(AI_CONFIG_PP_LBW_MAX_WEIGHTS, 4);

    const aiScene* scene = importer.ReadFile(filename.toStdString(), aiProcess_GenSmoothNormals | aiProcess_Triangulate | aiProcess_CalcTangentSpace/* | aiProcess_FlipUVs*/);

    if(!scene || scene->mFlags == AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode)
    {
        throw QString("The file wasn't successfuly opened");

        return;
    }

    if(scene->HasAnimations())
    {
        has_animations = true;
        bones          = loadBones(scene);

        buildSkeleton(scene->mRootNode, NULL);

        animations = new Animations();
        animations->setBones(bones);

        for(uint i = 0; i < scene->mNumAnimations; ++i)
            animations->add(loadAnimation(scene->mAnimations[i], i));
    }

    meshes = new Meshes();

    for(uint i = 0; i < scene->mNumMeshes; ++i)
        meshes->add(loadMesh(scene->mMeshes[i], scene->mMaterials[scene->mMeshes[i]->mMaterialIndex], i));

    initialize(scene);
    // try delete scene probably crash
}
Example #10
0
std::vector<std::shared_ptr<RenderingObject>> LoadMesh(std::shared_ptr<ShaderProgram> inputShader, const std::string& filename, std::vector<std::shared_ptr<aiMaterial>>* outputMaterials)
{

#ifndef ASSET_PATH
    static_assert(false, "ASSET_PATH is not defined. Check to make sure your projects are setup correctly");
#endif

    Assimp::Importer importer;
    importer.SetPropertyInteger(AI_CONFIG_PP_SBP_REMOVE, aiPrimitiveType_LINE | aiPrimitiveType_POINT);

    const std::string completeFilename = std::string(STRINGIFY(ASSET_PATH)) + "/" + filename;

    const aiScene* scene = importer.ReadFile(completeFilename.c_str(),
            aiProcess_CalcTangentSpace       | 
            aiProcess_Triangulate            |
            aiProcess_JoinIdenticalVertices  |
            aiProcess_FixInfacingNormals |
            aiProcess_SortByPType);
    if (!scene) {
        std::cerr << "ERROR: Assimp failed -- " << importer.GetErrorString() << std::endl;
        return {};
    }

    std::vector<std::shared_ptr<aiMaterial>> sceneMaterials;
    if (outputMaterials) {
        sceneMaterials.resize(scene->mNumMaterials);
        for (unsigned int m = 0; m < scene->mNumMaterials; ++m) {
            aiMaterial* material = scene->mMaterials[m];
            std::shared_ptr<aiMaterial> dstMaterial = std::make_shared<aiMaterial>();
            aiMaterial::CopyPropertyList(dstMaterial.get(), material);
            sceneMaterials[m] = dstMaterial;
        }
    }

    std::vector<std::shared_ptr<RenderingObject>> loadedMeshes;
    for (decltype(scene->mNumMeshes) i = 0; i < scene->mNumMeshes; ++i) {
        const aiMesh* mesh = scene->mMeshes[i];
        if (!mesh->HasPositions()) {
            std::cerr << "WARNING: A mesh in " << filename << " does not have positions. Skipping." << std::endl;
            continue;
        }

        auto totalVertices = mesh->mNumVertices;
        std::unique_ptr<RenderingObject::PositionArray> positions = make_unique<RenderingObject::PositionArray>(totalVertices);
        std::unique_ptr<RenderingObject::NormalArray> normals = mesh->HasNormals() ? make_unique<RenderingObject::NormalArray>(totalVertices) : nullptr;
        std::unique_ptr<RenderingObject::UVArray> uv =  mesh->HasTextureCoords(0) ? make_unique<RenderingObject::UVArray>(totalVertices) : nullptr;
        std::unique_ptr<RenderingObject::ColorArray> colors = mesh->HasVertexColors(0) ? make_unique<RenderingObject::ColorArray>(totalVertices) : nullptr;
        std::unique_ptr<RenderingObject::IndexArray> indices = mesh->HasFaces() ? make_unique<RenderingObject::IndexArray>(mesh->mNumFaces * 3) : nullptr;

        for (decltype(totalVertices) v = 0; v < totalVertices; ++v) {
            positions->at(v) = glm::vec4(mesh->mVertices[v].x, mesh->mVertices[v].y, mesh->mVertices[v].z, 1.f);
            
            if (normals) {
                normals->at(v) = glm::vec3(mesh->mNormals[v].x, mesh->mNormals[v].y, mesh->mNormals[v].z);
            }

            if (uv) {
                uv->at(v) = glm::vec2(mesh->mTextureCoords[0][v].x, mesh->mTextureCoords[0][v].y);
            }

            if (colors) {
                colors->at(v) = glm::vec4(mesh->mColors[0][v].r, mesh->mColors[0][v].g, mesh->mColors[0][v].b, mesh->mColors[0][v].a);
            }
        }

        for (decltype(mesh->mNumFaces) f = 0; f < mesh->mNumFaces && indices; ++f) {
            const aiFace& face =  mesh->mFaces[f];
            if (face.mNumIndices != 3) {
                std::cerr << "WARNING: Input mesh may not be triangulated. Skipping face with: " << face.mNumIndices << " vertices." << std::endl;
                continue;
            }

            for (int j = 0; j < 3; ++j) {
                indices->at(f * 3 + j) = face.mIndices[j];
            }
        }

        std::shared_ptr<RenderingObject> createdMesh = std::make_shared<RenderingObject>(inputShader, std::move(positions), std::move(indices),
            std::move(normals), std::move(uv), std::move(colors));
        loadedMeshes.push_back(std::move(createdMesh));
        if (outputMaterials) {
            outputMaterials->push_back(sceneMaterials[mesh->mMaterialIndex]);
        }
    }
    return loadedMeshes;
}
Example #11
0
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;
}
Example #12
0
std::shared_ptr<GeometryData::GenericObject> AssimpWrapper::LoadModel(std::string sFilename)
{
    Assimp::Importer importer;

    importer.SetPropertyInteger(AI_CONFIG_PP_SBP_REMOVE, aiPrimitiveType_POINT | aiPrimitiveType_LINE );

    const aiScene* scene = importer.ReadFile(sFilename,
                                             aiProcess_CalcTangentSpace	|
                                             aiProcess_ValidateDataStructure	|
                                             aiProcess_Triangulate		|
                                             aiProcess_PreTransformVertices	|
                                             //aiProcess_JoinIdenticalVertices	|
                                             aiProcess_GenSmoothNormals		|
                                             aiProcess_ImproveCacheLocality |
                                             aiProcess_FindInvalidData |
                                             //aiProcess_MakeLeftHanded |
                                             //aiProcess_OptimizeMeshes |
                                             //aiProcess_OptimizeGraph  |
                                             aiProcess_GenUVCoords |
                                             aiProcess_TransformUVCoords |
                                             aiProcess_FlipUVs |
                                             aiProcess_FindDegenerates |
                                             aiProcess_SortByPType

                                             );

      // If the import failed, report it
    if( !scene)
        Logger::error() << importer.GetErrorString() << Logger::endl;
    else
        Logger::debug() << "Loaded file " << sFilename << " with assimp" << Logger::endl;

    //bool bModelHasMeshes = scene->HasMeshes();
    //bool bModelHasMaterials = scene->HasMaterials();
    //bool bModelHasTextures = scene->HasTextures();

    unsigned int nNumMeshes = scene->mNumMeshes;

    assert (nNumMeshes > 0);

    GeometryData::GenericObject *pObject = new GeometryData::GenericObject(nNumMeshes);

    std::shared_ptr<GeometryData::GenericObject> spObject(pObject);


    for (unsigned int i=0; i < nNumMeshes; i++)
    {
        aiMesh *pMesh = scene->mMeshes[i];
        GeometryData::GenericMesh *pGenericMesh = std::shared_ptr<GeometryData::GenericMesh>(pObject->GetMesh(i)).get();

        unsigned int nMaterialIndex = pMesh->mMaterialIndex;

        aiMaterial *pUsedMaterial = scene->mMaterials[nMaterialIndex];

        // now fetch the material properties
       /* aiColor3D acDiffuse (0.f,0.f,0.f);
        bool bGotColorDiffuse = (AI_SUCCESS == pUsedMaterial->Get(AI_MATKEY_COLOR_DIFFUSE, acDiffuse));
        float pfDiffuseColor[3] = { acDiffuse.r, acDiffuse.g, acDiffuse.b };
        if (bGotColorDiffuse)
        {
           // pGenericMesh->AddAttributeValues(GeometryData::GenericData::DATA_MATERIAL_COLOR_DIFFUSE, 3, pfDiffuseColor);

            unsigned int nNumVertices = pMesh->mNumVertices;

            std::vector<float> vfFakedColor;

            //get vertices
            for (unsigned int ii=0; ii < nNumVertices; ii++)
            {
                vfFakedColor.push_back(pfDiffuseColor[0]);
                vfFakedColor.push_back(pfDiffuseColor[1]);
                vfFakedColor.push_back(pfDiffuseColor[2]);
            }

            pGenericMesh->AddAttributeValues(GeometryData::GenericData::DATA_COLORS,
                                       3 * nNumVertices,
                                       &vfFakedColor[0]);
        }

        aiColor3D acSpecular (0.f, 0.f, 0.f);
        bool bGotSpecularColor = (AI_SUCCESS == pUsedMaterial->Get(AI_MATKEY_COLOR_SPECULAR, acSpecular));
        float pfSpecularColor[3] = { acSpecular.r, acSpecular.g, acSpecular.b };
        if (bGotSpecularColor)
            pGenericMesh->AddAttributeValues(GeometryData::GenericData::DATA_MATERIAL_COLOR_SPECULAR, 3, pfSpecularColor);

        float fShininess = 0.0f;
        bool bGotShininess = (AI_SUCCESS == pUsedMaterial->Get(AI_MATKEY_SHININESS, fShininess));
        if (bGotShininess)
            pGenericMesh->AddAttributeValues(GeometryData::GenericData::DATA_MATERIAL_SHININESS, 1, &fShininess);

        float fShininessStrength = 0.0f;
        bool bGotShininessStrength = (AI_SUCCESS == pUsedMaterial->Get(AI_MATKEY_SHININESS_STRENGTH, fShininessStrength));
        if (bGotShininessStrength)
            pGenericMesh->AddAttributeValues(GeometryData::GenericData::DATA_MATERIAL_SHININESS_STRENGTH, 1, &fShininessStrength);*/

        assert (pMesh->HasPositions());

        if (pMesh->HasPositions())
        {
            // get vertices
            unsigned int nNumVertices = pMesh->mNumVertices;

            std::vector<float> vfVertices;

            //get vertices
            for (unsigned int ii=0; ii < nNumVertices; ii++)
            {
                vfVertices.push_back(pMesh->mVertices[ii].x);
                vfVertices.push_back(pMesh->mVertices[ii].y);
                vfVertices.push_back(pMesh->mVertices[ii].z);
            }

            pGenericMesh->AddAttributeValues(GeometryData::GenericData::DATA_VERTICES,
                                       3 * nNumVertices,
                                       &vfVertices[0]);
        }


        if (pMesh->HasNormals())
        {
            unsigned int nNumVertices = pMesh->mNumVertices;

            std::vector<float> vfNormals;

            //get vertices
            for (unsigned int ii=0; ii < nNumVertices; ii++)
            {
                vfNormals.push_back(pMesh->mNormals[ii].x);
                vfNormals.push_back(pMesh->mNormals[ii].y);
                vfNormals.push_back(pMesh->mNormals[ii].z);
            }

            pGenericMesh->AddAttributeValues(GeometryData::GenericData::DATA_NORMALS,
                                       3 * nNumVertices,
                                       &vfNormals[0]);
        }

        if (pMesh->HasTangentsAndBitangents())
        {
            unsigned int nNumVertices = pMesh->mNumVertices;

            std::vector<float> vfTangents;
            std::vector<float> vfBitangents;

            //get vertices
            for (unsigned int ii=0; ii < nNumVertices; ii++)
            {
                vfTangents.push_back(pMesh->mTangents[ii].x);
                vfTangents.push_back(pMesh->mTangents[ii].y);
                vfTangents.push_back(pMesh->mTangents[ii].z);
                vfBitangents.push_back(pMesh->mBitangents[ii].x);
                vfBitangents.push_back(pMesh->mBitangents[ii].y);
                vfBitangents.push_back(pMesh->mBitangents[ii].z);
            }

            pGenericMesh->AddAttributeValues(GeometryData::GenericData::DATA_TANGENTS,
                                       3 * nNumVertices,
                                       &vfTangents[0]);

            pGenericMesh->AddAttributeValues(GeometryData::GenericData::DATA_BITANGENTS,
                                       3 * nNumVertices,
                                       &vfBitangents[0]);
        }


        if (pMesh->GetNumColorChannels() > 1)
            Logger::error() << "The model " << sFilename << " has more than one color channel. Only 1 color channel is imported by AssimpWrapper" << Logger::endl;

        if (pMesh->HasVertexColors(0))
        {
            unsigned int nNumVertices = pMesh->mNumVertices;

            std::vector<float> vfColors;

            //get vertices
            for (unsigned int ii=0; ii < nNumVertices; ii++)
            {
                vfColors.push_back(pMesh->mColors[0][ii].r);
                vfColors.push_back(pMesh->mColors[0][ii].g);
                vfColors.push_back(pMesh->mColors[0][ii].b);
            }

            pGenericMesh->AddAttributeValues(GeometryData::GenericData::DATA_COLORS,
                                               3 * nNumVertices,
                                               &vfColors[0]);
        }

        // get indices

        unsigned int nNumFaces = pMesh->mNumFaces;
        std::vector<unsigned int> vIndicesVector;

        for (unsigned int ii=0; ii < nNumFaces; ii++)
        {
            assert (pMesh->mFaces[ii].mNumIndices == 3);

            vIndicesVector.push_back(pMesh->mFaces[ii].mIndices[0]);
            vIndicesVector.push_back(pMesh->mFaces[ii].mIndices[1]);
            vIndicesVector.push_back(pMesh->mFaces[ii].mIndices[2]);
        }

        pGenericMesh->AddIndices(nNumFaces * 3, &vIndicesVector[0]);

        if (sFilename == "models/pool_sphere.dae")
        {
            pGenericMesh->SetTexturePath(GeometryData::TextureNames::CUBEMAP, "abc");
        }

        // get textures
        for (int iTextureType= (int) aiTextureType_DIFFUSE; iTextureType <= (int) aiTextureType_UNKNOWN; iTextureType++)
        {
            int iCount = pUsedMaterial->GetTextureCount((aiTextureType) iTextureType);

            if (iCount >= 1)
            {
                aiString sTexturePath;

                if (iCount > 1)
                    Logger::debug() << "Model \"" << sFilename << "\" contains more than one texture per type. This is not supported yet." << Logger::endl;

                pUsedMaterial->GetTexture((aiTextureType) iTextureType, 0, &sTexturePath);

                GeometryData::TextureType tTextureType;

                bool bIgnoreTexture = false;

                // if the texture type is supported by GeometryData, set the corresponding type and path
                switch (iTextureType)
                {
                case aiTextureType_DIFFUSE:
                    Logger::debug() << "diffuse " << std::string(sTexturePath.data) << Logger::endl;
                    tTextureType = GeometryData::TextureNames::ALBEDO;
                    break;
                case aiTextureType_NORMALS:
                    Logger::debug() << "normals " << std::string(sTexturePath.data) << Logger::endl;
                    tTextureType = GeometryData::TextureNames::NORMAL;
                    break;
                case aiTextureType_SPECULAR:
                    Logger::debug() << "specular " << std::string(sTexturePath.data) << Logger::endl;
                    tTextureType = GeometryData::TextureNames::SPECULAR;
                    break;
                case aiTextureType_HEIGHT:
                    Logger::debug() << "height " << std::string(sTexturePath.data) << Logger::endl;
                    tTextureType = GeometryData::TextureNames::NORMAL;
                    break;
                case aiTextureType_DISPLACEMENT:
                    Logger::debug() << "displacement " << std::string(sTexturePath.data) << Logger::endl;
                    tTextureType = GeometryData::TextureNames::DISPLACE;
                    break;
                default:
                    bIgnoreTexture = true;
                }

                if (!bIgnoreTexture)
                {
                    std::vector<float> vTextureCoords;

                    if (pMesh->GetNumUVChannels() > 1)
                        Logger::error() << "Model \"" << sFilename << "\" contains more than one uv channel. That's not supported by the importer yet." << Logger::endl;

                    if (pMesh->GetNumUVChannels() >= 1)
                    {
                        for (unsigned int nVertex=0; nVertex < pMesh->mNumVertices; nVertex++)
                        {
                            vTextureCoords.push_back(pMesh->mTextureCoords[0][nVertex].x);
                            vTextureCoords.push_back(pMesh->mTextureCoords[0][nVertex].y);
                        }

                        pGenericMesh->SetTextureCoords(tTextureType, vTextureCoords.size(), &vTextureCoords[0]);
                    }

                    pGenericMesh->SetTexturePath(tTextureType, std::string(sTexturePath.data));
                }
                else
                {
                    Logger::debug() << "Model \"" << sFilename << "\" contains some types of textures which are not supported by the importer yet" << Logger::endl;
                }
            }
        }
    }


    return spObject;
}
Example #13
0
bool Model::LoadAssimp(const char *filename)
{
	Assimp::Importer importer;

	// remove unused data
	importer.SetPropertyInteger(AI_CONFIG_PP_RVC_FLAGS, 
		aiComponent_COLORS | aiComponent_LIGHTS | aiComponent_CAMERAS);

	// max triangles and vertices per mesh, splits above this threshold
	importer.SetPropertyInteger(AI_CONFIG_PP_SLM_TRIANGLE_LIMIT, INT_MAX);
	importer.SetPropertyInteger(AI_CONFIG_PP_SLM_VERTEX_LIMIT, 0xfffe); // avoid the primitive restart index

	// remove points and lines
	importer.SetPropertyInteger(AI_CONFIG_PP_SBP_REMOVE, aiPrimitiveType_POINT | aiPrimitiveType_LINE);

	const aiScene *scene = importer.ReadFile(filename,
		aiProcess_CalcTangentSpace |
		aiProcess_JoinIdenticalVertices |
		aiProcess_Triangulate |
		aiProcess_RemoveComponent |
		aiProcess_GenSmoothNormals |
		aiProcess_SplitLargeMeshes |
		aiProcess_ValidateDataStructure |
		//aiProcess_ImproveCacheLocality | // handled by optimizePostTransform()
		aiProcess_RemoveRedundantMaterials |
		aiProcess_SortByPType |
		aiProcess_FindInvalidData |
		aiProcess_GenUVCoords |
		aiProcess_TransformUVCoords |
		aiProcess_OptimizeMeshes |
		aiProcess_OptimizeGraph);

	if (scene == nullptr)
		return false;

	if (scene->HasTextures())
	{
		// embedded textures...
	}

	if (scene->HasAnimations())
	{
		// todo
	}

	m_Header.materialCount = scene->mNumMaterials;
	m_pMaterial = new Material [m_Header.materialCount];
	memset(m_pMaterial, 0, sizeof(Material) * m_Header.materialCount);
	for (unsigned int materialIndex = 0; materialIndex < scene->mNumMaterials; materialIndex++)
	{
		const aiMaterial *srcMat = scene->mMaterials[materialIndex];
		Material *dstMat = m_pMaterial + materialIndex;

		aiColor3D diffuse(1.0f, 1.0f, 1.0f);
		aiColor3D specular(1.0f, 1.0f, 1.0f);
		aiColor3D ambient(1.0f, 1.0f, 1.0f);
		aiColor3D emissive(0.0f, 0.0f, 0.0f);
		aiColor3D transparent(1.0f, 1.0f, 1.0f);
		float opacity = 1.0f;
		float shininess = 0.0f;
		float specularStrength = 1.0f;
		aiString texDiffusePath;
		aiString texSpecularPath;
		aiString texEmissivePath;
		aiString texNormalPath;
		aiString texLightmapPath;
		aiString texReflectionPath;
		srcMat->Get(AI_MATKEY_COLOR_DIFFUSE, diffuse);
		srcMat->Get(AI_MATKEY_COLOR_SPECULAR, specular);
		srcMat->Get(AI_MATKEY_COLOR_AMBIENT, ambient);
		srcMat->Get(AI_MATKEY_COLOR_EMISSIVE, emissive);
		srcMat->Get(AI_MATKEY_COLOR_TRANSPARENT, transparent);
		srcMat->Get(AI_MATKEY_OPACITY, opacity);
		srcMat->Get(AI_MATKEY_SHININESS, shininess);
		srcMat->Get(AI_MATKEY_SHININESS_STRENGTH, specularStrength);
		srcMat->Get(AI_MATKEY_TEXTURE(aiTextureType_DIFFUSE, 0), texDiffusePath);
		srcMat->Get(AI_MATKEY_TEXTURE(aiTextureType_SPECULAR, 0), texSpecularPath);
		srcMat->Get(AI_MATKEY_TEXTURE(aiTextureType_EMISSIVE, 0), texEmissivePath);
		srcMat->Get(AI_MATKEY_TEXTURE(aiTextureType_NORMALS, 0), texNormalPath);
		srcMat->Get(AI_MATKEY_TEXTURE(aiTextureType_LIGHTMAP, 0), texLightmapPath);
		srcMat->Get(AI_MATKEY_TEXTURE(aiTextureType_REFLECTION, 0), texReflectionPath);

		dstMat->diffuse = Vector3(diffuse.r, diffuse.g, diffuse.b);
		dstMat->specular = Vector3(specular.r, specular.g, specular.b);
		dstMat->ambient = Vector3(ambient.r, ambient.g, ambient.b);
		dstMat->emissive = Vector3(emissive.r, emissive.g, emissive.b);
		dstMat->transparent = Vector3(transparent.r, transparent.g, transparent.b);
		dstMat->opacity = opacity;
		dstMat->shininess = shininess;
		dstMat->specularStrength = specularStrength;

		char *pRem = nullptr;

		strncpy_s(dstMat->texDiffusePath, "models/", Material::maxTexPath - 1);
		strncat_s(dstMat->texDiffusePath, texDiffusePath.C_Str(), Material::maxTexPath - 1);
		pRem = strrchr(dstMat->texDiffusePath, '.');
		while (pRem != nullptr && *pRem != 0) *(pRem++) = 0; // remove extension

		strncpy_s(dstMat->texSpecularPath, "models/", Material::maxTexPath - 1);
		strncat_s(dstMat->texSpecularPath, texSpecularPath.C_Str(), Material::maxTexPath - 1);
		pRem = strrchr(dstMat->texSpecularPath, '.');
		while (pRem != nullptr && *pRem != 0) *(pRem++) = 0; // remove extension

		strncpy_s(dstMat->texEmissivePath, "models/", Material::maxTexPath - 1);
		strncat_s(dstMat->texEmissivePath, texEmissivePath.C_Str(), Material::maxTexPath - 1);
		pRem = strrchr(dstMat->texEmissivePath, '.');
		while (pRem != nullptr && *pRem != 0) *(pRem++) = 0; // remove extension

		strncpy_s(dstMat->texNormalPath, "models/", Material::maxTexPath - 1);
		strncat_s(dstMat->texNormalPath, texNormalPath.C_Str(), Material::maxTexPath - 1);
		pRem = strrchr(dstMat->texNormalPath, '.');
		while (pRem != nullptr && *pRem != 0) *(pRem++) = 0; // remove extension

		strncpy_s(dstMat->texLightmapPath, "models/", Material::maxTexPath - 1);
		strncat_s(dstMat->texLightmapPath, texLightmapPath.C_Str(), Material::maxTexPath - 1);
		pRem = strrchr(dstMat->texLightmapPath, '.');
		while (pRem != nullptr && *pRem != 0) *(pRem++) = 0; // remove extension

		strncpy_s(dstMat->texReflectionPath, "models/", Material::maxTexPath - 1);
		strncat_s(dstMat->texReflectionPath, texReflectionPath.C_Str(), Material::maxTexPath - 1);
		pRem = strrchr(dstMat->texReflectionPath, '.');
		while (pRem != nullptr && *pRem != 0) *(pRem++) = 0; // remove extension

		aiString matName;
		srcMat->Get(AI_MATKEY_NAME, matName);
		strncpy_s(dstMat->name, matName.C_Str(), Material::maxMaterialName - 1);
	}

	m_Header.meshCount = scene->mNumMeshes;
	m_pMesh = new Mesh [m_Header.meshCount];
	memset(m_pMesh, 0, sizeof(Mesh) * m_Header.meshCount);
	// first pass, count everything
	for (unsigned int meshIndex = 0; meshIndex < scene->mNumMeshes; meshIndex++)
	{
		const aiMesh *srcMesh = scene->mMeshes[meshIndex];
		Mesh *dstMesh = m_pMesh + meshIndex;

		assert(srcMesh->mPrimitiveTypes == aiPrimitiveType_TRIANGLE);

		dstMesh->materialIndex = srcMesh->mMaterialIndex;

		// just store everything as float. Can quantize in Model::optimize()
		dstMesh->attribsEnabled |= attrib_mask_position;
		dstMesh->attrib[attrib_position].offset = dstMesh->vertexStride;
		dstMesh->attrib[attrib_position].normalized = 0;
		dstMesh->attrib[attrib_position].components = 3;
		dstMesh->attrib[attrib_position].format = attrib_format_float;
		dstMesh->vertexStride += sizeof(float) * 3;

		dstMesh->attribsEnabled |= attrib_mask_texcoord0;
		dstMesh->attrib[attrib_texcoord0].offset = dstMesh->vertexStride;
		dstMesh->attrib[attrib_texcoord0].normalized = 0;
		dstMesh->attrib[attrib_texcoord0].components = 2;
		dstMesh->attrib[attrib_texcoord0].format = attrib_format_float;
		dstMesh->vertexStride += sizeof(float) * 2;

		dstMesh->attribsEnabled |= attrib_mask_normal;
		dstMesh->attrib[attrib_normal].offset = dstMesh->vertexStride;
		dstMesh->attrib[attrib_normal].normalized = 0;
		dstMesh->attrib[attrib_normal].components = 3;
		dstMesh->attrib[attrib_normal].format = attrib_format_float;
		dstMesh->vertexStride += sizeof(float) * 3;

		dstMesh->attribsEnabled |= attrib_mask_tangent;
		dstMesh->attrib[attrib_tangent].offset = dstMesh->vertexStride;
		dstMesh->attrib[attrib_tangent].normalized = 0;
		dstMesh->attrib[attrib_tangent].components = 3;
		dstMesh->attrib[attrib_tangent].format = attrib_format_float;
		dstMesh->vertexStride += sizeof(float) * 3;

		dstMesh->attribsEnabled |= attrib_mask_bitangent;
		dstMesh->attrib[attrib_bitangent].offset = dstMesh->vertexStride;
		dstMesh->attrib[attrib_bitangent].normalized = 0;
		dstMesh->attrib[attrib_bitangent].components = 3;
		dstMesh->attrib[attrib_bitangent].format = attrib_format_float;
		dstMesh->vertexStride += sizeof(float) * 3;

		// depth-only
		dstMesh->attribsEnabledDepth |= attrib_mask_position;
		dstMesh->attribDepth[attrib_position].offset = dstMesh->vertexStrideDepth;
		dstMesh->attribDepth[attrib_position].normalized = 0;
		dstMesh->attribDepth[attrib_position].components = 3;
		dstMesh->attribDepth[attrib_position].format = attrib_format_float;
		dstMesh->vertexStrideDepth += sizeof(float) * 3;

		// color rendering
		dstMesh->vertexDataByteOffset = m_Header.vertexDataByteSize;
		dstMesh->vertexCount = srcMesh->mNumVertices;

		dstMesh->indexDataByteOffset = m_Header.indexDataByteSize;
		dstMesh->indexCount = srcMesh->mNumFaces * 3;

		m_Header.vertexDataByteSize += dstMesh->vertexStride * dstMesh->vertexCount;
		m_Header.indexDataByteSize += sizeof(uint16_t) * dstMesh->indexCount;

		// depth-only rendering
		dstMesh->vertexDataByteOffsetDepth = m_Header.vertexDataByteSizeDepth;
		dstMesh->vertexCountDepth = srcMesh->mNumVertices;

		m_Header.vertexDataByteSizeDepth += dstMesh->vertexStrideDepth * dstMesh->vertexCountDepth;
	}
	// allocate storage
	m_pVertexData = new unsigned char [m_Header.vertexDataByteSize];
	m_pIndexData = new unsigned char [m_Header.indexDataByteSize];
	m_pVertexDataDepth = new unsigned char [m_Header.vertexDataByteSizeDepth];
	m_pIndexDataDepth = new unsigned char [m_Header.indexDataByteSize];
	// second pass, fill in vertex and index data
	for (unsigned int meshIndex = 0; meshIndex < scene->mNumMeshes; meshIndex++)
	{
		const aiMesh *srcMesh = scene->mMeshes[meshIndex];
		Mesh *dstMesh = m_pMesh + meshIndex;

		float *dstPos = (float*)(m_pVertexData + dstMesh->vertexDataByteOffset + dstMesh->attrib[attrib_position].offset);
		float *dstTexcoord0 = (float*)(m_pVertexData + dstMesh->vertexDataByteOffset + dstMesh->attrib[attrib_texcoord0].offset);
		float *dstNormal = (float*)(m_pVertexData + dstMesh->vertexDataByteOffset + dstMesh->attrib[attrib_normal].offset);
		float *dstTangent = (float*)(m_pVertexData + dstMesh->vertexDataByteOffset + dstMesh->attrib[attrib_tangent].offset);
		float *dstBitangent = (float*)(m_pVertexData + dstMesh->vertexDataByteOffset + dstMesh->attrib[attrib_bitangent].offset);

		float *dstPosDepth = (float*)(m_pVertexDataDepth + dstMesh->vertexDataByteOffsetDepth + dstMesh->attribDepth[attrib_position].offset);

		for (unsigned int v = 0; v < dstMesh->vertexCount; v++)
		{
			if (srcMesh->mVertices)
			{
				dstPos[0] = srcMesh->mVertices[v].x;
				dstPos[1] = srcMesh->mVertices[v].y;
				dstPos[2] = srcMesh->mVertices[v].z;

				dstPosDepth[0] = srcMesh->mVertices[v].x;
				dstPosDepth[1] = srcMesh->mVertices[v].y;
				dstPosDepth[2] = srcMesh->mVertices[v].z;
			}
			else
			{
				// no position? That's kind of bad.
				assert(0);
			}
			dstPos = (float*)((unsigned char*)dstPos + dstMesh->vertexStride);
			dstPosDepth = (float*)((unsigned char*)dstPosDepth + dstMesh->vertexStrideDepth);

			if (srcMesh->mTextureCoords[0])
			{
				dstTexcoord0[0] = srcMesh->mTextureCoords[0][v].x;
				dstTexcoord0[1] = srcMesh->mTextureCoords[0][v].y;
			}
			else
			{
				dstTexcoord0[0] = 0.0f;
				dstTexcoord0[1] = 0.0f;
			}
			dstTexcoord0 = (float*)((unsigned char*)dstTexcoord0 + dstMesh->vertexStride);

			if (srcMesh->mNormals)
			{
				dstNormal[0] = srcMesh->mNormals[v].x;
				dstNormal[1] = srcMesh->mNormals[v].y;
				dstNormal[2] = srcMesh->mNormals[v].z;
			}
			else
			{
				// Assimp should generate normals if they are missing, according to the postprocessing flag specified on load,
				// so we should never get here.
				assert(0);
			}
			dstNormal = (float*)((unsigned char*)dstNormal + dstMesh->vertexStride);

			if (srcMesh->mTangents)
			{
				dstTangent[0] = srcMesh->mTangents[v].x;
				dstTangent[1] = srcMesh->mTangents[v].y;
				dstTangent[2] = srcMesh->mTangents[v].z;
			}
			else
			{
				// TODO: generate tangents/bitangents if missing
				dstTangent[0] = 1.0f;
				dstTangent[1] = 0.0f;
				dstTangent[2] = 0.0f;
			}
			dstTangent = (float*)((unsigned char*)dstTangent + dstMesh->vertexStride);

			if (srcMesh->mBitangents)
			{
				dstBitangent[0] = srcMesh->mBitangents[v].x;
				dstBitangent[1] = srcMesh->mBitangents[v].y;
				dstBitangent[2] = srcMesh->mBitangents[v].z;
			}
			else
			{
				// TODO: generate tangents/bitangents if missing
				dstBitangent[0] = 0.0f;
				dstBitangent[1] = 1.0f;
				dstBitangent[2] = 0.0f;
			}
			dstBitangent = (float*)((unsigned char*)dstBitangent + dstMesh->vertexStride);
		}

		uint16_t *dstIndex = (uint16_t*)(m_pIndexData + dstMesh->indexDataByteOffset);
		uint16_t *dstIndexDepth = (uint16_t*)(m_pIndexDataDepth + dstMesh->indexDataByteOffset);
		for (unsigned int f = 0; f < srcMesh->mNumFaces; f++)
		{
			assert(srcMesh->mFaces[f].mNumIndices == 3);

			*dstIndex++ = srcMesh->mFaces[f].mIndices[0];
			*dstIndex++ = srcMesh->mFaces[f].mIndices[1];
			*dstIndex++ = srcMesh->mFaces[f].mIndices[2];

			*dstIndexDepth++ = srcMesh->mFaces[f].mIndices[0];
			*dstIndexDepth++ = srcMesh->mFaces[f].mIndices[1];
			*dstIndexDepth++ = srcMesh->mFaces[f].mIndices[2];
		}
	}

	ComputeAllBoundingBoxes();

	return true;
}
Example #14
0
/**
* Load the model.
* Return true on success, false on failure.
**/
bool AssimpModel::load(Render3D* render, bool meshdata, AssimpLoadFlags flags)
{
	Assimp::Importer importer;

	importer.SetPropertyInteger(AI_CONFIG_PP_SBP_REMOVE, aiPrimitiveType_POINT | aiPrimitiveType_LINE);
	importer.SetPropertyInteger(AI_CONFIG_PP_RVC_FLAGS, aiComponent_COLORS | aiComponent_LIGHTS | aiComponent_CAMERAS);
	importer.SetPropertyInteger(AI_CONFIG_PP_SLM_VERTEX_LIMIT, 65535);
	importer.SetPropertyInteger(AI_CONFIG_PP_SLM_TRIANGLE_LIMIT, 65535);

	unsigned int assflags = aiProcess_CalcTangentSpace
		| aiProcess_Triangulate
		| aiProcess_JoinIdenticalVertices
		| aiProcess_SortByPType
		| aiProcess_FlipUVs
		| aiProcess_FindDegenerates
		| aiProcess_ImproveCacheLocality
		| aiProcess_RemoveComponent;

	// For map meshes we flatten geometry
	if (flags & ALM_FlattenGeometry) {
		assflags |= aiProcess_PreTransformVertices;
		assflags |= aiProcess_RemoveRedundantMaterials;
		assflags |= aiProcess_OptimizeMeshes;
		assflags |= aiProcess_FindInvalidData;
		assflags |= aiProcess_SplitLargeMeshes;
	}

	// Normally models are re-centered; this isn't always deisred.
	if (flags & ALF_NoRecenter) {
		this->recenter = false;
	}

	// Read the file from the mod
	Sint64 len;
	Uint8 * data = this->mod->loadBinary("models/" + this->name, &len);
	if (! data) {
		this->mod->setLoadErr("Failed to load %s; file read failed", this->name.c_str());
		return false;
	}

	// Check we aren't larger than size_t
	if (len > MAX_FILE_SIZE) {
		this->mod->setLoadErr("Failed to load %s; file too large", this->name.c_str());
		return false;
	}

	// Do the import
	const struct aiScene* sc = importer.ReadFileFromMemory((const void*) data, (size_t)len, assflags, this->name.c_str());
	if (!sc) {
		this->mod->setLoadErr("Failed to load %s; file read failed; %s", this->name.c_str(), importer.GetErrorString());
		return false;
	}

	free(data);

	if (debug_enabled("loadbones")) {
		cout << endl << this->name << endl;
	}

	if (render != NULL && render->is3D()) {
		this->loadMeshes(true, sc);
		this->loadMaterials(render, sc);
	} else {
		this->loadMeshes(false, sc);
	}

	if (meshdata) {
		this->loadMeshdata(render != NULL, sc);
	}

	this->loadNodes(sc);
	this->loadAnimations(sc);
	this->calcBoundingBox(sc);
	this->setBoneNodes();

	return true;
}
Example #15
0
void
Mesh::bind()
{
    Assimp::Importer importer;    

    unsigned int flags = aiProcess_Triangulate | aiProcess_JoinIdenticalVertices;
    
    if (generateVertexNormals) {
	importer.SetPropertyInteger(AI_CONFIG_PP_RVC_FLAGS, aiComponent_NORMALS);
	importer.SetPropertyFloat(AI_CONFIG_PP_GSN_MAX_SMOOTHING_ANGLE, 30.0f);
	// ignore normals in file and generate per vertex normals
	flags |= aiProcess_RemoveComponent | aiProcess_GenSmoothNormals;
    } else {
	// generate face normals if not already present in the file
	flags |= aiProcess_GenNormals;
    }
    
    const aiScene* scene = importer.ReadFile(fileName, flags);
    
    if (!scene) {
	return;
    }

    std::vector<float> vertices;
    std::vector<float> normals;
    std::vector<float> textureCoordinates;
    
    min.x = 1e38;
    min.y = 1e38;
    min.z = 1e38;
    max.x = -1e38;
    max.y = -1e38;
    max.z = -1e38;

    const struct aiNode* nd = scene->mRootNode;
    for (unsigned int n = 0; n < nd->mNumMeshes; ++n) {
	const struct aiMesh* mesh = scene->mMeshes[nd->mMeshes[n]];
	
	std::cout << "vertices: " << mesh->mNumVertices << ", faces: " << mesh->mNumFaces << std::endl;
	
	for (unsigned int t = 0; t < mesh->mNumFaces; ++t) {
	    const struct aiFace* face = &mesh->mFaces[t];
	    switch (face->mNumIndices) {
	    case 3:
		break;
	    default:
		std::cout << "ignored" << std::endl;
		continue;
	    }
	    for (unsigned int idx= 0;idx < face->mNumIndices;idx++) {
		float x = mesh->mVertices[face->mIndices[idx]].x;
		float y = mesh->mVertices[face->mIndices[idx]].y;
		float z = mesh->mVertices[face->mIndices[idx]].z;
		float nx = mesh->mNormals[face->mIndices[idx]].x;
		float ny = mesh->mNormals[face->mIndices[idx]].y;
		float nz = mesh->mNormals[face->mIndices[idx]].z;

		if (x < min.x) {
		    min.x = x;
		}
		if (y < min.y) {
		    min.y = y;
		}
		if (z < min.z) {
		    min.z = z;
		}
		if (x > max.x) {
		    max.x = x;
		}
		if (y > max.y) {
		    max.y = y;
		}
		if (z > max.z) {
		    max.z = z;
		}
		vertices.push_back(x);
		vertices.push_back(y);
		vertices.push_back(z);
		vertices.push_back(1.0f);
		normals.push_back(nx);
		normals.push_back(ny);
		normals.push_back(nz);
		normals.push_back(0.0f);
		textureCoordinates.push_back(x / 8);
		textureCoordinates.push_back(z / 8);
	    }
	}
    }

    std::cout << "bounding box: min = "
	    << min.x << ", " << min.y << ", " << min.z
	    << " - max = "
	    << max.x << ", " << max.y << ", " << max.z
	    << std::endl;
 
//    vertices.clear();
//    normals.clear();
//    quad(vertices, normals, 0, 1, 2, 3);
//    quad(vertices, normals, 0, 4, 5, 1);
//    quad(vertices, normals, 1, 5, 6, 2);
//    quad(vertices, normals, 2, 6, 7, 3);
//    quad(vertices, normals, 3, 7, 4, 0);
//    quad(vertices, normals, 4, 7, 6, 5);
    
    count = vertices.size();

    glGenBuffers(1, &vertexBuffer);
    glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
    glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(float), &vertices[0], GL_STATIC_DRAW);

    glGenBuffers(1, &normalBuffer);
    glBindBuffer(GL_ARRAY_BUFFER, normalBuffer);
    glBufferData(GL_ARRAY_BUFFER, normals.size() * sizeof(float), &normals[0], GL_STATIC_DRAW);

    glGenBuffers(1, &textureBuffer);
    glBindBuffer(GL_ARRAY_BUFFER, textureBuffer);
    glBufferData(GL_ARRAY_BUFFER, textureCoordinates.size() * sizeof(float), &textureCoordinates[0], GL_STATIC_DRAW);
}
Example #16
0
bool StaticMesh::loadFromFile(const std::string& infile)
{
    Assimp::Importer imp;

    // Load scene and grab first mesh only
    imp.SetPropertyInteger(AI_CONFIG_PP_SBP_REMOVE,
                           aiPrimitiveType_LINE |
                           aiPrimitiveType_POINT |
                           aiPrimitiveType_POLYGON, nullptr);

    #ifdef DEBUG
    std::cout << "Calling Assimp::Importer::ReadFile...\n";
    #endif // DEBUG

    const aiScene *scene = imp.ReadFile(infile, aiProcessPreset_TargetRealtime_Quality
                                                & (!aiProcess_SplitLargeMeshes));
    #ifdef DEBUG
    std::cout << "Checking for a mesh...\n";
    #endif // DEBUG
    if(scene == nullptr)
        return false;
    else if(!scene->HasMeshes())
        return false;

    imp.ApplyPostProcessing(aiProcess_JoinIdenticalVertices);

    // Will only load one mesh
    const aiMesh *mesh = scene->mMeshes[0];

    #ifdef DEBUG
    std::cout << "Checking mesh has what we need...\n";
    #endif // DEBUG
    // Don't process special mesh types
    if(!mesh->HasPositions() ||
       !mesh->HasFaces())
        return false;

    vertexCount = mesh->mNumVertices;
    triangleCount = mesh->mNumFaces;

    // Check what attributes are in the mesh and
    // calculate total count of floats
    std::size_t componentCount = components.vertex = 3;
    if(mesh->HasNormals())
    {
        componentCount += components.normal = 3;
        #ifdef DEBUG
        std::cout << "Has normals\n";
        #endif // DEBUG
    }
    if(mesh->HasTangentsAndBitangents())
    {
        componentCount += (components.tangentBitangent = 3) * 2;
        #ifdef DEBUG
        std::cout << "Has tangents and bitangents\n";
        #endif // DEBUG
    }
    if(mesh->HasTextureCoords(0))
    {
        componentCount += components.texture = 3;
        #ifdef DEBUG
        std::cout << "Has texture coordinates\n";
        #endif // DEBUG
    }

    // Scale size for size of float
    std::size_t totalSize = componentCount * sizeof(float) * vertexCount;

    #ifdef DEBUG
    std::cout << totalSize << std::endl;
    std::cout << "Allocating and mapping vertex buffer...\n";
    #endif // DEBUG

    // Set size and map buffer
    glBindBuffer(GL_ARRAY_BUFFER, buffer);
    glBufferData(GL_ARRAY_BUFFER, totalSize, nullptr, GL_STATIC_DRAW);
    GLfloat *mapPtr = (GLfloat*) glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
//    glNamedBufferDataEXT(buffer, totalSize, nullptr, GL_STATIC_DRAW);
//    GLfloat *mapPtr = (GLfloat*) glMapNamedBufferEXT(buffer, GL_WRITE_ONLY);
    if(mapPtr == nullptr)
        return false;

    #ifdef DEBUG
    std::cout << "Worked!\n";
    #endif // DEBUG

    // Load all attributes into mapped buffer
    for(unsigned int i = 0; i < vertexCount; ++i)
    {
        GLfloat *head = mapPtr + i * componentCount;

        *head++ = mesh->mVertices[i].x;
        *head++ = mesh->mVertices[i].y;
        *head++ = mesh->mVertices[i].z;

        if(mesh->HasNormals())
        {
            *head++ = mesh->mNormals[i].x;
            *head++ = mesh->mNormals[i].y;
            *head++ = mesh->mNormals[i].z;
        }
        if(mesh->HasTextureCoords(0))
        {
            *head++ = mesh->mTextureCoords[0][i].x;
            *head++ = mesh->mTextureCoords[0][i].y;
            *head++ = mesh->mTextureCoords[0][i].z;
        }
        if(mesh->HasTangentsAndBitangents())
        {
            *head++ = mesh->mTangents[i].x;
            *head++ = mesh->mTangents[i].y;
            *head++ = mesh->mTangents[i].z;
            *head++ = mesh->mBitangents[i].x;
            *head++ = mesh->mBitangents[i].y;
            *head++ = mesh->mBitangents[i].z;
        }
    }

    if(!glUnmapBuffer(GL_ARRAY_BUFFER))
        return false;

    #ifdef DEBUG
    std::cout << "Allocating and mapping index buffer...\n";
    #endif // DEBUG

    // Same for index buffer
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indices);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, triangleCount*3*sizeof(GLshort), nullptr, GL_STATIC_DRAW);
    GLushort *indexMapPtr = (GLushort*) glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY);
//    glNamedBufferDataEXT(indices, triangleCount * 3 * sizeof(GLushort), nullptr, GL_STATIC_DRAW);
//    GLushort *indexMapPtr = (GLushort*) glMapNamedBufferEXT(indices, GL_WRITE_ONLY);
    if(indexMapPtr == nullptr)
        return false;

    #ifdef DEBUG
    std::cout << "Worked!\n";
    #endif // DEBUG

    for(unsigned int i = 0; i < triangleCount; ++i)
    {
        #ifdef DEBUG
        assert(mesh->mFaces[i].mNumIndices == 3);
        #endif // DEBUG
        unsigned int *indexArray = mesh->mFaces[i].mIndices;
        for(unsigned int j = 0; j < 3; ++j)
        {
            #ifdef DEBUG
            assert(*indexArray <= std::numeric_limits<GLushort>::max());
            #endif // DEBUG
            *indexMapPtr++ = *indexArray++;
        }
    }

    if(!glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER))
        return false;;

    #ifdef DEBUG
    std::cout << "Loading mesh successful!\n";
    std::cout << "Setting up vertex array...\n";
    #endif // DEBUG

    glBindVertexArray(vertexArray);

    glBindVertexBuffer(0, buffer, 0, (components.vertex +
                                      components.normal +
                                      components.texture +
                                      components.tangentBitangent * 2)
                                        * sizeof(GLfloat));
    glVertexAttribFormat(0, 3, GL_FLOAT, GL_FALSE, 0);
    glVertexAttribBinding(0, 0);
    glEnableVertexAttribArray(0);

    if(components.normal)
    {
        glVertexAttribFormat(1, 3, GL_FLOAT, GL_FALSE, components.vertex * sizeof(float));
        glVertexAttribBinding(1, 0);
        glEnableVertexAttribArray(1);
    }
    if(components.texture)
    {
        glVertexAttribFormat(2, 3, GL_FLOAT, GL_FALSE, (components.vertex +
                                                        components.normal) * sizeof(float));
        glVertexAttribBinding(2, 0);
        glEnableVertexAttribArray(2);
    }
    if(components.tangentBitangent)
    {
        glVertexAttribFormat(3, 3, GL_FLOAT, GL_FALSE, (components.vertex +
                                                        components.normal +
                                                        components.texture) * sizeof(float));
        glVertexAttribBinding(3, 0);
        glEnableVertexAttribArray(3);

        glVertexAttribFormat(4, 3, GL_FLOAT, GL_FALSE, (components.vertex +
                                                        components.normal +
                                                        components.texture +
                                                        components.tangentBitangent) * sizeof(float));
        glVertexAttribBinding(4, 0);
        glEnableVertexAttribArray(4);
    }

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indices);

    glBindVertexArray(0);

    #ifdef DEBUG
    std::cout << vertexCount << ' ' << triangleCount << std::endl;
    std::cout << +components.vertex << ' ';
    std::cout << +components.normal << ' ';
    std::cout << +components.texture << ' ';
    std::cout << +components.tangentBitangent << std::endl;
    #endif // DEBUG

    return true;
}
bool NvSimpleMeshLoader::LoadFile(LPWSTR szFilename)
{
    bool bLoaded = false;
    (void)bLoaded;

    // Create a logger instance 
    Assimp::DefaultLogger::create("",Logger::VERBOSE);

    // Create an instance of the Importer class
    Assimp::Importer importer;

    CHAR szFilenameA[MAX_PATH];
    WideCharToMultiByte(CP_ACP,0,szFilename,MAX_PATH,szFilenameA,MAX_PATH,NULL,false);

    mediaPath = szFilenameA;
    auto index = mediaPath.find_last_of('\\');
    if(index != -1)
        mediaPath = mediaPath.substr(0,index) + "\\";
    else
        mediaPath = ".\\";

    // Set some flags for the removal of various data that we don't use
    importer.SetPropertyInteger("AI_CONFIG_PP_RVC_FLAGS",aiComponent_ANIMATIONS | aiComponent_BONEWEIGHTS | aiComponent_COLORS | aiComponent_LIGHTS | aiComponent_CAMERAS);
    //importer.SetPropertyInteger("AI_CONFIG_PP_SBP_REMOVE",aiPrimitiveType_POINTS | aiPrimitiveType_LINES );

    // load the scene and preprocess it into the form we want
    const aiScene *scene = importer.ReadFile(szFilenameA,
                                                aiProcess_Triangulate|    // only higher order primitives will be triangulated
                                                aiProcess_GenNormals|    // if normals exist, will not be generated
                                                aiProcess_CalcTangentSpace|
                                                aiProcess_PreTransformVertices| // rolls all node hierarchy(if existant) into the local space of meshes
                                                //aiProcess_RemoveRedundantMaterials|
                                                //aiProcess_FixInfacingNormals|
                                                aiProcess_FindDegenerates|
                                                aiProcess_SortByPType|
                                                aiProcess_RemoveComponent|    // processes the above flags set to remove data we don't want
                                                aiProcess_FindInvalidData|
                                                aiProcess_GenUVCoords|
                                                aiProcess_TransformUVCoords|
                                                aiProcess_OptimizeMeshes |

                                                aiProcessPreset_TargetRealtime_Quality
                                                );

    // can't load?
    if(!scene)
        return false;

    if(scene->HasMeshes())
    {
        pMeshes = new NvSimpleRawMesh[scene->mNumMeshes];
        NumMeshes = scene->mNumMeshes;

        D3DXMATRIX mIdentity;
        D3DXMatrixIdentity(&mIdentity);

        RecurseAddMeshes(scene,scene->mRootNode,&mIdentity,true);
    }

    // cleanup
    Assimp::DefaultLogger::kill();

    return NumMeshes > 0;
}
Example #18
0
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;
}
Example #19
0
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_ERROR, "'%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;

	// Create a logger for debugging model loading issues
	Assimp::DefaultLogger::create("", Assimp::Logger::VERBOSE);
	Assimp::DefaultLogger::get()->attachStream(new AssLogStream(), ASS_LOGGING_OPTIONS);

	// 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
	{
		// Optimize VBO-Mesh sizes/ranges
		GLint maxIndices  = 1024;
		GLint maxVertices = 1024;
		// FIXME returns non-optimal data, at best compute it ourselves (pre-TL cache size!)
		glGetIntegerv(GL_MAX_ELEMENTS_INDICES,  &maxIndices);
		glGetIntegerv(GL_MAX_ELEMENTS_VERTICES, &maxVertices);
		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;
	{
		// ASSIMP spams many SIGFPEs atm in normal & tangent generation
		ScopedDisableFpuExceptions fe;
		scene = importer.ReadFile(modelFilePath, ASS_POSTPROCESS_OPTIONS);
	}

	if (scene != NULL) {
		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()));
	}

	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->tex1.c_str(), model->tex2.c_str());
	texturehandlerS3O->LoadS3OTexture(model);

	// 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);

	// Update piece hierarchy based on metadata
	BuildPieceHierarchy(model);
	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->drawRadius: %f", model->drawRadius);
	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;
}
Example #20
0
//! Loads and returns a skinned model from a file.
SkinnedModel* ModelImporter::LoadSkinnedModel(string filename)
{
	// Is the model already loaded?
	if(mSkinnedModelMap.find(filename) != mSkinnedModelMap.end())
		return mSkinnedModelMap[filename];

	Assimp::Importer importer;
	mFilename =	filename;
	SkinnedModel* model = NULL;

	// Important! Makes sure that if the angle between two face normals is > 80 they are not smoothed together.
	// Since the angle between a cubes face normals is 90 the lighting looks very bad if we don't specify this.
	importer.SetPropertyFloat(AI_CONFIG_PP_GSN_MAX_SMOOTHING_ANGLE, 80.0f);	
	importer.SetPropertyInteger(AI_CONFIG_IMPORT_TER_MAKE_UVS, 1);
	importer.SetPropertyInteger(AI_CONFIG_PP_SBP_REMOVE, aiPrimitiveType_LINE);

	// Load scene from the file.
	const aiScene* scene = importer.ReadFile(filename, 
		aiProcess_CalcTangentSpace | 
		aiProcess_Triangulate | 
		aiProcess_GenSmoothNormals | 
		aiProcess_SplitLargeMeshes | 
		aiProcess_ConvertToLeftHanded | 
		aiProcess_SortByPType);

	if(scene)
	{
		// Create the model that is getting filled out.
		model = new SkinnedModel();

		// Create the animator.
		SceneAnimator* animator = new SceneAnimator();
		animator->Init(scene);
		model->SetAnimator(animator);

		// Loop through all meshes.
		for(int j = 0; j < scene->mNumMeshes; j++)
		{
			aiMesh* assimpMesh = scene->mMeshes[j];

			// Calculate vertex weight and bone indices.
			vector<Weights> weights = CalculateWeights(assimpMesh, animator);

			vector<SkinnedVertex> vertices;
			vector<UINT> indices;

			// Add vertices to the vertex list.
			for(int i = 0; i < assimpMesh->mNumVertices; i++) 
			{
				aiVector3D v = assimpMesh->mVertices[i];
				aiVector3D n = assimpMesh->mNormals[i];
				aiVector3D t = aiVector3D(0, 0, 0);
				if(assimpMesh->HasTextureCoords(0))
					t = assimpMesh->mTextureCoords[0][i];

				n = n.Normalize();

				// Pos, normal and texture coordinates.
				SkinnedVertex vertex(v.x, v.y, v.z, n.x, n.y, n.z, 0, 0, 1, t.x, t.y);

				// Bone indices and weights.
				for(int k = 0; k < weights[i].boneIndices.size(); k++) 
					vertex.BoneIndices[k] = weights[i].boneIndices[k];

				vertex.Weights.x = weights[i].weights.size() >= 1 ? weights[i].weights[0] : 0;
				vertex.Weights.y = weights[i].weights.size() >= 2 ? weights[i].weights[1] : 0;
				vertex.Weights.z = weights[i].weights.size() >= 3 ? weights[i].weights[2] : 0;

				vertices.push_back(vertex);
			}

			// Add indices to the index list.
			for(int i = 0; i < assimpMesh->mNumFaces; i++) 
				for(int k = 0; k < assimpMesh->mFaces[i].mNumIndices; k++) 
					indices.push_back(assimpMesh->mFaces[i].mIndices[k]);

			// Get the path to the texture in the directory.
			aiString path;
			aiMaterial* material = scene->mMaterials[assimpMesh->mMaterialIndex];
			material->Get(AI_MATKEY_TEXTURE_DIFFUSE(0), path);
			FindValidPath(&path);

			// Extract all the ambient, diffuse and specular colors.
			aiColor4D ambient, diffuse, specular;
			material->Get(AI_MATKEY_COLOR_AMBIENT, ambient);
			material->Get(AI_MATKEY_COLOR_DIFFUSE, diffuse);
			material->Get(AI_MATKEY_COLOR_SPECULAR, specular);
				
			// Create the mesh and its primitive.
			SkinnedMesh* mesh = new SkinnedMesh();

			Primitive* primitive = new Primitive(GlobalApp::GetD3DDevice(), vertices, indices);
			mesh->SetPrimitive(primitive);
			mesh->SetVertices(vertices);
			mesh->SetIndices(indices);
			mPrimtiveFactory->AddPrimitive(path.C_Str(), primitive);

			// Replace .tga with .bmp [HACK].
			string texturePath = path.C_Str();
			int tgaPos = texturePath.find_first_of(".tga");
			if(tgaPos != string::npos) {
				texturePath.replace(texturePath.size()-4, 4, ".bmp");
				path = texturePath;
			}

			// Any texture?
			if(_stricmp(path.C_Str(), "") != 0)
				mesh->LoadTexture(path.C_Str());

			// Any normal map?
			aiString nmap;
			material->Get(AI_MATKEY_TEXTURE_HEIGHT(0), nmap);
			FindValidPath(&nmap);
			if(_stricmp(nmap.C_Str(), "") != 0)	
				mesh->SetNormalMap(GlobalApp::GetGraphics()->LoadTexture(nmap.C_Str()));

			// [NOTE] The material is set to white.
			mesh->SetMaterial(Material(Colors::White));
			//mesh->SetMaterial(Material(diffuse, diffuse, diffuse));

			model->SetFilename(filename);

			// Add the mesh to the model.
			model->AddMesh(mesh);
		}

		// Pre-calculate the bounding box.
		model->CalculateAABB();

		// Add the newly created mesh to the map and return it.
		mSkinnedModelMap[filename] = model;
		return mSkinnedModelMap[filename];
	}
	else {
		char buffer[246];
		sprintf(buffer, "Error loading model: %s", filename.c_str());
		MessageBox(0, buffer, "Error!", 0);
		mSkinnedModelMap[filename] = LoadSkinnedModel("models/box.obj");
		return mSkinnedModelMap[filename];
	}
}
Example #21
0
//! Loads and returns a static model from a file.
StaticModel* ModelImporter::LoadStaticModel(string filename)
{
	// Is the model already loaded?
	if(mStaticModelMap.find(filename) != mStaticModelMap.end())
		return mStaticModelMap[filename];

	Assimp::Importer importer;
	mFilename =	filename;
	StaticModel* model = NULL;

	// Important! Makes sure that if the angle between two face normals is > 80 they are not smoothed together.
	// Since the angle between a cubes face normals is 90 the lighting looks very bad if we don't specify this.
	importer.SetPropertyFloat(AI_CONFIG_PP_GSN_MAX_SMOOTHING_ANGLE, 80.0f);	
	importer.SetPropertyInteger(AI_CONFIG_IMPORT_TER_MAKE_UVS, 1);
	importer.SetPropertyInteger(AI_CONFIG_PP_SBP_REMOVE, aiPrimitiveType_LINE);

	// Load scene from the file.
	const aiScene* scene = importer.ReadFile(filename, 
		aiProcess_CalcTangentSpace		| 
		aiProcess_Triangulate			| 
		aiProcess_GenSmoothNormals		|
		aiProcess_SplitLargeMeshes		|
		aiProcess_ConvertToLeftHanded	|
		aiProcess_SortByPType);

	// Successfully loaded the scene.
	if(scene)
	{
		// Create the model that is getting filled out.
		model = new StaticModel();

		// Loop through all meshes.
		for(int i = 0; i < scene->mNumMeshes; i++)
		{
			aiMesh* assimpMesh = scene->mMeshes[i];
			vector<Vertex>	vertices;
			vector<UINT>	indices;

			// Add vertices to the vertex list.
			for(int i = 0; i < assimpMesh->mNumVertices; i++) 
			{
				aiVector3D v = assimpMesh->mVertices[i];
				aiVector3D n = assimpMesh->mNormals[i];
				aiVector3D t = aiVector3D(0, 0, 0);
				if(assimpMesh->HasTextureCoords(0))
					t = assimpMesh->mTextureCoords[0][i];

				n = n.Normalize();
				Vertex vertex(v.x, v.y, v.z, n.x, n.y, n.z, 0, 0, 0, t.x, t.y);
				vertices.push_back(vertex);
			}

			// Add indices to the index list.
			for(int i = 0; i < assimpMesh->mNumFaces; i++) 
				for(int j = 0; j < assimpMesh->mFaces[i].mNumIndices; j++) 
					indices.push_back(assimpMesh->mFaces[i].mIndices[j]);

			// Get the path to the texture in the directory.
			aiString path;
			aiMaterial* material = scene->mMaterials[assimpMesh->mMaterialIndex];
			material->Get(AI_MATKEY_TEXTURE_DIFFUSE(0), path);
			FindValidPath(&path);

			// Extract all the ambient, diffuse and specular colors.
			aiColor4D ambient, diffuse, specular;
			material->Get(AI_MATKEY_COLOR_AMBIENT, ambient);
			material->Get(AI_MATKEY_COLOR_DIFFUSE, diffuse);
			material->Get(AI_MATKEY_COLOR_SPECULAR, specular);

			// Create the mesh and its primitive.
			StaticMesh* mesh = new StaticMesh();
			Primitive* primitive = new Primitive(GlobalApp::GetD3DDevice(), vertices, indices);
			mesh->SetPrimitive(primitive);
			mesh->SetVertices(vertices);
			mesh->SetIndices(indices);
			mPrimtiveFactory->AddPrimitive(path.C_Str(), primitive);

			// Any texture?
			if(_stricmp(path.C_Str(), "") != 0)
				mesh->LoadTexture(path.C_Str());

			// Any normal map?
			aiString nmap;
			material->Get(AI_MATKEY_TEXTURE_HEIGHT(0), nmap);
			FindValidPath(&nmap);
			if(_stricmp(nmap.C_Str(), "") != 0)	
				mesh->SetNormalMap(GlobalApp::GetGraphics()->LoadTexture(nmap.C_Str()));

			// [NOTE] The material is set to white.
			mesh->SetMaterial(Material(Colors::White)); // Was  before [NOTE]

			model->SetFilename(filename);

			// Add the mesh to the model.
			model->AddMesh(mesh);
		}

		// Add to the model map and return it.
		mStaticModelMap[filename] = model;
		return mStaticModelMap[filename];
	}
	else {
		char buffer[246];
		sprintf(buffer, "Error loading model: %s", filename.c_str());
		MessageBox(0, buffer, "Error!", 0);
		mStaticModelMap[filename] = LoadStaticModel("models/box.obj");
		return mStaticModelMap[filename];
	}
}
void ManageAnimation::Init(const char *filename, float xRotateCorrection, bool normalize) {
	this->fRotateXCorrection = xRotateCorrection;
	// Create an instance of the Importer class
	Assimp::Importer importer;

	unsigned int flags = aiProcess_JoinIdenticalVertices|aiProcess_Triangulate|aiProcess_FixInfacingNormals|aiProcess_ValidateDataStructure|
	                     aiProcess_GenNormals|aiProcess_LimitBoneWeights;
	// |aiProcess_OptimizeMeshes
	if (normalize)
		flags |= aiProcess_PreTransformVertices; // This flag will remove all bones.
	importer.SetPropertyBool(AI_CONFIG_PP_PTV_NORMALIZE, true); // TODO: This is only used for aiProcess_PreTransformVertices
	importer.SetPropertyInteger(AI_CONFIG_PP_LBW_MAX_WEIGHTS, 3); // The shader can only handle three weights for each vertice.
	const aiScene* scene = importer.ReadFile( filename, flags);
	if (scene == 0) {
		ErrorDialog("assimp loading %s: %s\n", filename, importer.GetErrorString());
		return;
	}

	// Number of vertices and number of indices
	int vertexSize = 0, indexSize = 0;
	if (gVerbose) {
		printf("\nScene: %s (%s)*******************\n", scene->mRootNode->mName.data, filename);
		printf("%d materials, %d meshes, %d animations, %d textures\n", scene->mNumMaterials, scene->mNumMeshes, scene->mNumAnimations, scene->mNumTextures);
	}

	//**********************************************************************
	// Count how much data is needed. All indices and vetices are saved in
	// the same buffer.
	//**********************************************************************

	fMeshData.reset(new Mesh[scene->mNumMeshes]);
	fNumMeshes = scene->mNumMeshes;
	for (unsigned int i=0; i<scene->mNumMeshes; i++) {
		aiMesh *m = scene->mMeshes[i];
		if (m->mNumBones > 0)
			this->fUsingBones = true; // True if any mesh uses bones
		aiMaterial *mat = scene->mMaterials[m->mMaterialIndex];
		aiColor3D c (0.f,0.f,0.f);
		mat->Get(AI_MATKEY_COLOR_DIFFUSE, c);
		fMeshData[i].colour = glm::vec4(c.r, c.g, c.b, 1.0f);
		indexSize += m->mNumFaces * 3; // Always 3 indices for each face (triangle).
		vertexSize += m->mNumVertices;
		if (gVerbose)
			printf("\tMesh %d ('%s'): %d faces, %d vertices\n", i, m->mName.data, m->mNumFaces, m->mNumVertices);

		// Find all animation bones in all meshes. They may have been seen in another mesh already.
		fMeshData[i].bones.resize(m->mNumBones);
		for (unsigned int j=0; j < m->mNumBones; j++) {
			aiBone *aib = m->mBones[j];
			// Add the bone to the global list of bones if it isn't already there.
			boneindexIT_t it = fBoneIndex.find(aib->mName.data);
			unsigned int jointIndex = fBoneIndex.size();
			if (it == fBoneIndex.end())
				fBoneIndex[aib->mName.data] = jointIndex;
			else
				jointIndex = it->second;

			fMeshData[i].bones[j].jointIndex = jointIndex;
			CopyaiMat(&aib->mOffsetMatrix, fMeshData[i].bones[j].offset);
		}
	}
	if (gVerbose)
		printf("Total vertices needed: %d, index count %d\n", vertexSize, indexSize);

	// Find all mesh transformations and update the bones matrix dependency on parents
	glm::mat4 meshmatrix[scene->mNumMeshes];
	FindMeshTransformations(0, meshmatrix, glm::mat4(1), scene->mRootNode);
	if (gVerbose)
		DumpNodeTree(0, scene->mRootNode);

	// Copy all vertex data into one big buffer and all index data into another buffer
	VertexDataf vertexData[vertexSize];
	unsigned short indexData[indexSize];
	int vertexOffset = 0, indexOffset = 0;
	int previousOffset = 0; // The index offset for the current mesh

	// Skinning data. Allocate even if not using bones.
	char numWeights[vertexSize];
	memset(numWeights, 0, sizeof numWeights);
	glm::vec3 weights[vertexSize];
	float joints[vertexSize*3]; // Up to 4 joints per vertex, but only three are used.
	memset(joints, 0, sizeof joints);

	//**********************************************************************
	// Traverse the meshes again, generating the vertex data
	//**********************************************************************

	for (unsigned int i=0; i<scene->mNumMeshes; i++) {
		aiMesh *m = scene->mMeshes[i];
		if (gVerbose)
			printf("Mesh %d: %d faces, %d vertices, mtl index %d\n", i, m->mNumFaces, m->mNumVertices, m->mMaterialIndex);
#if 1
		if (gVerbose) {
#if 0
			printf("Indices:\n");
			for (unsigned int face=0; face < m->mNumFaces; face++) {
				printf("%d:(", m->mFaces[face].mNumIndices);
				for (unsigned int ind=0; ind < m->mFaces[face].mNumIndices; ind++)
					printf("%d,", m->mFaces[face].mIndices[ind]);
				printf("),");
			}
			printf("\nVertices:\n");
			for (unsigned int vert=0; vert < m->mNumVertices; vert++)
				printf("%6.3f %6.3f %6.3f\n", m->mVertices[vert].x, m->mVertices[vert].y, m->mVertices[vert].z);
#endif
			printf("    Transformation matrix:\n");
			PrintMatrix(4, meshmatrix[i]);
			printf("\n");
		}
#endif

		// Copy faces, but only those that are proper triangles.
		unsigned int numTriangles = 0; // The number of found triangles.
		for (unsigned int face=0; face < m->mNumFaces; face++) {
			if (m->mFaces[face].mNumIndices != 3)
				continue; // Only allow triangles
			// m->mFaces[face].mIndices is a local index into the current mesh. Value 0 will thus
			// adress the first vertex in the current mesh. As all vertices are stored in the same buffer,
			// an offset need to be added to get the correct index of the vertex.
			indexData[indexOffset++] = m->mFaces[face].mIndices[0] + previousOffset;
			indexData[indexOffset++] = m->mFaces[face].mIndices[1] + previousOffset;
			indexData[indexOffset++] = m->mFaces[face].mIndices[2] + previousOffset;
			numTriangles++;
		}
		fMeshData[i].numFaces = numTriangles;

		// Copy all vertices
		for (unsigned int v = 0; v < m->mNumVertices; v++) {
			glm::vec4 v1(m->mVertices[v].x, m->mVertices[v].y, m->mVertices[v].z, 1);
			glm::vec4 v2 = meshmatrix[i] * v1;
			vertexData[vertexOffset].SetVertex(glm::vec3(v2));
			glm::vec4 n1(m->mNormals[v].x, m->mNormals[v].y, m->mNormals[v].z, 1);
			glm::vec4 n2 = meshmatrix[i] * glm::normalize(n1);
			vertexData[vertexOffset].SetNormal(glm::vec3(n2));
			if (m->mTextureCoords[0] != 0) {
				vertexData[vertexOffset].SetTexture(m->mTextureCoords[0][v].x, m->mTextureCoords[0][v].y);
			} else {
				vertexData[vertexOffset].SetTexture(0,0);
			}
			vertexData[vertexOffset].SetIntensity(255);
			vertexData[vertexOffset].SetAmbient(100);
			vertexOffset++;
		}

		// Every animation bone in Assimp data structures have a list of weights and vertex index.
		// We want the weights, 0-3 of them, sorted on vertices instead.
		// Iterate through all bones used in this mesh, and copy weights to respective vertex data.
		for (unsigned j=0; j < m->mNumBones; j++) {
			fMeshData[i].bones[j].offset *= glm::inverse(meshmatrix[i]);
			aiBone *aib = m->mBones[j];
			boneindexIT_t it = fBoneIndex.find(aib->mName.data);
			if (it == fBoneIndex.end())
				ErrorDialog("Mesh %d bone %s not found", i, aib->mName.data);
			if (gVerbose) {
				printf("    Offset for mesh %d %s (%d) joint %d:\n", i, aib->mName.data, j, it->second);
				PrintMatrix(4, fMeshData[i].bones[j].offset);
			}
			for (unsigned k=0; k < aib->mNumWeights; k++) {
				int v = aib->mWeights[k].mVertexId + previousOffset; // Add the local vertex number in the current mesh to the offset to get the global number
				int w = numWeights[v]++;
				// Because AI_CONFIG_PP_LBW_MAX_WEIGHTS is maximized to 3, There can't be more than 3 weights for a vertex
				// unless there is a bug in Assimp.
				if (w >= 3)
					ErrorDialog("Too many bone weights on vertice %d, bone %s, model %s", v, aib->mName.data, filename);
				weights[v][w] = aib->mWeights[k].mWeight;
				joints[v*3 + w] = it->second;
			}
		}
		previousOffset = vertexOffset;
	}

	// Now that the weights are sorted on vertices, it is possible to normalize them. The sum shall be 1.
	for (int j=0; j < vertexSize; j++)
		NormalizeWeights(weights[j], numWeights[j]);
	ASSERT(vertexOffset == vertexSize);
	ASSERT(indexOffset <= indexSize);

	// Allocated the vertex data in OpenGL. The buffer object is used with the following layout:
	// 1. The usual vertex data, and array of type VertexDataf
	// 2. Skin weights, array of glm::vec3. 3 floats for each vertex.
	// 3. Bones index, 4 bytes for each vertex (only 3 used)
	const int AREA1 = vertexSize*sizeof vertexData[0];
	const int AREA2 = vertexSize*sizeof weights[0];
	const int AREA3 = vertexSize*3*sizeof (float);
	int bufferSize = AREA1;
	if (fUsingBones) {
		// Also need space for weights and bones indices.
		bufferSize += AREA2 + AREA3;
	}
	// Allocate the buffer, random content so far
	if (!fOpenglBuffer.BindArray(bufferSize, 0)) {
		ErrorDialog("ManageAnimation::Init: Data size is mismatch with input array\n");
	}
	fOpenglBuffer.ArraySubData(0, AREA1, vertexData);
	if (this->fUsingBones) {
		glBufferSubData(GL_ARRAY_BUFFER, AREA1, AREA2, weights);
		glBufferSubData(GL_ARRAY_BUFFER, AREA1+AREA2, AREA3, joints);
	}

	glGenVertexArrays(1, &fVao);
	glBindVertexArray(fVao);
	StageOneShader::EnableVertexAttribArray(this->fUsingBones); // Will be remembered in the VAO state
	// Allocate the index data in OpenGL
	if (!fIndexBuffer.BindElementsArray(indexSize*sizeof indexData[0], indexData)) {
		ErrorDialog("ManageAnimation::Init: Data size is mismatch with input array\n");
	}
	StageOneShader::VertexAttribPointer();
	if (this->fUsingBones)
		StageOneShader::VertexAttribPointerSkinWeights(AREA1, AREA1+AREA2);
	checkError("ManageAnimation::Init");
	glBindVertexArray(0);

	if (gVerbose) {
		printf("Mesh bones for '%s':\n", filename);
		for (auto &bone : fBoneIndex) {
			printf(" %s: joint %d\n", bone.first.c_str(), bone.second);
		}
	}

	// Decode animation information
	unsigned int numMeshBones = fBoneIndex.size();
	if (numMeshBones > 0 && scene->mNumAnimations == 0)
		ErrorDialog("ManageAnimation::Init %s: Bones but no animations", filename);
	if (scene->mNumAnimations > 0) {
		if (numMeshBones == 0)
			ErrorDialog("ManageAnimation::Init %s: No mesh bones", filename);
		if (gVerbose)
			printf("Parsing %d animations\n", scene->mNumAnimations);
	}

	//**********************************************************************
	// Decode the animations
	// There may be more animated bones than used by meshes.
	//**********************************************************************
	fAnimations.reset(new Animation[scene->mNumAnimations]);
	for (unsigned int i=0; i < scene->mNumAnimations; i++) {
		aiAnimation *aia = scene->mAnimations[i];
		fAnimations[i].name = aia->mName.data;
		fAnimations[i].keysPerSecond = aia->mTicksPerSecond;
		fAnimations[i].duration = aia->mDuration;

		// Set the size of bones to the actual nutmber of bones used by the meshes, not the total number of bones
		// in the model.
		fAnimations[i].bones.reset(new AnimationBone[numMeshBones]);

		// The number of keys has to be the same for all channels. This is a limitation if it is going to be possible to
		// pre compute all matrices.
		unsigned numChannels = aia->mNumChannels;
		if (numChannels == 0)
			ErrorDialog("ManageAnimation::Init no animation channels for %s, %s", aia->mName.data, filename);
		if (numChannels != numMeshBones)
			ErrorDialog("ManageAnimation::Init %s animation %d: Can only handle when all bones are used (%d out of %d)", filename, i, numChannels, numMeshBones);
		unsigned int numKeys = aia->mChannels[0]->mNumPositionKeys;
		struct channel {
			glm::mat4 mat; // Relative transformation matrix to parent
			channel *parent;
			aiNodeAnim *node;
			unsigned joint;
#define UNUSEDCHANNEL 0xFFFF
		};
		channel channels[numChannels]; // This is the list of all bones in this animation
		// Check that there are the same number of keys for all channels, and allocate transformation matrices
		bool foundOneBone = false;
		for (unsigned int j=0; j < numChannels; j++) {
			aiNodeAnim *ain = aia->mChannels[j];
			if (ain->mNumPositionKeys != numKeys || ain->mNumRotationKeys != numKeys || ain->mNumScalingKeys != numKeys)
				ErrorDialog("ManageAnimation::Init %s Bad animation setup: Pos keys %d, rot keys %d, scaling keys %d", filename, ain->mNumPositionKeys, ain->mNumRotationKeys, ain->mNumScalingKeys);
			channels[j].node = ain;
			channels[j].parent = 0;
			boneindexIT_t it = fBoneIndex.find(ain->mNodeName.data);
			if (it == fBoneIndex.end()) {
				// Skip this channel (bone animation)
				channels[j].joint = UNUSEDCHANNEL; // Mark it as not used
				continue;
				// ErrorDialog("ManageAnimation::Init: Unknown bone %s in animation %s for %s", ain->mNodeName.data, fAnimations[i].name.c_str(), filename);
			}
			foundOneBone = true;
			unsigned int joint = it->second;
			fAnimations[i].bones[joint].frameMatrix.reset(new glm::mat4[numKeys]);
			channels[j].joint = joint;
		}
		if (!foundOneBone)
			ErrorDialog("ManageAnimation::Init %s animation %d no bones used", filename, i);

		// Find the parent for each animation node
		for (unsigned j=0; j<numChannels; j++) {
			aiNode *n = FindNode(scene->mRootNode, channels[j].node->mNodeName.data);
			if (n == 0 || n->mParent == 0)
				continue; // No parent
			n = n->mParent;
			for (unsigned p=0; p<numChannels; p++) {
				if (p == j || strcmp(n->mName.data, channels[p].node->mNodeName.data) != 0)
					continue;
				// Found it!
				channels[j].parent = &channels[p];
				break;
			}
		}

		fAnimations[i].times.reset(new double[numKeys]);
		fAnimations[i].numKeys = numKeys;
		// The first key frame doesn't always start at time 0
		double firstKeyTime = channels[0].node->mPositionKeys[0].mTime;
		for (unsigned k=0; k < numKeys; k++) {
			fAnimations[i].times[k] = channels[0].node->mPositionKeys[k].mTime - firstKeyTime;
			// printf("Animation key %d at time %.2f\n", k, fAnimations[i].times[k]);
			for (unsigned int j=0; j < numChannels; j++) {
				aiNodeAnim *ain = channels[j].node;
				glm::mat4 R;
				CopyaiQuat(R, ain->mRotationKeys[k].mValue);
				glm::mat4 T = glm::translate(glm::mat4(1), glm::vec3(ain->mPositionKeys[k].mValue.x, ain->mPositionKeys[k].mValue.y, ain->mPositionKeys[k].mValue.z));
				glm::mat4 S = glm::scale(glm::mat4(1), glm::vec3(ain->mScalingKeys[k].mValue.x, ain->mScalingKeys[k].mValue.y, ain->mScalingKeys[k].mValue.z));
				channels[j].mat = T * R * S;
				if (gVerbose) {
					printf("     Key %d animation bone %s relative\n", k, channels[j].node->mNodeName.data);
					PrintMatrix(10, channels[j].mat);
				}
			}
			// Iterate through each animation bone and compute the transformation matrix using parent matrix.
			for (unsigned int j=0; j < numChannels; j++) {
				unsigned joint = channels[j].joint;
				glm::mat4 mat(1);
				for (channel *node = &channels[j]; node; node = node->parent) {
					mat = node->mat * mat;
				}
				mat = armature * mat;
				if (joint != UNUSEDCHANNEL) {
					fAnimations[i].bones[joint].frameMatrix[k] = mat;
					if (gVerbose) {
						printf("     Key %d animation bone %s channel %d absolute\n", k, channels[j].node->mNodeName.data, j);
						PrintMatrix(10, mat);
					}
				}
			}
		}
	}
}
Example #23
0
bool Model::loadFromFile(const std::string& filename)
{
    Assimp::Importer importer;


	std::string strModelsResourcesFolder = "Data/Resources/Models/";

	std::string strModelFinalFilename = strModelsResourcesFolder + filename;

    // Component to be removed when importing file
    importer.SetPropertyInteger(AI_CONFIG_PP_RVC_FLAGS,
                                aiComponent_COLORS
//                                | aiComponent_TANGENTS_AND_BITANGENTS
                                | aiComponent_BONEWEIGHTS
                                | aiComponent_ANIMATIONS
                                | aiComponent_LIGHTS
                                | aiComponent_CAMERAS);
    importer.SetPropertyInteger(AI_CONFIG_PP_PTV_NORMALIZE, 1);

    // And have it read the given file with some example postprocessing
    // Usually - if speed is not the most important aspect for you - you'll
    // propably to request more postprocessing than we do in this example.
	const aiScene* scene = importer.ReadFile(strModelFinalFilename,
        aiProcess_Triangulate
        | aiProcess_JoinIdenticalVertices
        | aiProcess_RemoveComponent
        | aiProcess_GenNormals
        | aiProcess_CalcTangentSpace
        | aiProcess_PreTransformVertices
        //| aiProcess_GenUVCoords
        //| aiProcess_MakeLeftHanded
    );


//    const aiScene* scene = importer.ReadFile( filename,
//                                              aiProcessPreset_TargetRealtime_MaxQuality
//    );

    // If the import failed, report it
    if( !scene)
    {
        std::cerr << importer.GetErrorString() << '\n';
        return false;
    }    

    m_nodes.clear();

    aiNode* rootNode = scene->mRootNode;

    handleNode(rootNode, aiMatrix4x4());

    m_meshes.clear();
    m_meshes.resize(scene->mNumMeshes);

    m_materials.clear();
    //m_materials.resize(scene->mNumMaterials);

    //std::string dir = filename;

    //size_t lastSeparator = dir.find_last_of('/');

    //if (lastSeparator != std::string::npos) {
    //    dir.erase(lastSeparator, dir.size());
    //}
    //else {
    //    dir = std::string(".");
    //}

    for (unsigned int i = 0; i < scene->mNumMeshes; ++i) {
        m_meshes[i].loadFromAssimpMesh(scene->mMeshes[i]);
    }

    //for (unsigned int i = 0; i < scene->mNumMaterials; ++i) {
    //    m_materials[i].loadFromAssimpMaterial(scene->mMaterials[i], dir);
    //}

//    const aiMesh* mesh = scene->mMeshes[0];

//    std::cerr << "Mesh HasFaces ? " << mesh->HasFaces() << '\n';
//    std::cerr << "Mesh HasNormals ? " << mesh->HasNormals() << '\n';
//    std::cerr << "Mesh HasPositions ? " << mesh->HasPositions() << '\n';
//    std::cerr << "Mesh HasTangentsAndBitangents ? " << mesh->HasTangentsAndBitangents() << '\n';
//    std::cerr << "Mesh HasBones ? " << mesh->HasBones() << '\n';
//    std::cerr << "Mesh HasTextureCoords ? " << mesh->HasTextureCoords(0) << '\n';
//    std::cerr << "mesh->mTextureCoords[0] != NULL ? " << (mesh->mTextureCoords[0] != NULL) << '\n';
//    std::cerr << "Mesh GetNumUVChannels ? " << mesh->GetNumUVChannels() << '\n';
//    std::cerr << "Mesh GetNumColorChannels ? " << mesh->GetNumColorChannels() << '\n';
//    std::cerr << "Mesh mNumFaces ? " << mesh->mNumFaces << '\n';
//    std::cerr << "Mesh mNumVertices ? " << mesh->mNumVertices << '\n';
//    std::cerr << "Mesh mPrimitiveTypes ? " << mesh->mPrimitiveTypes << " and should be " << aiPrimitiveType_TRIANGLE << '\n';

    return true;
}
Example #24
0
S3DModel* CAssParser::Load(const std::string& modelFilePath)
{
	LOG_S(LOG_SECTION_MODEL, "Loading model: %s", modelFilePath.c_str() );
	const std::string modelPath  = FileSystem::GetDirectory(modelFilePath);
	const std::string modelName  = FileSystem::GetBasename(modelFilePath);

	//! LOAD METADATA
	//! 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";
	}
	LuaParser metaFileParser(metaFileName, SPRING_VFS_MOD_BASE, SPRING_VFS_ZIP);
	if (!CFileHandler::FileExists(metaFileName, SPRING_VFS_ZIP)) {
		LOG_S(LOG_SECTION_MODEL, "No meta-file '%s'. Using defaults.", metaFileName.c_str());
	} else if (!metaFileParser.Execute()) {
		LOG_SL(LOG_SECTION_MODEL, L_ERROR, "'%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()) {
		LOG_S(LOG_SECTION_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
	LOG_S(LOG_SECTION_MODEL, "Importing model file: %s", modelFilePath.c_str() );
	const aiScene* scene = importer.ReadFile( modelFilePath, ASS_POSTPROCESS_OPTIONS );
	if (scene != NULL) {
		LOG_S(LOG_SECTION_MODEL,
				"Processing scene for model: %s (%d meshes / %d materials / %d textures)",
				modelFilePath.c_str(), scene->mNumMeshes, scene->mNumMaterials,
				scene->mNumTextures );
	} else {
		LOG_SL(LOG_SECTION_MODEL, L_ERROR, "Model Import: %s",
				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) {
			model->tex1 = FileSystem::GetFilename(*fi);
			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) {
			model->tex2 = FileSystem::GetFilename(*fi);
			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
	LOG_S(LOG_SECTION_MODEL, "Loading textures. Tex1: '%s' Tex2: '%s'",
			model->tex1.c_str(), model->tex2.c_str());
	texturehandlerS3O->LoadS3OTexture(model);

	//! Load all pieces in the model
	LOG_S(LOG_SECTION_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
	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_S(LOG_SECTION_MODEL, "Model %s Imported.", model->name.c_str());
	return model;
}