234 lines
8.6 KiB
C++
234 lines
8.6 KiB
C++
#include "MaterialLibraryMultiRootOctreeBuilder.h"
|
|
#include "../Util/Stopwatch.h"
|
|
#include "OctreeLoader.h"
|
|
#include "../CollectionHelper.h"
|
|
#include "../../inc/tbb/parallel_for.h"
|
|
#include "../../inc/tbb/concurrent_queue.h"
|
|
|
|
MaterialLibraryMultiRootOctreeBuilder::MaterialLibraryMultiRootOctreeBuilder(BaseQuantizer<Color, ColorCompare>* quantizer) :
|
|
BaseMaterialOctreeBuilder(),
|
|
mTree(NULL),
|
|
mIntermediateTree(NULL),
|
|
mQuantizeColors(quantizer != NULL),
|
|
mQuantizer(quantizer),
|
|
mSceneColors(std::vector<Color>()),
|
|
mColorReplacers(std::unordered_map<Color, Color>())
|
|
{
|
|
// TODO: when building in steps, use preprocessing to find the materials in the upper levels
|
|
}
|
|
MaterialLibraryMultiRootOctreeBuilder::~MaterialLibraryMultiRootOctreeBuilder() {}
|
|
|
|
bool MaterialLibraryMultiRootOctreeBuilder::IsLimitedColors() const { return mQuantizeColors || !IsSinglePass(); }
|
|
|
|
bool MaterialLibraryMultiRootOctreeBuilder::UsePreprocessing() const { return IsLimitedColors(); }
|
|
|
|
std::string MaterialLibraryMultiRootOctreeBuilder::GetTreeType() { return "blc" + (mQuantizer == NULL ? "" : mQuantizer->GetQuantizerDescriptor()); }
|
|
|
|
void MaterialLibraryMultiRootOctreeBuilder::InitTree()
|
|
{
|
|
mTree = new MaterialLibraryMultiRoot<Color, ColorCompare>(GetTreeDepth());
|
|
}
|
|
|
|
void MaterialLibraryMultiRootOctreeBuilder::FinalizeTree()
|
|
{
|
|
// Store the amount of nodes the octree had for the first few levels
|
|
auto nodesPerLevel = mTree->GetOctreeNodesPerLevel();
|
|
}
|
|
|
|
void MaterialLibraryMultiRootOctreeBuilder::TerminateTree()
|
|
{
|
|
OctreeLoader::WriteCache(mTree, GetTreeType(), GetOutputFile(), verbose);
|
|
delete mTree;
|
|
mSceneColors.clear();
|
|
mColorReplacers.clear();
|
|
}
|
|
|
|
void MaterialLibraryMultiRootOctreeBuilder::InitCurPassTree(glm::uvec3 coord)
|
|
{
|
|
mIntermediateTree = new MaterialTree<Color, ColorCompare>(GetSinglePassTreeDepth());
|
|
mIntermediateTree->UseLeafMap(true);
|
|
|
|
//for (auto color : mSceneColors)
|
|
// mIntermediateTree->AddMaterial(Color(color));
|
|
//mIntermediateTree->FinalizeMaterials();
|
|
}
|
|
|
|
void MaterialLibraryMultiRootOctreeBuilder::FinalizeCurPassTree(glm::uvec3 coord)
|
|
{
|
|
Stopwatch watch;
|
|
|
|
if (mIntermediateTree->GetNodeCount() > 1) // Only append the tree (and compress) if it is not empty
|
|
{
|
|
// Convert the intermediate tree to a DAG before building the material library multiroot tree:
|
|
if (verbose) printf("Converting intermediate tree to a DAG...\n");
|
|
watch.Reset();
|
|
mIntermediateTree->ToDAG();
|
|
if (verbose) printf("Converting took %d ms.\n", (int)(watch.GetTime() * 1000));
|
|
|
|
// Propagate the materials in the intermediate tree
|
|
if (verbose) printf("Propagating materials in the intermediate tree...");
|
|
watch.Reset();
|
|
mIntermediateTree->PropagateMaterials(Color::WeightedAverage);
|
|
if (verbose) printf("Propagated in %d ms.\n", (int)(watch.GetTime() * 1000));
|
|
|
|
// Quantize the colors in the material tree
|
|
if (IsLimitedColors())
|
|
{
|
|
if (verbose) printf("Replacing materials by their quantized counterparts.");
|
|
std::vector<Color> curPassMaterials = mIntermediateTree->GetUniqueMaterials();
|
|
CollectionHelper::Unique(curPassMaterials, ColorCompare());
|
|
std::vector<Color> curPassQuantizedMaterials(curPassMaterials.size());
|
|
|
|
if (verbose) printf(".");
|
|
// For each material in the curPassMaterials, find the closest material
|
|
tbb::concurrent_queue<size_t> newReplacers;
|
|
tbb::parallel_for(size_t(0), curPassMaterials.size(), [&](const size_t& i)
|
|
{
|
|
auto cachedReplacer = mColorReplacers.find(curPassMaterials[i]);
|
|
if (cachedReplacer != mColorReplacers.end())
|
|
curPassQuantizedMaterials[i] = cachedReplacer->second;
|
|
else
|
|
{
|
|
curPassQuantizedMaterials[i] = NearestFinder<Color>()(curPassMaterials[i], mSceneColors);
|
|
newReplacers.push(i);
|
|
}
|
|
});
|
|
|
|
// Add the newly found replacers to the cache
|
|
for (auto i = newReplacers.unsafe_begin(); i != newReplacers.unsafe_end(); ++i)
|
|
mColorReplacers.insert(std::pair<Color, Color>(curPassMaterials[*i], curPassQuantizedMaterials[*i]));
|
|
|
|
// Update the current scene color map
|
|
std::unordered_map<Color, Color> quantizedColors;
|
|
for (size_t i = 0; i < curPassMaterials.size(); i++)
|
|
quantizedColors.insert(std::pair<Color, Color>(curPassMaterials[i], curPassQuantizedMaterials[i]));
|
|
|
|
if (verbose) printf(".");
|
|
mIntermediateTree->ReplaceMaterials(quantizedColors);
|
|
if (verbose) printf("Replaced in %d ms.\n", (int)(watch.GetTime() * 1000));
|
|
if (verbose) printf("%llu new materials quantized, cache now contains %llu materials.\n", (unsigned64)newReplacers.unsafe_size(), (unsigned64)mColorReplacers.size());
|
|
}
|
|
|
|
// Build the actual MaterialLibaryMultiRootTree based on the intermediate tree
|
|
if (verbose) printf("Building multiroot tree based on intermediate tree...");
|
|
watch.Reset();
|
|
auto curPassTree = new MaterialLibraryMultiRoot<Color, ColorCompare>(mIntermediateTree->GetMaxLevel());
|
|
if (IsLimitedColors()) curPassTree->CreateMaterialLibrary(mSceneColors);
|
|
curPassTree->BaseOn(mIntermediateTree, false);
|
|
delete mIntermediateTree;
|
|
|
|
curPassTree->ShaveEquals();
|
|
curPassTree->ToDAG();
|
|
curPassTree->FillEmptySpace(false);
|
|
if (verbose) printf("Multiroot tree build in %d ms.\n", (int)(watch.GetTime() * 1000));
|
|
|
|
// Convert the current pass tree to a DAG
|
|
if (verbose) printf("Converting the current pass multiroot tree to a DAG...\n");
|
|
watch.Reset();
|
|
curPassTree->ToDAG();
|
|
if (verbose) printf("Converted in %d ms.\n", (int)(watch.GetTime() * 1000));
|
|
|
|
auto octreeNodesPerLevel = curPassTree->GetOctreeNodesPerLevel();
|
|
|
|
if (IsSinglePass()) // Means we just constructed the root, so no need to append
|
|
{
|
|
delete mTree;
|
|
mTree = curPassTree;
|
|
}
|
|
else
|
|
{
|
|
if (verbose) printf("Appending subtree... ");
|
|
watch.Reset();
|
|
mTree->Append(coord, GetAppendedTreeLevel(), curPassTree);
|
|
delete curPassTree;
|
|
if (verbose) printf("Appending took %d ms.\n", (int)(watch.GetTime() * 1000));
|
|
|
|
if (verbose) printf("Converting current tree to DAG...\n");
|
|
watch.Reset();
|
|
mTree->ToDAG(GetAppendedTreeLevel());
|
|
if (verbose) printf("Converted in %d ms.\n", (int)(watch.GetTime() * 1000));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
delete mIntermediateTree;
|
|
}
|
|
}
|
|
|
|
void MaterialLibraryMultiRootOctreeBuilder::AddMissingNode(const glm::uvec3& coordinate, const Color& color)
|
|
{
|
|
if (!mIntermediateTree->HasLeaf(coordinate))
|
|
AddNode(coordinate, color);
|
|
}
|
|
void MaterialLibraryMultiRootOctreeBuilder::AddNode(const glm::uvec3& coordinate, const Color& color)
|
|
{
|
|
if (IsLimitedColors())
|
|
{
|
|
auto replacer = mColorReplacers.find(color);
|
|
if (replacer == mColorReplacers.end())
|
|
{
|
|
Color replacement = NearestFinder<Color>()(color, mSceneColors);
|
|
mColorReplacers.insert(std::pair<Color, Color>(color, replacement));
|
|
replacer = mColorReplacers.find(color);
|
|
}
|
|
assert(replacer != mColorReplacers.end());
|
|
mIntermediateTree->AddLeafNode(coordinate, replacer->second);
|
|
}
|
|
else
|
|
{
|
|
mIntermediateTree->AddLeafNode(coordinate, Color(color));
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------------
|
|
// ---------------------------------PREPROCESSING------------------------------------
|
|
//-----------------------------------------------------------------------------------
|
|
void MaterialLibraryMultiRootOctreeBuilder::PreProcessNode(const glm::uvec3& coordinate, const Color& color)
|
|
{
|
|
mSceneColors.push_back(color);
|
|
}
|
|
|
|
void MaterialLibraryMultiRootOctreeBuilder::FinalizePreprocessing()
|
|
{
|
|
CalculateUniqueSceneColors();
|
|
if (mQuantizer != NULL)
|
|
{
|
|
if (verbose) printf("Quantizing %llu materials...", (unsigned64)mSceneColors.size());
|
|
Stopwatch watch; watch.Reset();
|
|
auto quantizedMaterials = mQuantizer->QuantizeMaterials(mSceneColors);
|
|
mSceneColors.clear();
|
|
for (auto quantizedMaterial : *quantizedMaterials)
|
|
{
|
|
mColorReplacers.insert(std::pair<Color, Color>(quantizedMaterial.first, quantizedMaterial.second));
|
|
mSceneColors.push_back(quantizedMaterial.second);
|
|
}
|
|
CalculateUniqueSceneColors();
|
|
if (verbose) printf("Quantized in %u ms, %llu materials left\n", (unsigned)(watch.GetTime() * 1000), (unsigned64)mSceneColors.size());
|
|
}
|
|
else
|
|
{
|
|
for (Color color : mSceneColors)
|
|
mColorReplacers.insert(std::pair<Color, Color>(color, color));
|
|
}
|
|
}
|
|
|
|
void MaterialLibraryMultiRootOctreeBuilder::CalculateUniqueSceneColors()
|
|
{
|
|
// Remove duplicates from scene colors
|
|
CollectionHelper::Unique(mSceneColors, ColorCompare());
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------------
|
|
// -----------------------------------STATISTICS-------------------------------------
|
|
//-----------------------------------------------------------------------------------
|
|
std::vector<size_t> MaterialLibraryMultiRootOctreeBuilder::GetOctreeNodesPerLevel()
|
|
{
|
|
return mTree->GetOctreeNodesPerLevel();
|
|
}
|
|
|
|
std::vector<size_t> MaterialLibraryMultiRootOctreeBuilder::GetNodesPerLevel()
|
|
{
|
|
return mTree->GetNodesPerLevel();
|
|
}
|
|
|