<< Click to Display Table of Contents >> Navigation: Simplygon 7.1 examples > VisibilityWeightExample.cpp |
///////////////////////////////////////////////////////////////////////////
//
// System: Simplygon
// File: VisibilityWeightExample.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#
//
// RunExample() will load a model and set some reduction settings. Then it
// will call VisibilitySettingsSetup() with the current iteration index.
// VisibilitySettingsSetup() will setup the visibility settings.
//
// VisibilitySettingsSetup() with "iteration":
//
// 0, will not use visibility in reducer or texture coordinate generator
//
// 1, will use visibility weights in both reducer and texture coordinate
// generator
//
// 2, will generate a bunch of camera views located on a hemisphere above
// the model and compute the visibility from them
//
// 3, will setup a camera path with an omni directional camera where to
// compute the visibility from
//
// 4, will setup another camera path where to compute the visibility from
// and cull triangles that aren't visible from the path
//
// 5, will setup an orthographic camera that will view the entire scene
// from a direction.
//
///////////////////////////////////////////////////////////////////////////
#include "../Common/Example.h"
void RunExample(const std::string& readFrom, const std::string& writeTo, bool use_occluder );
void VisibilitySettingsSetup( spScene scene, spVisibilitySettings visibility_settings, uint iteration );
int main( int argc , char* argv[] )
{
InitExample();
//Running visibility computations on the GPU is faster, but can generate different result between different machines
sg->SetGlobalSetting( "AllowGPUAcceleration" , false );
std::string assetPath = GetAssetPath();
//Run visibility example on a scene with a teapot inside an open box.
RunExample( assetPath + "ObscuredTeapot/ObscuredTeapot.obj", "ObscuredTeapot_LOD", false );
//Run visibility example on the teapot with the open box as an occluder.
//Note that the result of the teapot reduction in this case will be slightly
//different from the previous scene, since the open box as an occluder
//will not be included in the average visibility of scene geometry.
RunExample( assetPath + "ObscuredTeapot/Teapot.obj", "TeapotWithOccluder_LOD", true );
DeinitExample();
return 0;
}
void VisibilitySettingsSetup( spScene scene, spVisibilitySettings visibilitySettings, uint iteration )
{
switch( iteration )
{
case 0 :
// Without using visibility weights
// Using default settings of visibility_settings
break;
case 1 :
// Use visibility weights both in reducer and texture coordinate generator
// The reduction will use visibility weights when processing.
// Areas that are more visible will be preserved better.
// If regular vertex weights exist as well, then both will be used
visibilitySettings->SetUseVisibilityWeightsInReducer( true );
// The UV generator will create charts based on the visibility weights.
// Areas that are more visible will have greater UV space.
// If regular vertex weights exist as well, then both will be used
visibilitySettings->SetUseVisibilityWeightsInTexcoordGenerator( true );
break;
case 2 :
// Setup a bunch of camera views located above on a hemisphere
{
spSceneCamera sceneCamera = sg->CreateSceneCamera();
sceneCamera->SetCustomSphereCameraPath(
3, //Fidelity
0.0f, //Pitch angle
0.0f, //Yaw angle
90.0f //Coverage (degrees)
);
if(sceneCamera->ValidateCamera()) //If the camera is setup correctly
{
scene->GetRootNode()->AddChild(sceneCamera);
spSelectionSet selectionSet = sg->CreateSelectionSet();
selectionSet->AddItem(sceneCamera->GetNodeGUID());
rid cameraSelectionSetID = scene->GetSelectionSetTable()->AddItem(selectionSet);
visibilitySettings->SetCameraSelectionSetID(cameraSelectionSetID);
}
visibilitySettings->SetUseVisibilityWeightsInReducer( true );
visibilitySettings->SetUseVisibilityWeightsInTexcoordGenerator( true );
}
break;
case 3 :
// Setup a camera path manually where an omni directional camera use the same
// coordinate system as the model.
// One omni directional camera is placed inside the handle of the teapot and
// calculates visibility in all directions.
{
//Create a camera
spSceneCamera sceneCamera = sg->CreateSceneCamera();
//Get the camera position
spRealArray cameraPositions = sceneCamera->GetCameraPositions();
//Set the tuple count to 1
cameraPositions->SetTupleCount(1);
//Set the camera view
real xyz[] = {-11.32f, 8.654f, 0.204f};
cameraPositions->SetTuple(0, xyz);
// Have the camera view all directions around itself
sceneCamera->SetCameraType(SG_CAMERATYPE_OMNIDIRECTIONAL);
// Sets the camera coordinates to use the same coordinates system as the scene
sceneCamera->SetUseNormalizedCoordinates( false );
if(sceneCamera->ValidateCamera()) //If the camera is setup correctly
{
scene->GetRootNode()->AddChild(sceneCamera);
spSelectionSet cameraSelectionSet = sg->CreateSelectionSet();
cameraSelectionSet->AddItem(sceneCamera->GetNodeGUID());
rid selectionSetID = scene->GetSelectionSetTable()->AddSelectionSet(cameraSelectionSet);
visibilitySettings->SetCameraSelectionSetID(selectionSetID);
}
visibilitySettings->SetUseVisibilityWeightsInReducer( true );
visibilitySettings->SetUseVisibilityWeightsInTexcoordGenerator( true );
}
break;
case 4 :
// Setup a camera manually and cull triangles that are not visible
// The camera use a normalized (around the model) coordinate system.
{
//Create a camera
spSceneCamera sceneCamera = sg->CreateSceneCamera();
//Get the camera position and target position
spRealArray cameraPositions = sceneCamera->GetCameraPositions();
spRealArray targetPositions = sceneCamera->GetTargetPositions();
//Set the tuple count to 1
cameraPositions->SetTupleCount(1);
targetPositions->SetTupleCount(1);
// Have the camera in (0, 0, 3)
// Have it point to origin ( center of model )
real xyz[] = {0.0f,0.0f,3.0f};
real target[] = {0.0f,0.0f,0.0f};
cameraPositions->SetTuple(0, xyz);
targetPositions->SetTuple(0, target);
//Increase the resolution of the camera
int pixelResolution = 4096;
sceneCamera->SetPixelFieldOfView(sceneCamera->GetFieldOfView()/float(pixelResolution));
// Sets the camera coordinates to use normalized coordinates
sceneCamera->SetUseNormalizedCoordinates( true );
if(sceneCamera->ValidateCamera()) //If the camera is setup correctly
{
scene->GetRootNode()->AddChild(sceneCamera);
spSelectionSet selectionSet = sg->CreateSelectionSet();
selectionSet->AddItem(sceneCamera->GetNodeGUID());
rid cameraSelectionSetID = scene->GetSelectionSetTable()->AddItem(selectionSet);
visibilitySettings->SetCameraSelectionSetID(cameraSelectionSetID);
}
// Simply remove triangles that aren't visible
visibilitySettings->SetCullOccludedGeometry( true );
}
break;
case 5 :
//Setup an orthographic camera that will view the entire scene from a set direction
{
//Create a camera
spSceneCamera sceneCamera = sg->CreateSceneCamera();
//Make it orthographic
sceneCamera->SetCameraType(SG_CAMERATYPE_ORTHOGRAPHIC);
//Decide the size of the orthographic pixels
//This should correspond to the size of details in the scene that should be preserved
real smallSceneSize = scene->GetRadius()/500.0f;
//We want to make sure there aren't small patches of non visible triangles (surrounded by visible triangle)
//that are culled from the scene. It is better to keep those non-visible triangles if we want to do a good job
//with the reducer and the tex-coord generator
real smallArea = (scene->GetRadius()/40.0f)*(scene->GetRadius()/40.0f);
visibilitySettings->SetFillNonVisibleAreaThreshold(smallArea);
sceneCamera->SetOrthographicCameraPixelSize(smallSceneSize);
//Get the camera position and target position
spRealArray cameraPositions = sceneCamera->GetCameraPositions();
spRealArray targetPositions = sceneCamera->GetTargetPositions();
//Set the tuple count to 1
cameraPositions->SetTupleCount(1);
targetPositions->SetTupleCount(1);
//When you have an orthographic camera,
//the position and target are only used to determine the direction
//of the camera
real xyz[] = {1.0f,1.0f,1.0f};
real target[] = {0.0f,0.0f,0.0f};
cameraPositions->SetTuple(0, xyz);
targetPositions->SetTuple(0, target);
if(sceneCamera->ValidateCamera()) //If the camera is setup correctly
{
scene->GetRootNode()->AddChild(sceneCamera);
spSelectionSet selectionSet = sg->CreateSelectionSet();
selectionSet->AddItem(sceneCamera->GetNodeGUID());
rid cameraSelectionSetID = scene->GetSelectionSetTable()->AddItem(selectionSet);
visibilitySettings->SetCameraSelectionSetID(cameraSelectionSetID);
}
// Simply remove triangles that aren't visible
visibilitySettings->SetCullOccludedGeometry( true );
}
break;
default :
break;
}
}
void RunExample( const std::string& readFrom, const std::string& writeTo, bool UseOccluder )
{
char * outputFilenameDescription[] = { "regular", "weighted", "multiple_cameras_above_in_custom_sphere", "custom_point_camera_in_teapot_handle", "custom_camera_culled_triangles", "orthographic_camera" };
// Run all iterations, showing different uses of the visibility weights
for( uint i = 0 ; i < 6 ; ++i )
{
// Run reduction with some basic settings.
// The triangle count will be reduced to 10% of the original input, and
// depending on if "useVisibilityWeights" is set or not, hidden triangles will
// be more likely to be removed. The LOD is then stored to file.
std::string outputGeometryFilename = GetExecutablePath() + writeTo + "_" + std::to_string(i) + "_" + outputFilenameDescription[i] + ".obj";
std::string outputDiffuseTextureFilename = GetExecutablePath() + writeTo + "_" + std::to_string(i) + "_" + outputFilenameDescription[i] + ".png";
// Load from file
spWavefrontImporter objReader = sg->CreateWavefrontImporter();
objReader->SetImportFilePath(readFrom.c_str());
if( !objReader->RunImport() )
return;
spScene scene = objReader->GetScene();
spMaterialTable materials = scene->GetMaterialTable();
// Create the reduction-processor.
spReductionProcessor red = sg->CreateReductionProcessor();
red->SetScene(scene);
// Get the Reduction Settings.
spReductionSettings reductionSettings = red->GetReductionSettings();
// Below in the "UseOccluder" part we will add IGeometryData objects to the scene that will only be used to occlude the scene.
// To only process the scene objects we currently have (i.e. how to exclude the geometries that are occluders),
// we create a selection set with all the current meshes and tell the reducer to only reduce these objects.
int processSelectionSetID = scene->SelectNodes("ISceneMesh"); //Selects all the ISceneMeshes in the scene and returns the index of the selection set
reductionSettings->SetProcessSelectionSetID( processSelectionSetID );
// Will reduce to 3/10 of the original trianglecount.
reductionSettings->SetTriangleRatio( 0.30f );
// Just to show how generated tex-coords are affected by visibility
spMappingImageSettings mappingImageSettings = red->GetMappingImageSettings();
mappingImageSettings->SetGenerateTexCoords( true );
mappingImageSettings->SetGenerateMappingImage( true );
spVisibilitySettings visibilitySettings = red->GetVisibilitySettings();
//Sets the visibility settings for each iteration
VisibilitySettingsSetup( scene, visibilitySettings, i );
if( UseOccluder )
{
// Load occluder from file
objReader = sg->CreateWavefrontImporter();
objReader->SetImportFilePath( (GetAssetPath() + "ObscuredTeapot/occluder.obj").c_str() );
if( !objReader->RunImport() )
return;
spScene occluderScene = objReader->GetScene();
// Get the geometries from the scene
spSelectionSet selectionSceneMeshes = occluderScene->GetSelectionSetTable()->GetSelectionSet(occluderScene->SelectNodes("ISceneMesh"));
// Add the geometries from the occluder scene as occluders to the scene we loaded before
for(uint i = 0 ; i < selectionSceneMeshes->GetItemCount() ; ++i)
{
spGeometryData occluderGeometry = Cast<ISceneMesh>(occluderScene->GetNodeByGUID(selectionSceneMeshes->GetItem(i)))->GetGeometry();
spSceneMesh occluderSceneMesh = scene->GetRootNode()->CreateChildMesh(occluderGeometry);
spSelectionSet occluderSelectionSet = sg->CreateSelectionSet();
occluderSelectionSet->AddItem(occluderSceneMesh->GetNodeGUID());
rid occluderSelectionSetID = scene->GetSelectionSetTable()->AddSelectionSet(occluderSelectionSet);
visibilitySettings->SetOccluderSelectionSetID(occluderSelectionSetID);
}
}
red->RunProcessing();
spMappingImage mappingImage = red->GetMappingImage();
spMaterialTable outputMaterials = sg->CreateMaterialTable();
spMaterial outputMaterial = sg->CreateMaterial();
outputMaterials->AddMaterial( outputMaterial );
spColorCaster colorCaster = sg->CreateColorCaster();
colorCaster->SetMappingImage( mappingImage );
colorCaster->SetSourceMaterials( materials );
colorCaster->SetColorType( SG_MATERIAL_CHANNEL_DIFFUSE );
colorCaster->SetOutputChannels( 3 );
colorCaster->SetDestMaterial( outputMaterial );
colorCaster->SetOutputFilePath( outputDiffuseTextureFilename.c_str() );
colorCaster->CastMaterials();
// Set material to point to created texture filename.
outputMaterial->SetTexture( SG_MATERIAL_CHANNEL_DIFFUSE , outputDiffuseTextureFilename.c_str() );
scene->GetMaterialTable()->Copy(outputMaterials);
// Store to file
spWavefrontExporter objexp = sg->CreateWavefrontExporter();
objexp->SetScene(scene);
objexp->SetSelectionSet(processSelectionSetID); //Only output the LOD meshes (not the occluders)
objexp->SetExportFilePath( outputGeometryFilename.c_str() );
objexp->RunExport();
}
}