VertexWeightExample.cpp

<< Click to Display Table of Contents >>

Navigation:  Simplygon 7.1 examples >

VertexWeightExample.cpp

///////////////////////////////////////////////////////////////////////////
//
//  System:    Simplygon
//  File:      VertexWeightExample.cpp
//  Language:  C++
//
//  Copyright (c) 2015 Donya Labs AB. All rights reserved.
//
///////////////////////////////////////////////////////////////////////////
//
//  #Description#
//
//  A scene containing a model with a lot of small details is loaded.
//  The scene is processed and an LOD is generated for a defined pixel
//  size on screen.
//
//  Then we reload the scene and compute vertex weights. Every vertex gets
//  a weight depending on its distance to the extreme corner of the scene.
//  The further away, the smaller the weight.
//  (Vertex weights are values between 1/8 and 8, set by the user, to
//  particular parts of the scene that should be reduced more aggressively
//  or less. Vertices with higher values are decimated more.)
//  Then the scene is processed again but using the vertex weights.
//
//  Both processed scenes are exported. To see the results, toggle wireframe
//  when viewing the models to see the gradient of remaining detail on the
//  scene that used vertex weights.
//
//
///////////////////////////////////////////////////////////////////////////
#include "../Common/Example.h"
#include "../Common/Vector3D.h"
#include "../Common/Matrix4x4.h"
void RunExample(const std::string& readFrom);
void ComputeVertexWeightsForScene( spScene scene );
void RunReductionProcessing( spScene scene , int onScreenSize, bool useVertexWeights );
real Distance3D( real vec0[3], real vec1[3] );
int main( int argc , char* argv[] )
    {
    // init SDK
    InitExample();
    std::string assetPath = GetAssetPath();
    // Run the example code
    RunExample( assetPath + "Chain/chain.obj" );
    // deinit SDK
    DeinitExample();
    return 0;
    }
void RunExample(const std::string& readFrom)
    {
    bool useVertexWeights;
    // Load the scene and process it without using vertex weights
    useVertexWeights = false;
    if(true)
        {
        spWavefrontImporter objReader = sg->CreateWavefrontImporter();
        objReader->SetImportFilePath(readFrom.c_str());
        if(!objReader->RunImport())
            return;
        // Get the scene from the importer
        spScene scene = objReader->GetScene();
        // reduce the geometry, using on screen size
        printf("Reducing using on screen size without VertexWeighting...\n");
        RunReductionProcessing( scene , 300, useVertexWeights );
        // store the reduced geometry to a wavefront file
        std::string outputObjPath = GetExecutablePath() + "processed_scene_without_vertex_weights.obj";
        spWavefrontExporter objExporter = sg->CreateWavefrontExporter();
        objExporter->SetScene(scene);
        objExporter->SetExportFilePath(outputObjPath.c_str());
        objExporter->RunExport();
        }
    // Load the scene and process it while using vertex weights
    // the vertex weights are manually computed when the scene has been loaded
    useVertexWeights = true;
    if(true)
        {
        spWavefrontImporter objReader = sg->CreateWavefrontImporter();
        objReader->SetImportFilePath(readFrom.c_str());
        if(!objReader->RunImport())
            return;
        // Get the scene from the importer
        spScene scene = objReader->GetScene();
        ComputeVertexWeightsForScene(scene);
        // reduce the geometry, using on screen size
        printf("Reducing using on screen size with VertexWeighting...\n");
        RunReductionProcessing( scene , 300, useVertexWeights );
        // store the reduced geometry to a wavefront file
        std::string outputObjPath = GetExecutablePath() + "processed_scene_with_vertex_weights.obj";
        spWavefrontExporter objExporter = sg->CreateWavefrontExporter();
        objExporter->SetScene(scene);
        objExporter->SetExportFilePath(outputObjPath.c_str());
        objExporter->RunExport();
        }
    }
void ComputeVertexWeightsForScene( spScene scene )
    {
    // Computes vertex weights for the scene.
    // We get the extents (inf/sup) of the scene and set every vertex weight based on its distance to one of the extreme corners.
    // The further from the inferior the vertices are, the smaller their weights become
    // Get the inf/sup extents of the scene
    scene->CalculateExtents();
    real inf[3], sup[3];
    scene->GetInf(inf);
    scene->GetSup(sup);
    real diameter = Distance3D(sup, inf);
    // Extract all geometries and set the weights
    spSelectionSet selectAllMeshNodes = scene->GetSelectionSetTable()->GetSelectionSet( scene->SelectNodes("ISceneMesh") );
    for( uint i = 0 ; i < selectAllMeshNodes->GetItemCount() ; ++i )
        {
        spGeometryData geom = Cast<ISceneMesh>(scene->GetNodeByGUID(selectAllMeshNodes->GetItem(i)))->GetGeometry();
        if(!geom->GetVertexWeighting())
            geom->AddVertexWeighting();
        spRealArray vertexWeights = geom->GetVertexWeighting();
        spRealArray coordinates = geom->GetCoords();
        for(uint v = 0 ; v < geom->GetVertexCount() ; ++v)
            {
            spRealData xyz = sg->CreateRealData();
            coordinates->GetTuple(v, xyz);
            real distanceFromInf = Distance3D(xyz->GetData(), inf);
            //Normalize distanceFromInf with the scene diameter
            distanceFromInf = distanceFromInf / diameter;
            distanceFromInf = (distanceFromInf > 1.0) ? 1.0f : distanceFromInf; //Max 1.0
            //Distance 0.0 -> 1.0f
            //should give approx
            //Weights 5.0 -> 0.2
            real weight = exp(3.14159f * (distanceFromInf - 0.5f));
            vertexWeights->SetItem(v, weight);
            }
        }
    }
void RunReductionProcessing( spScene scene , int onScreenSize, bool useVertexWeights )
    {
    // Create the reduction processor. Set the scene that is to be processed
    spReductionProcessor red = sg->CreateReductionProcessor();
    red->SetScene(scene);
    ///////////////////////////////////////////////////
    //
    // Set the RepairSettings. Current settings will mean that all visual gaps will remain in the geometry and thus
    // hinder the reduction on geometries that contains gaps, holes and tjunctions.
    spRepairSettings repair_settings = red->GetRepairSettings();
    // Only vertices that actually share the same position will be welded together
    repair_settings->SetWeldDist( 0.0f );
    // Only t-junctions with no actual visual distance will be fixed.
    repair_settings->SetTjuncDist( 0.0f );
    ///////////////////////////////////////////////////
    //
    // Set the Reduction Settings.
    spReductionSettings reduction_settings = red->GetReductionSettings();
    // Make the LOD optimized for the number of pixels on screen
    reduction_settings->SetOnScreenSize(onScreenSize);
    reduction_settings->SetUseVertexWeights( useVertexWeights );
    ///////////////////////////////////////////////////
    //
    // Set the Normal Calculation Settings.
    spNormalCalculationSettings normal_settings = red->GetNormalCalculationSettings();
    // Will completely recalculate the normals.
    normal_settings->SetReplaceNormals( true );
    normal_settings->SetHardEdgeAngleInRadians( 3.14159f * 90.f / 180.0f );   
    // Run the process
    red->RunProcessing();   
    }
real Distance3D( real vec0[3], real vec1[3] )
    {
    return sqrt(
        (vec0[0]-vec1[0])*(vec0[0]-vec1[0])+
        (vec0[1]-vec1[1])*(vec0[1]-vec1[1])+
        (vec0[2]-vec1[2])*(vec0[2]-vec1[2])
        );
    }