GeometryExample.cpp

<< Click to Display Table of Contents >>

Navigation:  Simplygon 7.1 examples >

GeometryExample.cpp

///////////////////////////////////////////////////////////////////////////
//
//  System:    Simplygon
//  File:      GeomorphExample.cpp
//  Language:  C++
//
//  Copyright (c) 2015 Donya Labs AB. 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 progress_observer : 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
                printf ( " Progress : %d %% \n" , val );
                }
            }
    } progress_observer_object ;
int main( int argc , char* argv[] )
    {
    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... ");
    RunHighQualityReduction( assetPath + "CombineScene/scene.obj" );
    printf("Done.\n");
    // Done!
    printf("\nAll LODs complete, shutting down...");
    DeinitExample();
    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() )
        return;
    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( & progress_observer_object , 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 );   
    }