///////////////////////////////////////////////////////////////////////////
//
// System: Simplygon
// File: DataCreationPreferencesExample.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 wavefront file is opened, the scene is then processed in 3 different ways,
// one for each data creation preference setting.
//
// The generated LOD and the original geometry are combined into a single geometry
// with a shared vertex set.
//
// All reductions are run with identical settings except for the data creation
// preferences flag:
//
// 1) SG_DATACREATIONPREFERENCES_ONLY_USE_ORIGINAL_DATA
// When the reducer is set to only use original data, the new geometry is
// constructed entirely from vertices present in the original geometry.
//
// The combined geometry will have the same vertex count as the original.
//
// 2) SG_DATACREATIONPREFERENCES_PREFER_ORIGINAL_DATA
// When the flag is set to prefer original vertices, mesh repair will be allowed
// to run on the asset and new combinations of vertex data will be allowed to
// be created, but most of the vertices will correspond to ones found in the original.
//
// The combined geometry will probably have a larger vertex count than the original.
//
// 3) SG_DATACREATIONPREFERENCES_PREFER_OPTIMIZED_RESULT
// The third setting allows optimization of all vertex data, and produces an
// entirely new set of vertex coords. The vertices are re-positioned to preserve the
// original silhouette and volume of the mesh.
//
// The combined geometry will likely not share vertices between the LOD and original so
// the combined vertex count is increased.
//
//
// It should be noted that the most restrictive option original vertices should only
// be used when the original model is reasonably clean, as all the mesh repair features
// of Simplygon will be switched off. New normals will not be calculated, vertices
// will not be welded and T-junctions will not be fixed.
//
// The results of the three processes are saved as individual .obj files
//
///////////////////////////////////////////////////////////////////////////
#include "../Common/Example.h"
void RunExampleReduction( const std::string& readFrom, const std::string& writeTo, uint DataCreationPref );
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 reduction, use only original vertices
printf("Running reduction, only using original vertices\n");
RunExampleReduction(assetPath + "wall.obj", "original_and_lod_original_verts", SG_DATACREATIONPREFERENCES_ONLY_USE_ORIGINAL_DATA);
printf("Done, output geometry saved to file.\n\n");
// Run the example reduction, prefer original vertices but still allow new data when required
printf("Running reduction, allowing creation of new vertices when needed\n");
RunExampleReduction(assetPath + "wall.obj", "original_and_lod_new_verts", SG_DATACREATIONPREFERENCES_PREFER_ORIGINAL_DATA);
printf("Done, output geometry saved to file.\n\n");
// Run the example reduction, optimize all geometry data as required
printf("Running reduction, allowing modification of all vertex data\n");
RunExampleReduction(assetPath + "wall.obj", "original_and_lod_optimized_verts", SG_DATACREATIONPREFERENCES_PREFER_OPTIMIZED_RESULT);
printf("Done, output geometry saved to file.\n");
DeinitExample();
}
catch (const std::exception& ex)
{
std::cerr << ex.what() << std::endl;
return -1;
}
return 0;
}
void RunExampleReduction( const std::string& readFrom, const std::string& writeTo, uint DataCreationPref )
{
// Run reduction with default settings to 10% of the original triangle count.
// The data restrictions flag is set from the main function and determines
// if the reducer will be allowed to create new vertices or construct the LOD
// using only the vertices available in the original mesh. The decimated
// geometry is appended to the packed original, so that the geometry now contains
// all unique vertices from both the original geometry and the generated LOD.
// If the data creation flag is set to only use original data no new
// vertices should be created when the LOD is appended to the original mesh.
// The LOD triangles described with the combined vertex set is then added to
// the packed geometry, creating a geometry that contains both the original
// model and the generated LOD using the same vertices.
std::string output_geometry_filename = GetExecutablePath() + writeTo + ".obj";
// Load from file
spWavefrontImporter objReader = sg->CreateWavefrontImporter();
objReader->SetImportFilePath( readFrom.c_str() );
if( !objReader->RunImport() )
throw std::exception("Failed to load input file!");
// Get the scene from the importer
spScene scene = objReader->GetScene();
spSelectionSet selectMesh = scene->GetSelectionSetTable()->GetSelectionSet( scene->SelectNodes( "ISceneMesh" ) );
spGeometryData currentGeom = Cast<ISceneMesh>( scene->GetNodeByGUID( selectMesh->GetItem( 0 ) ) )->GetGeometry();
// Create a packed copy of the original geometry for appending to later
spPackedGeometryData packedGeometry = currentGeom->NewPackedCopy();
// To compare the combined vertex counts vs the original, we output the original unpacked -> packed geom
if( true )
{
spScene outputOriginalPackedScene = sg->CreateScene();
outputOriginalPackedScene->GetRootNode()->CreateChildMesh( packedGeometry->NewUnpackedCopy() );
outputOriginalPackedScene->GetMaterialTable()->Copy( scene->GetMaterialTable() );
spWavefrontExporter objexp = sg->CreateWavefrontExporter();
std::string output_original_unpacked_packed_filename = GetExecutablePath() + "original_unpacked_packed.obj";
objexp->SetExportFilePath( output_original_unpacked_packed_filename.c_str() );
objexp->SetScene( outputOriginalPackedScene );
objexp->RunExport();
}
// Create the reduction-processor.
spReductionProcessor red = sg->CreateReductionProcessor();
red->SetScene( scene );
// Set the Reduction Settings.
spReductionSettings reduction_settings = red->GetReductionSettings();
// Will reduce to 1/10 of the original trianglecount.
reduction_settings->SetTriangleRatio( 0.1f );
// Set the data creation preferences flag
reduction_settings->SetDataCreationPreferences( DataCreationPref );
// Run the reduction
red->RunProcessing();
// Append processed geometry to original geometry and check number of new vertices
// Unique vertices from currentGeom will be added to the packed geometry
// newVertexList will contain a description of the triangles of currentGeom using the
// original vertex IDs where available.
// newUniqueVertexCount should increase with the level of freedom allowed for the reducer
// Note that the geometries need to contain the same set of fields, otherwise the append will fail
spRidArray newVertexIdsList = sg->CreateRidArray();
int newUniqueVertexCount = packedGeometry->AppendPackedGeometry( currentGeom, newVertexIdsList, false );
printf( "%i new vertices generated.\n", newUniqueVertexCount );
// Save original triangle count
rid originalTriangleCount = packedGeometry->GetTriangleCount();
// Add the amount of triangles from currentgeom
packedGeometry->AddTriangles( currentGeom->GetTriangleCount() );
// Append LOD vertex list to the end of the original geometries vertex list
spRidData newVertexIdsListData = sg->CreateRidData();
newVertexIdsList->GetData( newVertexIdsListData );
packedGeometry->GetVertexIds()->SetDataRange( originalTriangleCount * 3, newVertexIdsListData.Data(), newVertexIdsList->GetItemCount() );
// Append LOD triangle data to the end of the original geometries triangle data
packedGeometry->GetTriangles()->CopyRange( currentGeom->GetTriangles(), originalTriangleCount, 0, currentGeom->GetTriangleCount() );
// Now, the triangles in packedGeometry describes the original model from 0 <= id < originalTriangleCount,
// and the generated LOD following that.
spScene outputCombinedGeometriesScene = sg->CreateScene();
outputCombinedGeometriesScene->GetRootNode()->CreateChildMesh( packedGeometry->NewUnpackedCopy() );
outputCombinedGeometriesScene->GetMaterialTable()->Copy( scene->GetMaterialTable() );
// Now store combined original and LOD geometry to file
spWavefrontExporter objexp = sg->CreateWavefrontExporter();
objexp->SetExportFilePath( output_geometry_filename.c_str() );
bool outputCombinedScene = true;
if( outputCombinedScene )
objexp->SetScene( outputCombinedGeometriesScene ); //Output original and LOD sharing vertex list
else
objexp->SetScene( scene ); //Only output the LOD
objexp->RunExport();
}