void glTF2Importer::InternReadFile(const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler) { this->mScene = pScene; // read the asset file glTF2::Asset asset(pIOHandler); asset.Load(pFile, GetExtension(pFile) == "glb"); // // Copy the data out // ImportEmbeddedTextures(asset); ImportMaterials(asset); ImportMeshes(asset); ImportCameras(asset); ImportNodes(asset); // TODO: it does not split the loaded vertices, should it? //pScene->mFlags |= AI_SCENE_FLAGS_NON_VERBOSE_FORMAT; MakeVerboseFormatProcess process; process.Execute(pScene); if (pScene->mNumMeshes == 0) { pScene->mFlags |= AI_SCENE_FLAGS_INCOMPLETE; } }
// ------------------------------------------------------------------------------------------------ aiReturn Exporter :: Export( const aiScene* pScene, const char* pFormatId, const char* pPath, unsigned int pPreprocessing ) { ASSIMP_BEGIN_EXCEPTION_REGION(); pimpl->mError = ""; for (size_t i = 0; i < pimpl->mExporters.size(); ++i) { const Exporter::ExportFormatEntry& exp = pimpl->mExporters[i]; if (!strcmp(exp.mDescription.id,pFormatId)) { try { // Always create a full copy of the scene. We might optimize this one day, // but for now it is the most pragmatic way. aiScene* scenecopy_tmp; SceneCombiner::CopyScene(&scenecopy_tmp,pScene); std::auto_ptr<aiScene> scenecopy(scenecopy_tmp); const ScenePrivateData* const priv = ScenePriv(pScene); // steps that are not idempotent, i.e. we might need to run them again, usually to get back to the // original state before the step was applied first. When checking which steps we don't need // to run, those are excluded. const unsigned int nonIdempotentSteps = aiProcess_FlipWindingOrder | aiProcess_FlipUVs | aiProcess_MakeLeftHanded; // Erase all pp steps that were already applied to this scene unsigned int pp = (exp.mEnforcePP | pPreprocessing) & ~(priv ? (priv->mPPStepsApplied & ~nonIdempotentSteps) : 0u); // If no extra postprocessing was specified, and we obtained this scene from an // Assimp importer, apply the reverse steps automatically. if (!pPreprocessing && priv) { pp |= (nonIdempotentSteps & priv->mPPStepsApplied); } // If the input scene is not in verbose format, but there is at least postprocessing step that relies on it, // we need to run the MakeVerboseFormat step first. if (scenecopy->mFlags & AI_SCENE_FLAGS_NON_VERBOSE_FORMAT) { bool verbosify = false; for( unsigned int a = 0; a < pimpl->mPostProcessingSteps.size(); a++) { BaseProcess* const p = pimpl->mPostProcessingSteps[a]; if (p->IsActive(pp) && p->RequireVerboseFormat()) { verbosify = true; break; } } if (verbosify || (exp.mEnforcePP & aiProcess_JoinIdenticalVertices)) { DefaultLogger::get()->debug("export: Scene data not in verbose format, applying MakeVerboseFormat step first"); MakeVerboseFormatProcess proc; proc.Execute(scenecopy.get()); } } if (pp) { // the three 'conversion' steps need to be executed first because all other steps rely on the standard data layout { FlipWindingOrderProcess step; if (step.IsActive(pp)) { step.Execute(scenecopy.get()); } } { FlipUVsProcess step; if (step.IsActive(pp)) { step.Execute(scenecopy.get()); } } { MakeLeftHandedProcess step; if (step.IsActive(pp)) { step.Execute(scenecopy.get()); } } // dispatch other processes for( unsigned int a = 0; a < pimpl->mPostProcessingSteps.size(); a++) { BaseProcess* const p = pimpl->mPostProcessingSteps[a]; if (p->IsActive(pp) && !dynamic_cast<FlipUVsProcess*>(p) && !dynamic_cast<FlipWindingOrderProcess*>(p) && !dynamic_cast<MakeLeftHandedProcess*>(p)) { p->Execute(scenecopy.get()); } } ScenePrivateData* const privOut = ScenePriv(scenecopy.get()); ai_assert(privOut); privOut->mPPStepsApplied |= pp; } exp.mExportFunction(pPath,pimpl->mIOSystem.get(),scenecopy.get()); } catch (DeadlyExportError& err) { pimpl->mError = err.what(); return AI_FAILURE; } return AI_SUCCESS; } } pimpl->mError = std::string("Found no exporter to handle this file format: ") + pFormatId; ASSIMP_END_EXCEPTION_REGION(aiReturn); return AI_FAILURE; }
//------------------------------------------------------------------------------- // Set the normal set of the scene //------------------------------------------------------------------------------- void AssetHelper::SetNormalSet(unsigned int iSet) { // we need to build an unique set of vertices for this ... { MakeVerboseFormatProcess* pcProcess = new MakeVerboseFormatProcess(); pcProcess->Execute(pcScene); delete pcProcess; for (unsigned int i = 0; i < pcScene->mNumMeshes;++i) { if (!apcMeshes[i]->pvOriginalNormals) { apcMeshes[i]->pvOriginalNormals = new aiVector3D[pcScene->mMeshes[i]->mNumVertices]; memcpy( apcMeshes[i]->pvOriginalNormals,pcScene->mMeshes[i]->mNormals, pcScene->mMeshes[i]->mNumVertices * sizeof(aiVector3D)); } delete[] pcScene->mMeshes[i]->mNormals; pcScene->mMeshes[i]->mNormals = NULL; } } // now we can start to calculate a new set of normals if (HARD == iSet) { GenFaceNormalsProcess* pcProcess = new GenFaceNormalsProcess(); pcProcess->Execute(pcScene); FlipNormalsInt(); delete pcProcess; } else if (SMOOTH == iSet) { GenVertexNormalsProcess* pcProcess = new GenVertexNormalsProcess(); pcProcess->SetMaxSmoothAngle((float)AI_DEG_TO_RAD(g_smoothAngle)); pcProcess->Execute(pcScene); FlipNormalsInt(); delete pcProcess; } else if (ORIGINAL == iSet) { for (unsigned int i = 0; i < pcScene->mNumMeshes;++i) { if (apcMeshes[i]->pvOriginalNormals) { delete[] pcScene->mMeshes[i]->mNormals; pcScene->mMeshes[i]->mNormals = apcMeshes[i]->pvOriginalNormals; apcMeshes[i]->pvOriginalNormals = NULL; } } } // recalculate tangents and bitangents Assimp::BaseProcess* pcProcess = new CalcTangentsProcess(); pcProcess->Execute(pcScene); delete pcProcess; // join the mesh vertices again pcProcess = new JoinVerticesProcess(); pcProcess->Execute(pcScene); delete pcProcess; iNormalSet = iSet; if (g_bWasFlipped) { // invert all normal vectors for (unsigned int i = 0; i < pcScene->mNumMeshes;++i) { aiMesh* pcMesh = pcScene->mMeshes[i]; for (unsigned int a = 0; a < pcMesh->mNumVertices;++a) { pcMesh->mNormals[a] *= -1.0f; } } } // recreate native data DeleteAssetData(true); CreateAssetData(); return; }
// ------------------------------------------------------------------------------------------------ aiReturn Exporter::Export( const aiScene* pScene, const char* pFormatId, const char* pPath, unsigned int pPreprocessing, const ExportProperties* pProperties) { ASSIMP_BEGIN_EXCEPTION_REGION(); // when they create scenes from scratch, users will likely create them not in verbose // format. They will likely not be aware that there is a flag in the scene to indicate // this, however. To avoid surprises and bug reports, we check for duplicates in // meshes upfront. const bool is_verbose_format = !(pScene->mFlags & AI_SCENE_FLAGS_NON_VERBOSE_FORMAT) || IsVerboseFormat(pScene); pimpl->mProgressHandler->UpdateFileWrite(0, 4); pimpl->mError = ""; for (size_t i = 0; i < pimpl->mExporters.size(); ++i) { const Exporter::ExportFormatEntry& exp = pimpl->mExporters[i]; if (!strcmp(exp.mDescription.id,pFormatId)) { try { // Always create a full copy of the scene. We might optimize this one day, // but for now it is the most pragmatic way. aiScene* scenecopy_tmp = nullptr; SceneCombiner::CopyScene(&scenecopy_tmp,pScene); pimpl->mProgressHandler->UpdateFileWrite(1, 4); std::unique_ptr<aiScene> scenecopy(scenecopy_tmp); const ScenePrivateData* const priv = ScenePriv(pScene); // steps that are not idempotent, i.e. we might need to run them again, usually to get back to the // original state before the step was applied first. When checking which steps we don't need // to run, those are excluded. const unsigned int nonIdempotentSteps = aiProcess_FlipWindingOrder | aiProcess_FlipUVs | aiProcess_MakeLeftHanded; // Erase all pp steps that were already applied to this scene const unsigned int pp = (exp.mEnforcePP | pPreprocessing) & ~(priv && !priv->mIsCopy ? (priv->mPPStepsApplied & ~nonIdempotentSteps) : 0u); // If no extra post-processing was specified, and we obtained this scene from an // Assimp importer, apply the reverse steps automatically. // TODO: either drop this, or document it. Otherwise it is just a bad surprise. //if (!pPreprocessing && priv) { // pp |= (nonIdempotentSteps & priv->mPPStepsApplied); //} // If the input scene is not in verbose format, but there is at least post-processing step that relies on it, // we need to run the MakeVerboseFormat step first. bool must_join_again = false; if (!is_verbose_format) { bool verbosify = false; for( unsigned int a = 0; a < pimpl->mPostProcessingSteps.size(); a++) { BaseProcess* const p = pimpl->mPostProcessingSteps[a]; if (p->IsActive(pp) && p->RequireVerboseFormat()) { verbosify = true; break; } } if (verbosify || (exp.mEnforcePP & aiProcess_JoinIdenticalVertices)) { ASSIMP_LOG_DEBUG("export: Scene data not in verbose format, applying MakeVerboseFormat step first"); MakeVerboseFormatProcess proc; proc.Execute(scenecopy.get()); if(!(exp.mEnforcePP & aiProcess_JoinIdenticalVertices)) { must_join_again = true; } } } pimpl->mProgressHandler->UpdateFileWrite(2, 4); if (pp) { // the three 'conversion' steps need to be executed first because all other steps rely on the standard data layout { FlipWindingOrderProcess step; if (step.IsActive(pp)) { step.Execute(scenecopy.get()); } } { FlipUVsProcess step; if (step.IsActive(pp)) { step.Execute(scenecopy.get()); } } { MakeLeftHandedProcess step; if (step.IsActive(pp)) { step.Execute(scenecopy.get()); } } bool exportPointCloud(false); if (nullptr != pProperties) { exportPointCloud = pProperties->GetPropertyBool(AI_CONFIG_EXPORT_POINT_CLOUDS); } // dispatch other processes for( unsigned int a = 0; a < pimpl->mPostProcessingSteps.size(); a++) { BaseProcess* const p = pimpl->mPostProcessingSteps[a]; if (p->IsActive(pp) && !dynamic_cast<FlipUVsProcess*>(p) && !dynamic_cast<FlipWindingOrderProcess*>(p) && !dynamic_cast<MakeLeftHandedProcess*>(p)) { if (dynamic_cast<PretransformVertices*>(p) && exportPointCloud) { continue; } p->Execute(scenecopy.get()); } } ScenePrivateData* const privOut = ScenePriv(scenecopy.get()); ai_assert(nullptr != privOut); privOut->mPPStepsApplied |= pp; } pimpl->mProgressHandler->UpdateFileWrite(3, 4); if(must_join_again) { JoinVerticesProcess proc; proc.Execute(scenecopy.get()); } ExportProperties emptyProperties; // Never pass NULL ExportProperties so Exporters don't have to worry. exp.mExportFunction(pPath,pimpl->mIOSystem.get(),scenecopy.get(), pProperties ? pProperties : &emptyProperties); pimpl->mProgressHandler->UpdateFileWrite(4, 4); } catch (DeadlyExportError& err) { pimpl->mError = err.what(); return AI_FAILURE; } return AI_SUCCESS; } } pimpl->mError = std::string("Found no exporter to handle this file format: ") + pFormatId; ASSIMP_END_EXCEPTION_REGION(aiReturn); return AI_FAILURE; }