///////////////////////////////////////////////////////////////////////////
//
// System: Simplygon
// File: TextureVertexWeightsExample.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#
// A geometry with diffuse textures are loaded. The geometry is assigned
// vertex weights which will determine how important the areas are.
//
// The geometry is reduced to 90% triangles remaining and a materialLOD is
// generated assisted by the vertex weights.
//
// The areas with larger vertex weights will get a larger proportional
// size of the UV texture space area.
//
//
///////////////////////////////////////////////////////////////////////////
#include "../Common/Example.h"
void RunExample( const std::string& readFrom, const std::string& writeTo );
int main( int argc, char* argv[] )
{
try
{
InitExample();
// Set global variable. Using Orthonormal method for calculating
// tangentspace.
sg->SetGlobalSetting("DefaultTBNType", SG_TANGENTSPACEMETHOD_ORTHONORMAL);
std::string assetPath = GetAssetPath();
// Run the example code
RunExample(assetPath + "SimplygonMan/SimplygonMan.obj", "SimplygonMan_LOD");
DeinitExample();
}
catch (const std::exception& ex)
{
std::cerr << ex.what() << std::endl;
return -1;
}
return 0;
}
//Sets the vertices in the "top" part of the model to larger values than the bottom part
void SetVertexWeights( spGeometryData geom )
{
//Get the axis aligned bounding box values
real inf[3];
real sup[3];
geom->GetInf( inf );
geom->GetSup( sup );
// compute the threshold y-axis value
// all vertices located above this will have larger weights
float threshold_y = 0.2f * inf[1] + 0.8f * sup[1];
if( geom->GetVertexWeighting() == NULL )
{
geom->AddVertexWeighting();
}
spRealArray vertex_weights = geom->GetVertexWeighting();
spRealArray vertex_coords = geom->GetCoords();
for( unsigned int v = 0; v < vertex_weights->GetItemCount(); ++v )
{
real y = vertex_coords->GetItem( v * 3 + 1 );
if( y > threshold_y )
{
vertex_weights->SetItem( v, 5.0f );
}
else
{
vertex_weights->SetItem( v, 1.0f );
}
}
}
void RunExample( const std::string& readFrom, const std::string& newName )
{
// Run reduction with some basic settings.
// Generate the output filenames
std::string output_geometry_filename = GetExecutablePath() + newName + ".obj";
std::string output_diffuse_filename = GetExecutablePath() + newName + "_diffuse.png";
// Load from file
spWavefrontImporter objReader = sg->CreateWavefrontImporter();
objReader->SetImportFilePath( readFrom.c_str() );
if( !objReader->RunImport() )
throw std::exception("Failed to load input file!");
spScene originalScene = objReader->GetScene();
spMaterialTable originalMaterials = originalScene->GetMaterialTable();
spTextureTable originalTextures = originalScene->GetTextureTable();
spScene lodScene = sg->CreateScene();
spGeometryData lodGeometry = originalScene->NewCombinedGeometry();
lodScene->GetRootNode()->CreateChildMesh( lodGeometry );
SetVertexWeights( lodGeometry );
// Create the reduction-processor.
spReductionProcessor red = sg->CreateReductionProcessor();
red->SetScene( lodScene );
// Get the Reduction Settings.
spReductionSettings reduction_settings = red->GetReductionSettings();
// Will reduce to 9/10 of the original trianglecount.
reduction_settings->SetTriangleRatio( 0.90f );
//Mapping image settings
spMappingImageSettings mapping_image_settings = red->GetMappingImageSettings();
mapping_image_settings->SetGenerateMappingImage( true );
mapping_image_settings->SetUseFullRetexturing( true );
// Set to generate new texture coordinates.
mapping_image_settings->SetGenerateTexCoords( true );
// The higher the number, the fewer texture-borders.
mapping_image_settings->SetParameterizerMaxStretch( 0.6f );
// Buffer space for when texture is mip-mapped, so color values dont blend over.
mapping_image_settings->SetGutterSpace( 1 );
mapping_image_settings->SetUseAutomaticTextureSize( false );
mapping_image_settings->SetWidth( 512 );
mapping_image_settings->SetHeight( 512 );
mapping_image_settings->SetMultisamplingLevel( 2 );
//Set the mapping image to use vertex weights
//This means that areas with larger vertex weights receive larger texture space
mapping_image_settings->SetUseVertexWeights( true );
red->RunProcessing();
// Mapping image is needed later on for texture casting.
spMappingImage mapping_image = red->GetMappingImage();
spTextureTable lodTexTable = lodScene->GetTextureTable();
lodTexTable->Clear();
spMaterialTable lodMaterials = lodScene->GetMaterialTable();
lodMaterials->Clear();
// Create new material for the table.
spMaterial output_material = sg->CreateMaterial();
output_material->SetName( "example_material" );
lodMaterials->AddMaterial( output_material );
// Cast diffuse texture data
{
// Cast the data using a color caster
spColorCaster cast = sg->CreateColorCaster();
cast->SetColorType( SG_MATERIAL_CHANNEL_DIFFUSE );
cast->SetSourceMaterials( originalMaterials );
cast->SetSourceTextures( originalTextures );
cast->SetMappingImage( mapping_image ); // The mapping image we got from the remeshing process.
cast->SetOutputChannels( 3 ); // RGB, 3 channels! (1 would be for gray scale, and 4 would be for RGBA.)
cast->SetOutputChannelBitDepth( 8 ); // 8 bits per channel. So in this case we will have 24bit colors RGB.
cast->SetDilation( 10 ); // To avoid mip-map artifacts, the empty pixels on the map needs to be filled to a degree as well.
cast->SetOutputFilePath( output_diffuse_filename.c_str() ); // Where the texture map will be saved to file.
cast->RunProcessing(); // Fetch!
// Set material to point to created texture filename.
spTexture newTex = sg->CreateTexture();
newTex->SetFilePath( output_diffuse_filename.c_str() );
newTex->SetName( "Diffuse" );
lodTexTable->AddTexture( newTex );
spShadingTextureNode texNode = sg->CreateShadingTextureNode();
texNode->SetTextureName( "Diffuse" );
output_material->SetShadingNetwork( SG_MATERIAL_CHANNEL_DIFFUSE, texNode );
}
// Store to file
spWavefrontExporter objexp = sg->CreateWavefrontExporter();
objexp->SetExportFilePath( output_geometry_filename.c_str() );
objexp->SetScene( lodScene );
objexp->RunExport();
}