Show / Hide Table of Contents
    ///////////////////////////////////////////////////////////////////////////
    //
    //  System:    Simplygon
    //  File:      OcclusionMeshExample.cpp
    //  Language:  C++
    //
    //  Copyright (c) 2019 Microsoft. All rights reserved.
    //
    ///////////////////////////////////////////////////////////////////////////
    //
    //  #Description# An occlusion mesh example
    //
    //  This example shows how to use the occlusion mesh processor.
    //
    //  The processor is used to generate three meshes, one occluder (smaller than the original asset), 
    //  one occludee (larger than the original asset), and one which is the same size as the original.
    //  The processor constructs the output meshes based purely on the silhouette of the input, meaning
    //  that the resulting meshes are efficient proxies constructed to occlude, and be occluded by, 
    //  other meshes in occlusion culling rendering and shadow passes. Not suitable for self-shadowing, 
    //  since they are not depth-conservative, only silhouette-conservative.
    //
    ///////////////////////////////////////////////////////////////////////////
    
    #include "../Common/Example.h"
    
    void RunOcclusionProcessing( const std::string& readFrom, const std::string& writeTo, int onScreenSize, int error, int mode );
    
    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;
    
    /////////////////////////////////////////////////////////////////////
    // Main function with startup and shutdown code
    
    int main( int argc, char* argv[] )
        {
        try
        {
            InitExample();
    
            std::string assetPath = GetAssetPath();
    
            // Create occluder
            printf("Running wall asset, generating occluder...\n");
            PrintProgressBar(0); //Initial progress bar
            RunOcclusionProcessing(assetPath + "wall.obj", "wall_occluder", 100, 10, SG_OCCLUSIONMODE_OCCLUDER);
            printf("\nDone.\n\n");
    
            // Create occludee
            printf("Running wall asset, generating occludee...\n");
            PrintProgressBar(0); //Initial progress bar
            RunOcclusionProcessing(assetPath + "wall.obj", "wall_occludee", 100, 10, SG_OCCLUSIONMODE_OCCLUDEE);
            printf("\nDone.\n\n");
    
            // Create offscreen shadow mesh, neither larger nor smaller than the original.
            printf("Running wall asset, generating shadow mesh...\n");
            PrintProgressBar(0); //Initial progress bar
            RunOcclusionProcessing(assetPath + "wall.obj", "wall_standard", 100, 10, SG_OCCLUSIONMODE_STANDARD);
            printf("\nDone.\n\n");
    
            // Done!
            printf("All LODs complete, shutting down...");
            DeinitExample();
        }
        catch (const std::exception& ex)
        {
            std::cerr << ex.what() << std::endl;
            return -1;
        }
    
        return 0;
        }
    
    //////////////////////////////////////////////////////////////////////
    
    void RunOcclusionProcessing( const std::string& readFrom, const std::string& writeTo, int onScreenSize, int error, int mode )
        {
        //Setup output paths
        std::string outputGeomPath = GetExecutablePath() + writeTo + ".obj";
    
        //Load input geometry from file
        spWavefrontImporter objReader = sg->CreateWavefrontImporter();
        objReader->SetExtractGroups( false ); //This makes the .obj reader import into a single geometry object instead of multiple
        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();
        scene->GetMaterialTable()->Clear(); //No materials required for occlusion meshing
    
                                            //Create a processor
        spOcclusionMeshProcessor omProcessor = sg->CreateOcclusionMeshProcessor();
        omProcessor->SetScene( scene );
    
        //Set settings
        spOcclusionMeshSettings omSettings = omProcessor->GetOcclusionMeshSettings();
        omSettings->SetOnScreenSize( onScreenSize ); //Determines triangle count / mesh resolution. Generally, we recommend sizes around 100 pixels, currently the algorithm scales badly at larger sizes.
        omSettings->SetOcclusionMode( mode ); //This determines if the output will be smaller or larger than the input.
        omSettings->SetOnScreenErrorTolerance( error ); //This determines the accuracy of the silhouette reconstruction. 1 is the most accurate, larger is faster. Measured in pixels in worst-case setting, so you can easily get away with much larger values.
        //omSettings->SetTransferSkinning( true );
        //omSettings->SetInvertOutputMesh(true); //This inverts the winding, making frontfaces backfaces. Good for guaranteed conservative occluders.
    
        omProcessor->AddObserver( &progressObserver, SG_EVENT_PROGRESS ); //Add progress observer
    
                                                                          //Run the processing
        omProcessor->RunProcessing();
    
        //Create an .obj exporter to save our result
        spWavefrontExporter objExporter = sg->CreateWavefrontExporter();
    
        // Do the actual exporting
        objExporter->SetExportFilePath( outputGeomPath.c_str() );
        objExporter->SetScene( scene ); //scene now contains the remeshed geometry and the material table we modified above
        objExporter->RunExport();
    
        //Done!
        }
    
    Back to top Terms of Use | Privacy and cookies | Trademarks | Copyright © 2019 Microsoft