Show / Hide Table of Contents
    ///////////////////////////////////////////////////////////////////////////
    //
    //  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();
        }
    
    Back to top Terms of Use | Privacy and cookies | Trademarks | Copyright © 2019 Microsoft