<< 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])
);
}