Show / Hide Table of Contents
    ///////////////////////////////////////////////////////////////////////////
    //
    //  System:    Simplygon
    //  File:      AggregationProcessorExample.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"
    
    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, bool cullGeometries = false, bool setupCamera = false);
    void SetupCameraAndAddToSet(SimplygonSDK::real  location[3], SimplygonSDK::real  lookat[3], SimplygonSDK::spScene& scene, SimplygonSDK::spSelectionSet& cameraSelectionSet);
    
    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();
    
            printf("Running scene aggregation, collapsing objects and baking material...\n");
            PrintProgressBar(0); //Initial progress bar
            RunExample(assetPath + "/CombineScene/scene.obj", "CombinedScene_MergeAll", true, true);
            printf("\nDone.\n\n");
    
            printf("Running scene aggregation, only baking material...\n");
            PrintProgressBar(0); //Initial progress bar
            RunExample(assetPath + "/CombineScene/scene.obj", "CombinedScene_MergeMaterials", true, false);
            printf("\nDone.\n\n");
    
            printf("Running scene aggregation, only merging objects...\n");
            PrintProgressBar(0); //Initial progress bar
            RunExample(assetPath + "/CombineScene/scene.obj", "CombinedScene_MergeGeometries", false, true);
            printf("\nDone.\n\n");
    
            printf("Running scene aggregation, collapsing objects and baking material and applying visibility pass...\n");
            PrintProgressBar(0); //Initial progress bar
            RunExample(assetPath + "/CombineSceneVisibility/scene.obj", "CombineSceneVisibility_MergeAllAndCull", true, true, true);
            printf("\nDone.\n\n");
    
            printf("Running scene aggregation, collapsing objects and baking material and applying visibility pass with camera...\n");
            PrintProgressBar(0); //Initial progress bar
            RunExample(assetPath + "/CombineSceneVisibility/scene.obj", "CombineSceneVisibility_MergeAllAndCull", true, true, true, true);
            printf("\nDone.\n\n");
    
            printf("All LODs complete, shutting down...");
    
            DeinitExample();
        }
        catch (const std::exception& ex)
        {
            std::cerr << ex.what() << std::endl;
            return -1;
        }
    
        return 0;
        }
    
    void RunExample(const std::string& readFrom, const std::string& writeTo, const bool &castMaterials, const bool &mergeGeometries, bool cullGeometries, bool setupCamera)
        {
        std::string diffuseTextureName = writeTo + "_Diffuse.png";
        std::string specularTextureName = writeTo + "_Specular.png";
    
        // Load from file
        spWavefrontImporter objReader = sg->CreateWavefrontImporter();
        objReader->SetImportFilePath(readFrom.c_str());
        objReader->SetExtractGroups(true);
        if (!objReader->RunImport())
            throw std::exception("Failed to load input file!");
    
        // Get the scene
        spScene scene = objReader->GetScene();
    
        //setup visibility cameras if culling is enabled. 
        rid selectionSetID = -1;
        real smallArea{};
        if (setupCamera)
            {
            spSelectionSet cameraSelectionSet = sg->CreateSelectionSet();
            selectionSetID = scene->GetSelectionSetTable()->AddSelectionSet(cameraSelectionSet);
    
            //We want to make sure there aren't small patches of non visible triangles (surrounded by visible triangle) 
            //that are culled from the scene. It is better to keep those non-visible triangles if we want to do a good job
            //with the reducer and the tex-coord generator
            smallArea = (scene->GetRadius() / 40.0f) * (scene->GetRadius() / 40.0f);
            real location[]{ 1.f, 1.f, 1.f };
            real lookat[]{ 0.f , 0.f, 0.f };
            SetupCameraAndAddToSet(location, lookat, scene, cameraSelectionSet);
            }
    
        spScene lodScene = sg->CreateScene();
        lodScene->DeepCopy(scene);
    
        // Create the spAggregationProcessor
        spAggregationProcessor aggregationProcessor = sg->CreateAggregationProcessor();
        // Set the input scene
        aggregationProcessor->SetScene(lodScene);
    
        spAggregationSettings aggregatorSettings = aggregationProcessor->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.
        aggregatorSettings->SetBaseAtlasOnOriginalTexCoords(true);
        aggregatorSettings->SetMergeGeometries(mergeGeometries);
        aggregatorSettings->SetMergeMaterials(castMaterials);
    
        aggregationProcessor->GetVisibilitySettings()->SetUseVisibilityWeightsInTexcoordGenerator(true);
        aggregationProcessor->GetVisibilitySettings()->SetCullOccludedGeometry(cullGeometries);
        aggregationProcessor->GetVisibilitySettings()->SetCameraSelectionSetID(selectionSetID);
        if (setupCamera)
            aggregationProcessor->GetVisibilitySettings()->SetFillNonVisibleAreaThreshold(smallArea);
    
        // Get the mapping image settings, a mapping image is needed to
        // cast the new textures.
        spMappingImageSettings mappingImageSettings = aggregationProcessor->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);
    
        //Add observer
        aggregationProcessor->AddObserver(&progressObserver, SG_EVENT_PROGRESS);
    
        // Run the process
        aggregationProcessor->RunProcessing();
    
        if (castMaterials)
            {
            //Clear the copied materials from the lod, and later populate it with newly generated materials
            spTextureTable lodTexTable = lodScene->GetTextureTable();
            lodTexTable->Clear();
            spMaterialTable lodMatTable = lodScene->GetMaterialTable();
            lodMatTable->Clear();
    
            //Create a new material that we cast the new textures onto
            spMaterial lodMaterial = sg->CreateMaterial();
            lodMaterial->SetName("output_material");
    
            lodMatTable->AddMaterial(lodMaterial);
            lodMatTable->SetName("CombinedMaterials");
    
            spColorCaster diffuseCaster = sg->CreateColorCaster();
            diffuseCaster->SetColorType(SG_MATERIAL_CHANNEL_DIFFUSE);
            diffuseCaster->SetSourceMaterials(scene->GetMaterialTable());
            diffuseCaster->SetSourceTextures(scene->GetTextureTable());
            diffuseCaster->SetOutputFilePath(diffuseTextureName.c_str());
            diffuseCaster->SetMappingImage(aggregationProcessor->GetMappingImage());
    
            diffuseCaster->RunProcessing();
    
            //Setup new texture in LOD scene
            AddSimplygonTexture(lodMaterial, lodTexTable, SG_MATERIAL_CHANNEL_DIFFUSE, diffuseTextureName.c_str());
    
            spColorCaster specularCaster = sg->CreateColorCaster();
            specularCaster->SetColorType(SG_MATERIAL_CHANNEL_SPECULAR);
            specularCaster->SetSourceMaterials(scene->GetMaterialTable());
            specularCaster->SetSourceTextures(scene->GetTextureTable());
            specularCaster->SetOutputFilePath(specularTextureName.c_str());
            specularCaster->SetMappingImage(aggregationProcessor->GetMappingImage());
    
            specularCaster->RunProcessing();
    
    
            //Setup new texture in LOD scene
            AddSimplygonTexture(lodMaterial, lodTexTable, SG_MATERIAL_CHANNEL_SPECULAR, specularTextureName.c_str());
            }
    
        // Store to file
        spWavefrontExporter objexp = sg->CreateWavefrontExporter();
    
        std::string output_geometry_filename = GetExecutablePath() + writeTo + ".obj";
    
        objexp->SetExportFilePath(output_geometry_filename.c_str());
        objexp->SetScene(lodScene);
        objexp->RunExport();
        }
    void SetupCameraAndAddToSet(SimplygonSDK::real  location[3], SimplygonSDK::real  lookat[3], SimplygonSDK::spScene& scene, SimplygonSDK::spSelectionSet& cameraSelectionSet)
        {
        auto sceneCamera = sg->CreateSceneCamera();
        sceneCamera->SetCameraType(SG_CAMERATYPE_ORTHOGRAPHIC);
        auto cameraLocations = sceneCamera->GetCameraPositions();
        auto cameraLookats = sceneCamera->GetTargetPositions();
        //Set the tuple count to 1
        cameraLocations->SetTupleCount(1);
        cameraLookats->SetTupleCount(1);
        //Set the camera view
        cameraLocations->SetTuple(0, location);
        cameraLookats->SetTuple(0, lookat);
    
        //Decide the size of the orthographic pixels
        //This should correspond to the size of details in the scene that should be preserved
        real smallSceneSize = scene->GetRadius() / 500.0f;
        sceneCamera->SetOrthographicCameraPixelSize(smallSceneSize);
        if (sceneCamera->ValidateCamera()) //If the camera is setup correctly
            {
            scene->GetRootNode()->AddChild(sceneCamera);
            cameraSelectionSet->AddItem(sceneCamera->GetNodeGUID());
            }
        }
    
    Back to top Terms of Use | Privacy and cookies | Trademarks | Copyright © 2019 Microsoft