///////////////////////////////////////////////////////////////////////////
//
// System: Simplygon
// File: ChartAggregatorExample.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#
//
// Sets up a scene from an OBJ file and creates an aggregate
// UV layout for all mesh parts, while preserving original charts.
// Four different layouts are produced, where charts are scaled differently:
// - Equal scaling
// - Scaling weighted based on the charts' corresponding area in 3D space
// - Scaling weighted based on the corresponding material texture sizes
// - Scaling charts to perfectly reproduce the pixel density of the input textures
//
// To view the results, load the outputted scenes and view the texture coords.
//
// No new materials are baked in this example, only new UVs are computed.
// Check out AggregationProcessorExample for aggregating scenes and baking
// the materials.
//
///////////////////////////////////////////////////////////////////////////
#include "../Common/Example.h"
void RunChartAggregation(const std::string& readFrom,
const std::string& writeToUnWeighted,
const std::string& writeToAreaWeighted,
const std::string& writeToOriginalTextureWeighted,
const std::string& writeToPreserveOriginalUVDensity);
int main(int argc, char* argv[])
{
try
{
InitExample();
std::string assetPath = GetAssetPath();
// Run the example code
//
RunChartAggregation(assetPath + "TexturedPlanes/texturedplanes.obj", "result_unweighted", "result_areaWeighted", "result_originalTextureWeighted", "result_PreserveOriginalUVDensity");
DeinitExample();
}
catch (const std::exception& ex)
{
std::cerr << ex.what() << std::endl;
return -1;
}
return 0;
}
void RunChartAggregation(const std::string& readFrom,
const std::string& writeToUnWeighted,
const std::string& writeToAreaWeighted,
const std::string& writeToOriginalTextureWeighted,
const std::string& writeToPreserveOriginalUVDensity
)
{
std::string exePath = GetExecutablePath();
// Import geometries from a file and optimize them.
//
std::string output_unweighted_filename = exePath + writeToUnWeighted + ".obj";
std::string output_areaweighted_filename = exePath + writeToAreaWeighted + ".obj";
std::string output_textureweighted_filename = exePath + writeToOriginalTextureWeighted + ".obj";
std::string output_preservedpixeldensity_filename = exePath + writeToPreserveOriginalUVDensity + ".obj";
// Load object from file.
// Have the importer combine all groups into one geometry.
//
spWavefrontImporter objReader = sg->CreateWavefrontImporter();
objReader->SetExtractGroups(false);
objReader->SetImportFilePath(readFrom.c_str());
if (!objReader->RunImport())
throw std::exception("Failed to load input file!");
spScene scene = objReader->GetScene();
spSceneMesh sceneMesh = SafeCast<ISceneMesh>(scene->GetRootNode()->GetChild(0));
spGeometryData originalGeometry = sceneMesh->GetGeometry();
// The working geometry have multiple overlapping UV charts, since
// several meshes were combined into one geometry.
// Now, create new chart-disjoint UV layouts by running the
// chart aggregator.
//
spChartAggregator chartAggregator = sg->CreateChartAggregator();
// If multiple parts of the mesh have the same texcoords, you can either select to
// only generate one instance of the repeating texture or one instance for each
// time it is used. This is controlled with the SeparateOverlappingCharts flag.
// If charts are overlapping in the original texture coords, they will be separated if
// SeparateOverlappingCharts is set to true.
//
chartAggregator->SetSeparateOverlappingCharts(true);
chartAggregator->SetMaterialTable(scene->GetMaterialTable());
chartAggregator->SetTextureTable(scene->GetTextureTable());
chartAggregator->SetTexCoordLevel(0);
chartAggregator->SetTextureWidth(1024);
chartAggregator->SetTextureHeight(1024);
chartAggregator->SetGutterSpace(4);
spWavefrontExporter objExporter = sg->CreateWavefrontExporter();
// Unweighted layout (i.e. all charts are scaled with the same factor, so sizes correspond to the proportions defined by their old UVs)
//
spGeometryData workingGeometry = originalGeometry->NewCopy(true);
chartAggregator->SetChartAggregatorMode(SG_CHARTAGGREGATORMODE_UVSIZEPROPORTIONS);
chartAggregator->Parameterize(workingGeometry, workingGeometry->GetTexCoords(0));
sceneMesh->SetGeometry(workingGeometry);
objExporter->SetExportFilePath(output_unweighted_filename.c_str());
objExporter->SetScene(scene);
objExporter->RunExport();
// Chart size based on corresponding geometry area in 3D-space, i.e. pixel density per area will be consistent across the mesh
//
workingGeometry = originalGeometry->NewCopy(true);
chartAggregator->SetChartAggregatorMode(SG_CHARTAGGREGATORMODE_SURFACEAREA);
chartAggregator->Parameterize(workingGeometry, workingGeometry->GetTexCoords(0));
sceneMesh->SetGeometry(workingGeometry);
objExporter = sg->CreateWavefrontExporter();
objExporter->SetExportFilePath(output_areaweighted_filename.c_str());
objExporter->SetScene(scene);
objExporter->RunExport();
// Chart size based on the original texture sizes. Here we want the output chart proportions to be determined by the original textures proportions
//
workingGeometry = originalGeometry->NewCopy(true);
chartAggregator->SetChartAggregatorMode(SG_CHARTAGGREGATORMODE_TEXTURESIZEPROPORTIONS);
// We can decide which texture channel decides which proportions to keep, diffuse if default
//chartAggregator->SetOriginalChartProportionsChannel(SG_MATERIAL_CHANNEL_DIFFUSE);
chartAggregator->Parameterize(workingGeometry, workingGeometry->GetTexCoords(0));
sceneMesh->SetGeometry(workingGeometry);
objExporter = sg->CreateWavefrontExporter();
objExporter->SetExportFilePath(output_textureweighted_filename.c_str());
objExporter->SetScene(scene);
objExporter->RunExport();
// Chart size based on the original texture sizes, while perfectly maintaining the pixel density of the original textures. Will override manually set output texture sizes.
//
workingGeometry = originalGeometry->NewCopy(true);
chartAggregator->SetChartAggregatorMode(SG_CHARTAGGREGATORMODE_ORIGINALPIXELDENSITY);
// We can decide which texture channel decides which proportions to keep, diffuse if default
//chartAggregator->SetOriginalChartProportionsChannel(SG_MATERIAL_CHANNEL_DIFFUSE);
chartAggregator->Parameterize(workingGeometry, workingGeometry->GetTexCoords(0));
sceneMesh->SetGeometry(workingGeometry);
objExporter = sg->CreateWavefrontExporter();
objExporter->SetExportFilePath(output_preservedpixeldensity_filename.c_str());
objExporter->SetScene(scene);
objExporter->RunExport();
}