Show / Hide Table of Contents
    ///////////////////////////////////////////////////////////////////////////
    //
    //  System:    Simplygon
    //  File:      AggregationPipelineExample.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# 
    //
    //  Reduce drawcalls by using the IAggregationProcessor to combine all the 
    //  objects in a scene into a single new object that shares newly 
    //  generated textures.
    // 
    //
    //  A scene with multiple objects and materials is loaded.
    //  The scene contains 4 instances of the SimplygonMan,
    //  1 textured Utah teapot and 1 textured plane.
    //
    //  We run an AggregationProcessor on the scene and export the result as a
    //  Wavefront file.
    //
    //  The resulting scene has a single texture per material channel (diffuse
    //  and specular). All textures have been combined into these new textures.
    //  All texture coordinates have been re-computed to map to the new 
    //  textures.
    //
    //  The 4 SimplygonMan meshes share texture coordinates since they had
    //  the same textures. The plane and Utah teapot have new unique 
    //  UV-coordinates.
    //
    //  See the output texture images to see how the textures have been 
    //  combined.
    //
    ///////////////////////////////////////////////////////////////////////////
    
    #include "../Common/Example.h"
    
    #include <chrono>
    
    #ifdef __cpp_lib_filesystem // Check for C++17 filesystem
    #include <filesystem>
    namespace fs = std::filesystem;
    #else
    #ifndef _SILENCE_EXPERIMENTAL_FILESYSTEM_DEPRECATION_WARNING
    #define _SILENCE_EXPERIMENTAL_FILESYSTEM_DEPRECATION_WARNING
    #endif
    #include <experimental/filesystem>
    namespace fs = std::experimental::filesystem::v1;
    #endif
    
    class ProgressObserver : public robserver
        {
            public:
            virtual void Execute(
                IObject * subject,
                rid EventId,
                void * EventParameterBlock,
                unsigned int EventParameterBlockSize )
                {
                // only care for progress events
                if( EventId == SG_EVENT_PROGRESS )
                    {
                    // get the progress in percent
                    int val = *((int *)EventParameterBlock);
                    // tell the process to continue
                    // this is required by the progress event
                    *((int *)EventParameterBlock) = 1;
                    // output the progress update
                    PrintProgressBar( val );
                    }
                }
        } progressObserver;
    
    void RunExample(const std::string& readFrom, const std::string& writeTo, const bool &castMaterials, const bool &mergeGeometries);
    
    int main(int argc, char* argv[])
        {
        InitExample();
    
        // Set global variable. Using Orthonormal method for calculating
        // tangentspace.
        sg->SetGlobalSetting("DefaultTBNType", SG_TANGENTSPACEMETHOD_ORTHONORMAL);
    
        std::string assetPath = GetAssetPath();
    
        std::chrono::milliseconds elapsed(0);
        int numRuns = 1;
        double timeMultiplier = 1.0 / ((double)(numRuns > 1 ? (numRuns - 1) : 1) * 1000.0);
    
        printf("Running scene aggregation, collapsing objects and baking material...\n");
        elapsed = std::chrono::milliseconds::zero();
        for (int run = 0; run < numRuns; ++run)
            {
            PrintProgressBar(0); //Initial progress bar
            auto start = std::chrono::high_resolution_clock::now();
            RunExample(assetPath + "/CombineScene/scene.obj", "CombinedScene_MergeAll", true, true);
            if (run || numRuns == 1)
                elapsed += std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now() - start);
            }
        printf("\nDone, %.2f seconds\n\n", (double)elapsed.count() * timeMultiplier);
    
        printf("Running scene aggregation, only baking material...\n");
        elapsed = std::chrono::milliseconds::zero();
        for (int run = 0; run < numRuns; ++run)
            {
            PrintProgressBar(0); //Initial progress bar
            auto start = std::chrono::high_resolution_clock::now();
            RunExample(assetPath + "/CombineScene/scene.obj", "CombinedScene_MergeMaterials", true, false);
            if (run || numRuns == 1)
                elapsed += std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now() - start);
            }
        printf("\nDone, %.2f seconds\n\n", (double)elapsed.count() * timeMultiplier);
    
        printf("Running scene aggregation, only merging objects...\n");
        elapsed = std::chrono::milliseconds::zero();
        for (int run = 0; run < numRuns; ++run)
            {
            PrintProgressBar(0); //Initial progress bar
            auto start = std::chrono::high_resolution_clock::now();
            RunExample(assetPath + "/CombineScene/scene.obj", "CombinedScene_MergeGeometries", false, true);
            if (run || numRuns == 1)
                elapsed += std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now() - start);
            }
        printf("\nDone, %.2f seconds\n\n", (double)elapsed.count() * timeMultiplier);
    
        printf("All LODs complete, shutting down...");
    
        DeinitExample();
    
        return 0;
        }
    
    void RunExample(const std::string& readFrom, const std::string& writeTo, const bool &castMaterials, const bool &mergeGeometries)
        {
        //Setup output paths
        fs::path outputBasePath = fs::path( GetExecutablePath() ) / writeTo;
        fs::remove_all( outputBasePath );
        fs::create_directories( outputBasePath );
    
        std::string outputGeomPath = ( outputBasePath / ( writeTo + ".obj" ) ).generic_u8string();
    
        //Create a remeshing pipeline
        spAggregationPipeline aggregationPipeline = sg->CreateAggregationPipeline();
    
        ///////////////////////////////////////////////////////////////////////////////////////////////
        // SETTINGS
    
        spPipelineSettings pipelineSettings = aggregationPipeline->GetPipelineSettings();
        pipelineSettings->SetTextureOutputPath( ( outputBasePath / "Textures" ).generic_u8string().c_str() );
    
        spAggregationSettings aggregationSettings = aggregationPipeline->GetAggregationSettings();
    
        // Set the BaseAtlasOnOriginalTexCoords to true so that the new texture
        // coords will be based on the original. This way the four identical
        // SimplygonMan mesh instances will still share texture coords, and
        // when packing the texture charts into the new atlas, only rotations
        // multiples of 90 degrees are allowed.
        aggregationSettings->SetBaseAtlasOnOriginalTexCoords(true);
        aggregationSettings->SetMergeGeometries(mergeGeometries);
        aggregationSettings->SetMergeMaterials(castMaterials);
    
        spVisibilitySettings visibilitySettings = aggregationPipeline->GetVisibilitySettings();
        visibilitySettings->SetUseVisibilityWeightsInTexcoordGenerator(true);
    
        // Get the mapping image settings, a mapping image is needed to
        // cast the new textures.
        spMappingImageSettings mappingImageSettings = aggregationPipeline->GetMappingImageSettings();
        mappingImageSettings->SetGenerateMappingImage(true);
        mappingImageSettings->SetGutterSpace(1);
        mappingImageSettings->SetWidth(2048);
        mappingImageSettings->SetHeight(2048);
        mappingImageSettings->SetUseFullRetexturing(true); //replace old UVs
    
        // If BaseAtlasOnOriginalTexCoords is enabled and 
        // if charts are overlapping in the original texture coords, they will be separated if
        // SeparateOverlappingCharts is set to true.
        mappingImageSettings->SetChartAggregatorSeparateOverlappingCharts(false);
    
        // Set the output texcoord level name for the retextured UVs
        mappingImageSettings->SetTexCoordLevelName( "retextured" );
    
        if (castMaterials)
            {
            spColorCaster diffuseCaster = sg->CreateColorCaster();
            spColorCasterSettings diffuseCasterSetttings = diffuseCaster->GetColorCasterSettings();
            diffuseCasterSetttings->SetMaterialChannel(SG_MATERIAL_CHANNEL_DIFFUSE);
    
            spColorCaster specularCaster = sg->CreateColorCaster();
            spColorCasterSettings specularCasterSetttings = specularCaster->GetColorCasterSettings();
            specularCasterSetttings->SetMaterialChannel(SG_MATERIAL_CHANNEL_SPECULAR);
    
            aggregationPipeline->AddMaterialCaster( diffuseCaster, 0 );
            aggregationPipeline->AddMaterialCaster( specularCaster, 0 );
            }
    
        //END SETTINGS 
        ///////////////////////////////////////////////////////////////////////////////////////////////
    
        //Add observer
        aggregationPipeline->AddObserver( &progressObserver, SG_EVENT_PROGRESS );
    
        // Run the process
        aggregationPipeline->RunSceneFromFile( readFrom.c_str(), outputGeomPath.c_str() );
    
        spPipelineSerializer serializer = sg->CreatePipelineSerializer();
        serializer->SavePipelineToFile( (GetExecutablePath() + writeTo + "/pipeline.json").c_str(), aggregationPipeline );
        }
    
    Back to top Terms of Use | Privacy and cookies | Trademarks | Copyright © 2019 Microsoft