///////////////////////////////////////////////////////////////////////////
//
// System: Simplygon
// File: MaterialPartRemoverExample.cpp
// Language: C++
//
// Copyright (c) 2019 Microsoft. All rights reserved.
//
// This is private property, and it is illegal to copy or distribute in
// any form, without written authorization by the copyright owner(s).
//
///////////////////////////////////////////////////////////////////////////
//
// #Description#
//
// A scene containing multiple objects of different sizes and materials are loaded.
//
// A threshold is set per-material. If an object is smaller than the threshold
// corresponding with its material ID, it will be removed by the PartRemover.
//
// The threshold is expressed in percent of the entire scene diameter. So if
// Material 0 has threshold 10% and an object with material ID 0 is smaller than
// 10% of the scene, it will be removed.
//
// This is useful for removing decal quads of certain sizes from the generated LOD.
//
///////////////////////////////////////////////////////////////////////////
#include "../Common/Example.h"
void RunExampleMaterialPartRemover( const std::string& readFrom, const std::string& writeTo );
int main( int argc, char* argv[] )
{
try
{
InitExample();
// Set global variable. Using Orthonormal method for calculating
// tangentspace.
sg->SetGlobalSetting("DefaultTBNType", SG_TANGENTSPACEMETHOD_ORTHONORMAL);
std::string assetPath = GetAssetPath();
// Run the example code
RunExampleMaterialPartRemover(assetPath + "PartRemoverAssets/partRemoverScene.obj", "partRemoverScene_out");
DeinitExample();
}
catch (const std::exception& ex)
{
std::cerr << ex.what() << std::endl;
return -1;
}
return 0;
}
void RunExampleMaterialPartRemover( const std::string& readFrom, const std::string& writeTo )
{
std::string output_geometry_filename = GetExecutablePath() + writeTo + ".obj";
// Load from file
spWavefrontImporter objReader = sg->CreateWavefrontImporter();
objReader->SetExtractGroups( false ); //Makes unified geometry data
objReader->SetImportFilePath( readFrom.c_str() );
if( !objReader->RunImport() )
throw std::exception("Failed to load input file!");
// Make a copy of all the scene geometries as a a single combined geometry
// The triangles that belong to each individual geometry (or part-geometry)
// will have a GroupID to know where it belongs to.
spScene scene = objReader->GetScene();
spGeometryData combinedGeomCopy = scene->NewCombinedGeometry( -1 );
spMaterialTable materials = scene->GetMaterialTable();
// Calculate the extents to get a scene scale value
combinedGeomCopy->CalculateExtents( false );
real inf[3], sup[3], diag[3];
combinedGeomCopy->GetInf( inf );
combinedGeomCopy->GetSup( sup );
for( uint i = 0; i < 3; ++i )
diag[i] = sup[i] - inf[i];
real diam = sqrtf( diag[0] * diag[0] + diag[1] * diag[1] + diag[2] * diag[2] );
// Create the part remover tool
spPartRemover partRem = sg->CreatePartRemover();
partRem->SetGeometry( combinedGeomCopy );
// Set settings
// partRem->SetSizeThreshold( 0.2f*diam ); //This sets the global threshold, which will be ignored if the flag below is true
partRem->SetUsePerMaterialSizeThresholds( true ); // This will make the part remover use the per-material threshold array
// Setup the PerMaterialSizeThresholds array
spRealArray perMaterialSizeThresholds = partRem->GetPerMaterialSizeThresholds();
unsigned int matCount = materials->GetItemsCount();
perMaterialSizeThresholds->SetItemCount( matCount );
// If parts made up of material 1 have a diameter smaller than 10% of the scene's entire diameter,
// then remove the part. Material 2 parts get removed at 20%.
// The threshold for Material 0 is zero, meaning we never remove parts using it.
if( matCount >= 2 )
{
perMaterialSizeThresholds->SetItem( 0, 0.0f );
perMaterialSizeThresholds->SetItem( 1, 0.1f*diam );
perMaterialSizeThresholds->SetItem( 2, 0.2f*diam );
}
// For all remaining materials
for( uint i = 3; i < matCount; ++i )
{
perMaterialSizeThresholds->SetItem( i, 0.f ); //Do not remove parts consisting of these materials
}
// Run the processing
partRem->RunPartRemoval();
// Input the combined geometry with the parts removed into a new empty scene
spScene processedScene = sg->CreateScene();
processedScene->GetRootNode()->CreateChildMesh( combinedGeomCopy );
processedScene->GetMaterialTable()->Copy( scene->GetMaterialTable() );
processedScene->GetTextureTable()->Copy( scene->GetTextureTable() );
// Store to file
spWavefrontExporter objexp = sg->CreateWavefrontExporter();
objexp->SetExportFilePath( output_geometry_filename.c_str() );
objexp->SetScene( processedScene );
objexp->RunExport();
}