Show / Hide Table of Contents
    ///////////////////////////////////////////////////////////////////////////
    //
    //  System:    Simplygon
    //  File:      GeomorphExample.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# Shows how to use Geomorph. A scene is loaded, and some
    //  of the geometries in the scene are selected for reduction.
    //  The processed scene will contain reduced geometry mesh nodes,
    //  each of which in turn holds an additional child mesh node containing
    //  a geomorph geometry that shows how original vertices have moved during
    //  reduction. Blend geometries between original and geomorph geometries are
    //  then generated in steps of 1/10 and stored to file, to show how the
    //  morph-data can be used.
    //
    ///////////////////////////////////////////////////////////////////////////
    
    #include "../Common/Example.h"
    
    void RunHighQualityReduction( const std::string& readFrom );
    void MorphGeometry( spGeometryData Orig, spGeometryData Morph, spGeometryData Blend, real blend_val );
    
    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;
    
    int main( int argc, char* argv[] )
        {
        try
        {
            InitExample();
    
            // Before any specific processing starts, set global variables. 
            // Using Orthonormal method for calculating tangentspace.
            sg->SetGlobalSetting("DefaultTBNType", SG_TANGENTSPACEMETHOD_ORTHONORMAL);
    
            std::string assetPath = GetAssetPath();
    
            // Run HQ reduction example, reducing a single geometry to a single LOD
            printf("Running HQ reduction... \n");
            PrintProgressBar(0);
            RunHighQualityReduction(assetPath + "SimplygonMan/SimplygonMan.obj");
            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 RunHighQualityReduction( const std::string& readFrom )
        {
        // Load input geometry from file
        spWavefrontImporter objReader = sg->CreateWavefrontImporter();
        objReader->SetExtractGroups( true ); //This makes the .obj reader import each group into a separate scene mesh node
        objReader->SetImportFilePath( readFrom.c_str() );
        if( !objReader->RunImport() )
            throw std::exception("Failed to load input file!");
    
        spScene lodScene;
        spScene originalScene;
        spScene blendScene;
    
        originalScene = objReader->GetScene();
    
        // Create a selection-set with all mesh nodes.
        int mesh_nodes_id = originalScene->SelectNodes( "ISceneMesh" );
        spSelectionSet mesh_nodes = originalScene->GetSelectionSetTable()->GetSelectionSet( mesh_nodes_id );
    
        // Copy the original scene. One to be used for morphing the geometry, and one to send to the ReductionProcessor.
        lodScene = originalScene->NewCopy();
        blendScene = originalScene->NewCopy();
    
        // Select all nodes that contain the word "dman", which all parts that belong to the characters in the scene do.
        spSelectionSet selectionSet = sg->CreateSelectionSet();
        std::string dman_string = std::string( "dman" );
    
        for( uint i = 0; i < mesh_nodes->GetItemCount(); ++i )
            {
            std::string mesh_name = std::string( lodScene->GetNodeByGUID( mesh_nodes->GetItem( i ) )->GetName() );
    
            if( mesh_name.find( dman_string ) != std::string::npos )
                {
                spSceneMesh mesh = Cast<ISceneMesh>( lodScene->GetNodeByGUID( mesh_nodes->GetItem( i ) ) );
                selectionSet->AddItem( mesh->GetNodeGUID() );
                }
            }
    
        rid selection_set_id = lodScene->GetSelectionSetTable()->AddSelectionSet( selectionSet );
    
        // Create the reduction-processor, and set the geometry to reduce
        spReductionProcessor reductionProcessor = sg->CreateReductionProcessor();
        reductionProcessor->SetScene( lodScene );
    
        ///////////////////////////////////////////////////////////////////////////////////////////////
        // SETTINGS - Most of these are set to the same value by default, but are set anyway for clarity
    
        // The reduction settings object contains settings pertaining to the actual decimation
        spReductionSettings reductionSettings = reductionProcessor->GetReductionSettings();
    
        reductionSettings->SetProcessSelectionSetID( selection_set_id );
    
        reductionSettings->SetCreateGeomorphGeometry( true ); // Set to create a GeomorphGeometry. Fetched after processing with "reductionProcessor->GetGeomorphGeometry();"
        reductionSettings->SetUseSymmetryQuadRetriangulator( false ); // Cant be used at the same time as creating GeomorphGeometry, since the connectivity to the triangles will change and muck things up.
    
        reductionProcessor->GetNormalCalculationSettings()->SetReplaceNormals( true );
        reductionProcessor->GetNormalCalculationSettings()->SetHardEdgeAngleInRadians( 3.14159f * 60.f / 180.0f );
    
        // Reduce the scene to 10% of the original triangle-count.
        reductionSettings->SetStopCondition( SG_STOPCONDITION_ANY );
        reductionSettings->SetReductionTargets( SG_REDUCTIONTARGET_TRIANGLERATIO );
        reductionSettings->SetTriangleRatio( 0.1f );
    
        // The repair settings object contains settings for the pre-processing block
        spRepairSettings repairSettings = reductionProcessor->GetRepairSettings();
        repairSettings->SetWeldDist( 0.0f );
        repairSettings->SetUseTJunctionRemover( false ); // Cant be used at the same time as creating GeomorphGeometry, since new triangles are created and then we cant blend them.
    
        //END SETTINGS 
        ///////////////////////////////////////////////////////////////////////////////////////////////
        reductionProcessor->AddObserver( &progressObserver, SG_EVENT_PROGRESS );
        // Run the actual processing. After this, the set geometry will have been reduced according to the settings
        reductionProcessor->RunProcessing();
    
    
        // Selection set to collect geomorph nodes in scene
        spSelectionSet geomorphSelectionSet = sg->CreateSelectionSet();
    
        // Morph the geometry, 10 % each step.
        for( float blend_val = 0.0f; blend_val <= 1.0f; blend_val += 0.1f )
            {
    
            // The LOD scene contains morphed geometries, placed as children of their respective reduced geometry mesh node.
            // The name of a morph mesh node is the same as its parent, with "_geomorph" added.
            for( uint i = 0; i < mesh_nodes->GetItemCount(); ++i )
                {
                spSceneMesh mesh = Cast<ISceneMesh>( originalScene->GetNodeByGUID( mesh_nodes->GetItem( i ) ) );
                spSceneMesh lod = Cast<ISceneMesh>( lodScene->GetNodeByGUID( mesh_nodes->GetItem( i ) ) );
                spSceneMesh morph = NULL;
                spSceneMesh blend = Cast<ISceneMesh>( blendScene->GetNodeByGUID( mesh_nodes->GetItem( i ) ) );
    
                uint num_children = lod->GetChildCount();
                for( uint j = 0; j < num_children; j++ )
                    {
                    std::string child_name = std::string( lod->GetChild( j )->GetName() );
                    std::string morph_name = std::string( "_geomorph" );
    
                    if( child_name.find( morph_name ) != std::string::npos )
                        {
                        morph = Cast<ISceneMesh>( lod->GetChild( j ) );
                        //printf("Found morph mesh for LOD ");
                        //printf( lod->GetName() );
                        //printf("\n");
    
                        // Add to selection set
                        geomorphSelectionSet->AddItem( morph->GetNodeGUID() );
    
                        // Morph the geometry and store it into the mesh from the blend-scene.
                        MorphGeometry( mesh->GetGeometry(), morph->GetGeometry(), blend->GetGeometry(), blend_val );
    
                        break;
                        }
                    }
                }
    
            // Save the blend-scene to file.
            spWavefrontExporter exp = sg->CreateWavefrontExporter();
            exp->SetScene( blendScene );
    
            std::string output_name = std::string( "BlendedGeometry" ) + std::to_string( blend_val ) + ".obj";
            exp->SetExportFilePath( output_name.c_str() );
            exp->RunExport();
            }
    
        // Also store the LOD to file.
        // Remove all geomorph nodes first.
        rid geomorph_selection_set_id = lodScene->GetSelectionSetTable()->AddSelectionSet( geomorphSelectionSet );
        lodScene->RemoveSceneNodes( geomorph_selection_set_id );
    
        spWavefrontExporter exp = sg->CreateWavefrontExporter();
        exp->SetScene( lodScene );
    
        std::string output_name = "LodGeom.obj";
        exp->SetExportFilePath( output_name.c_str() );
        exp->RunExport();
    
        //Done! LOD created.
        }
    
    void ArrayBlend( spRealArray TargetArray, spRealArray OrigArray, spRealArray MorphArray, real blend_val )
        {
    
        for( uint i = 0; i < TargetArray->GetItemCount(); i++ )
            {
            real tmp = OrigArray->GetItem( i )*blend_val + MorphArray->GetItem( i )*(1.0f - blend_val);
            TargetArray->SetItem( i, tmp );
            }
    
        }
    
    void MorphGeometry( spGeometryData Orig, spGeometryData Morph, spGeometryData Blend, real blend_val )
        {
    
        spRealArray TargetArray, OrigArray, MorphArray;
        spRidArray TargetVertexIds, OrigVertexIds, MorphVertexIds;
    
        //-------------------------------------------------------------
        // Morph the Coords
        //-------------------------------------------------------------
        TargetArray = Blend->GetCoords();
        OrigArray = Orig->GetCoords();
        MorphArray = Morph->GetCoords();
    
        TargetVertexIds = Blend->GetVertexIds();
        OrigVertexIds = Orig->GetVertexIds();
        MorphVertexIds = Morph->GetVertexIds();
    
        // For each corner:
        for( uint c = 0; c < TargetVertexIds->GetItemCount(); ++c )
            {
            // For each x,z,y value in each coordinate:
            for( uint d = 0; d < 3; d++ )
                {
                real tmp = OrigArray->GetItem( OrigVertexIds->GetItem( c ) * 3 + d )*blend_val + MorphArray->GetItem( MorphVertexIds->GetItem( c ) * 3 + d )*(1.0f - blend_val);
                TargetArray->SetItem( TargetVertexIds->GetItem( c ) * 3 + d, tmp );
                }
            }
    
        //-------------------------------------------------------------
        // Morph the UVs
        //-------------------------------------------------------------
        TargetArray = Blend->GetTexCoords( 0 );
        OrigArray = Orig->GetTexCoords( 0 );
        MorphArray = Morph->GetTexCoords( 0 );
    
        if( TargetArray )
            ArrayBlend( TargetArray, OrigArray, MorphArray, blend_val );
    
        //-------------------------------------------------------------
        // Morph the Normals
        //-------------------------------------------------------------
        TargetArray = Blend->GetNormals();
        OrigArray = Orig->GetNormals();
        MorphArray = Morph->GetNormals();
    
        if( TargetArray )
            ArrayBlend( TargetArray, OrigArray, MorphArray, blend_val );
    
        //-------------------------------------------------------------
        // Morph the Tangents
        //-------------------------------------------------------------
        TargetArray = Blend->GetTangents( 0 );
        OrigArray = Orig->GetTangents( 0 );
        MorphArray = Morph->GetTangents( 0 );
    
        if( TargetArray )
            ArrayBlend( TargetArray, OrigArray, MorphArray, blend_val );
    
        //-------------------------------------------------------------
        // Morph the Bitangents
        //-------------------------------------------------------------
        TargetArray = Blend->GetBitangents( 0 );
        OrigArray = Orig->GetBitangents( 0 );
        MorphArray = Morph->GetBitangents( 0 );
    
        if( TargetArray )
            ArrayBlend( TargetArray, OrigArray, MorphArray, blend_val );
    
        }
    
    Back to top Terms of Use | Privacy and cookies | Trademarks | Copyright © 2019 Microsoft