Initial commit: Final state of the master project
This commit is contained in:
18
Research/scene/Material/MaterialQuantizer/BaseQuantizer.h
Normal file
18
Research/scene/Material/MaterialQuantizer/BaseQuantizer.h
Normal file
@@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
template<typename T, typename Comparer>
|
||||
class BaseQuantizer
|
||||
{
|
||||
public:
|
||||
virtual std::map<T, T, Comparer>* QuantizeMaterials(std::vector<T> materials) const = 0;
|
||||
virtual std::string GetQuantizerDescriptor() const = 0;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class QuickQuantizer
|
||||
{
|
||||
public:
|
||||
virtual T Quantize(const T& material) const = 0;
|
||||
};
|
||||
@@ -0,0 +1,48 @@
|
||||
#pragma once
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include "BaseQuantizer.h"
|
||||
#include "ColorQuantizer/BaseColorQuantizer.h"
|
||||
#include "../ColorAndNormal.h"
|
||||
#include "../ColorAndOpacity.h"
|
||||
#include "../ColorAndNormalAndValue.h"
|
||||
#include "../../../core/CollectionHelper.h"
|
||||
|
||||
// Basically quantizes the colors using the given color quantizer and leaves the values as-is (assuming they are quantized enough already)
|
||||
// Deleting this object also deletes the associated color quantizer
|
||||
template<typename T, typename TCompare>
|
||||
class ColorAndValueQuantizer : public BaseQuantizer<ColorAndValue<T>, ColorAndValueCompare<T, TCompare>>
|
||||
{
|
||||
private:
|
||||
BaseColorQuantizer* mColorQuantizer;
|
||||
public:
|
||||
ColorAndValueQuantizer(BaseColorQuantizer* colorQuantizer)
|
||||
: mColorQuantizer(colorQuantizer)
|
||||
{}
|
||||
|
||||
~ColorAndValueQuantizer()
|
||||
{
|
||||
delete mColorQuantizer;
|
||||
}
|
||||
|
||||
virtual std::map<ColorAndValue<T>, ColorAndValue<T>, ColorAndValueCompare<T, TCompare>>* QuantizeMaterials(std::vector<ColorAndValue<T>> materials) const
|
||||
{
|
||||
std::vector<Color> colors(materials.size());
|
||||
for (size_t i = 0; i < materials.size(); i++) colors[i] = materials[i].GetFirst();
|
||||
CollectionHelper::Unique(colors, ColorCompare());
|
||||
auto quantizedColors = mColorQuantizer->QuantizeMaterials(colors);
|
||||
std::map<ColorAndValue<T>, ColorAndValue<T>, ColorAndValueCompare<T, TCompare>>* res = new std::map<ColorAndValue<T>, ColorAndValue<T>, ColorAndValueCompare<T, TCompare>>();
|
||||
for (auto mat : materials)
|
||||
{
|
||||
ColorAndValue<T> replacer(quantizedColors->at(mat.GetFirst()), mat.GetSecond());
|
||||
res->insert(std::make_pair(mat, replacer));
|
||||
}
|
||||
delete quantizedColors;
|
||||
return res;
|
||||
}
|
||||
virtual std::string GetQuantizerDescriptor() const { return mColorQuantizer->GetQuantizerDescriptor(); }
|
||||
};
|
||||
|
||||
typedef ColorAndValueQuantizer<ColorAndNormal, ColorAndNormalCompare> ColorAndNormalQuantizer;
|
||||
typedef ColorAndValueQuantizer<ColorAndOpacity, ColorAndOpacityCompare> ColorAndOpacityQuantizer;
|
||||
typedef ColorAndValueQuantizer<ColorAndNormalAndValue, ColorAndNormalAndValueCompare> ColorAndNormalAndValueQuantizer;
|
||||
@@ -0,0 +1,53 @@
|
||||
#include "BaseColorQuantizer.h"
|
||||
#include "../../../../inc/tbb/parallel_for.h"
|
||||
|
||||
std::map<Color, Color, ColorCompare>* BaseColorQuantizer::QuantizeMaterials(std::vector<Color> materials) const
|
||||
{
|
||||
// Convert the "Colors" to u8vec3
|
||||
std::vector<glm::u8vec3> colors(materials.size());
|
||||
tbb::parallel_for(size_t(0), materials.size(), [&](size_t i)
|
||||
{
|
||||
colors[i] = materials[i].GetColor();
|
||||
});
|
||||
|
||||
// Quantize the colors
|
||||
auto quantizedColors = QuantizeColors(colors);
|
||||
//PrintQuantizationStatistics(quantizedColors);
|
||||
|
||||
// Find out what the quantized materials are
|
||||
std::map<Color, Color, ColorCompare>* quantizedMaterials = new std::map<Color, Color, ColorCompare>();
|
||||
for (auto quantizedColor : *quantizedColors)
|
||||
{
|
||||
quantizedMaterials->insert(std::pair<Color, Color>(Color(quantizedColor.first), Color(quantizedColor.second)));
|
||||
glm::vec3 error = glm::abs(glm::vec3(quantizedColor.first) - glm::vec3(quantizedColor.second));
|
||||
}
|
||||
delete quantizedColors;
|
||||
return quantizedMaterials;
|
||||
}
|
||||
|
||||
void BaseColorQuantizer::PrintQuantizationStatistics(std::map<glm::u8vec3, glm::u8vec3, u8vec3comparer>* quantizedColors) const
|
||||
{
|
||||
glm::vec3 sumError(0);
|
||||
unsigned maxError = 0;
|
||||
glm::uvec3 maxErrorValue(0);
|
||||
float sumDeltaE = 0;
|
||||
float maxDeltaE = 0;
|
||||
for (auto quantizedColor : *quantizedColors)
|
||||
{
|
||||
glm::vec3 error = glm::abs(glm::vec3(quantizedColor.first) - glm::vec3(quantizedColor.second));
|
||||
sumError += error;
|
||||
unsigned errorU = error.r + error.g + error.b;
|
||||
if (errorU > maxError)
|
||||
{
|
||||
maxError = errorU;
|
||||
maxErrorValue = error;
|
||||
}
|
||||
float deltaE = ColorHelper::GetDeltaEFromRGB(quantizedColor.first, quantizedColor.second);
|
||||
if (deltaE == deltaE) // Only sum if it is not NaN...
|
||||
sumDeltaE += deltaE;
|
||||
if (deltaE > maxDeltaE) maxDeltaE = deltaE;
|
||||
}
|
||||
glm::vec3 meanError = sumError / float(quantizedColors->size());
|
||||
float meanDeltaE = sumDeltaE / float(quantizedColors->size());
|
||||
printf("Mean errors: (%f, %f, %f), Max errors: (%u, %u, %u), Mean delta-E: %f, Max delta-E: %f\n", meanError.x, meanError.y, meanError.z, maxErrorValue.x, maxErrorValue.y, maxErrorValue.z, meanDeltaE, maxDeltaE);
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
#include "../BaseQuantizer.h"
|
||||
#include "../../Color.h"
|
||||
|
||||
class BaseColorQuantizer : public BaseQuantizer<Color, ColorCompare>
|
||||
{
|
||||
public:
|
||||
virtual ~BaseColorQuantizer() {}
|
||||
|
||||
void PrintQuantizationStatistics(std::map<glm::u8vec3, glm::u8vec3, u8vec3comparer>* quantizedColors) const;
|
||||
std::map<Color, Color, ColorCompare>* QuantizeMaterials(std::vector<Color> materials) const override;
|
||||
virtual std::map<glm::u8vec3, glm::u8vec3, u8vec3comparer>* QuantizeColors(std::vector<glm::u8vec3> colors) const = 0;
|
||||
};
|
||||
@@ -0,0 +1,28 @@
|
||||
#include "ColorBitCutter.h"
|
||||
|
||||
ColorBitCutter::ColorBitCutter(unsigned8 bitCount)
|
||||
{
|
||||
assert(bitCount <= 8);
|
||||
mBitCount = bitCount;
|
||||
}
|
||||
ColorBitCutter::~ColorBitCutter() {}
|
||||
|
||||
std::map<glm::u8vec3, glm::u8vec3, u8vec3comparer>* ColorBitCutter::QuantizeColors(std::vector<glm::u8vec3> colors) const
|
||||
{
|
||||
std::map<glm::u8vec3, glm::u8vec3, u8vec3comparer>* res = new std::map<glm::u8vec3, glm::u8vec3, u8vec3comparer>();
|
||||
unsigned8 mask = BitHelper::GetHSMask<unsigned8>(0, mBitCount);
|
||||
for (glm::u8vec3 color : colors)
|
||||
{
|
||||
glm::u8vec3 replacementColor = glm::u8vec3(
|
||||
color.x & mask,
|
||||
color.y & mask,
|
||||
color.z & mask);
|
||||
res->insert(std::pair<glm::u8vec3, glm::u8vec3>(color, replacementColor));
|
||||
}
|
||||
return res;
|
||||
}
|
||||
std::string ColorBitCutter::GetQuantizerDescriptor() const
|
||||
{
|
||||
return "b" + std::to_string(mBitCount);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
#include <map>
|
||||
#include "../../../../inc/glm/common.hpp"
|
||||
#include "../../../../core/Comparers.h"
|
||||
#include "BaseColorQuantizer.h"
|
||||
|
||||
class ColorBitCutter : public BaseColorQuantizer
|
||||
{
|
||||
public:
|
||||
ColorBitCutter(unsigned8 bitCount);
|
||||
~ColorBitCutter() override;
|
||||
|
||||
std::map<glm::u8vec3, glm::u8vec3, u8vec3comparer>* QuantizeColors(std::vector<glm::u8vec3> colors) const override;
|
||||
std::string GetQuantizerDescriptor() const override;
|
||||
|
||||
private:
|
||||
unsigned8 mBitCount;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
#include "MaxErrorClusterer.h"
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <forward_list>
|
||||
|
||||
#include "../../../../inc/glm/geometric.hpp"
|
||||
|
||||
// Quantize the colors in CIELAB-space clusters that have a maximum size maxDistance.
|
||||
MaxErrorClusterer::MaxErrorClusterer(float maxDistance)
|
||||
{
|
||||
mMaxDistance = maxDistance;
|
||||
}
|
||||
MaxErrorClusterer::~MaxErrorClusterer() { }
|
||||
|
||||
std::map<glm::u8vec3, glm::u8vec3, u8vec3comparer>* MaxErrorClusterer::QuantizeColors(std::vector<glm::u8vec3> colors) const
|
||||
{
|
||||
// Transform all colors to CIELAB space:
|
||||
ListNode<Color>* firstUnclusteredColor = new ListNode<Color>();
|
||||
ListNode<Color>* cur = firstUnclusteredColor;
|
||||
for (auto rgb : colors)
|
||||
{
|
||||
Color color(rgb);
|
||||
cur->color = color;
|
||||
cur->next = new ListNode<Color>();
|
||||
cur = cur->next;
|
||||
}
|
||||
|
||||
auto res = new std::map<glm::u8vec3, glm::u8vec3, u8vec3comparer>();
|
||||
while (firstUnclusteredColor != NULL)
|
||||
{
|
||||
Color curColor = firstUnclusteredColor->color;
|
||||
// Pop the head of the "list"
|
||||
{
|
||||
auto nextUnclusteredColor = firstUnclusteredColor->next;
|
||||
delete firstUnclusteredColor;
|
||||
firstUnclusteredColor = nextUnclusteredColor;
|
||||
}
|
||||
// Create a new cluster for this unclustered color
|
||||
auto cluster = std::vector<Color>();
|
||||
cluster.push_back(curColor);
|
||||
|
||||
// Loop through the unclustered colors
|
||||
if (firstUnclusteredColor != NULL)
|
||||
{
|
||||
cur = firstUnclusteredColor;
|
||||
ListNode<Color>* last = NULL;
|
||||
ListNode<Color>* next = cur->next;
|
||||
while (cur != NULL)
|
||||
{
|
||||
next = cur->next;
|
||||
if (ColorHelper::GetDeltaEFromLAB(cur->color.lab, curColor.lab) <= mMaxDistance)
|
||||
{
|
||||
// If we are close enough to the last color, add the current color to the cluster
|
||||
cluster.push_back(cur->color);
|
||||
|
||||
// Delete the current node from the list of unclustered nodes
|
||||
delete cur;
|
||||
|
||||
// If this isn't the first node in the list, make sure the last node points to this node
|
||||
if (last != NULL)
|
||||
{
|
||||
last->next = next;
|
||||
cur = last;
|
||||
}
|
||||
else
|
||||
{ // If this is the first node, we just deleted it, so replace the current first node by the next node
|
||||
firstUnclusteredColor = next;
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
// If this node wasn't add to the cluster, the last node should be updated before advancing
|
||||
last = cur;
|
||||
}
|
||||
// Advance one position
|
||||
cur = next;
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate the center of the current cluster
|
||||
glm::vec3 clusterSum(0);
|
||||
glm::u8vec3 clusterReplacementColor = curColor.rgb;
|
||||
for (auto color : cluster)
|
||||
res->insert(std::pair<glm::u8vec3, glm::u8vec3>(color.rgb, clusterReplacementColor));
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
std::string MaxErrorClusterer::GetQuantizerDescriptor() const
|
||||
{
|
||||
char str[7];
|
||||
sprintf(str, "%.2f", mMaxDistance);
|
||||
auto formattedMaxDistance = std::string(str);
|
||||
return "de" + formattedMaxDistance;
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
#pragma once
|
||||
#include "BaseColorQuantizer.h"
|
||||
#include "../../../../core/ColorHelper.h"
|
||||
|
||||
class MaxErrorClusterer :
|
||||
public BaseColorQuantizer
|
||||
{
|
||||
public:
|
||||
// Quantize the colors in CIELAB-space clusters that have a maximum size maxDistance.
|
||||
// This is done using a greedy clustering algorithm that adds all colors to the cluster of a color if they're less than half the distance away.
|
||||
MaxErrorClusterer(float maxDistance);
|
||||
~MaxErrorClusterer() override;
|
||||
|
||||
std::map<glm::u8vec3, glm::u8vec3, u8vec3comparer>* QuantizeColors(std::vector<glm::u8vec3> colors) const override;
|
||||
std::string GetQuantizerDescriptor() const override;
|
||||
protected:
|
||||
float mMaxDistance;
|
||||
private:
|
||||
template<typename T>
|
||||
struct ListNode
|
||||
{
|
||||
public:
|
||||
T color;
|
||||
ListNode<T>* next = NULL;
|
||||
|
||||
ListNode(T value) { color = value; }
|
||||
ListNode() { }
|
||||
};
|
||||
struct Color
|
||||
{
|
||||
glm::u8vec3 rgb;
|
||||
glm::vec3 lab;
|
||||
|
||||
Color(glm::u8vec3 rgb)
|
||||
{
|
||||
this->rgb = rgb;
|
||||
lab = ColorHelper::RGBtoLAB(rgb);
|
||||
}
|
||||
|
||||
Color() : Color(glm::u8vec3(0)) {}
|
||||
};
|
||||
};
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
#include "XiangCIELABClusterer.h"
|
||||
#include "../../../../core/ColorHelper.h"
|
||||
#include <string>
|
||||
|
||||
XiangCIELABClusterer::XiangCIELABClusterer(unsigned quantizedColorCount) : XiangClusterer(quantizedColorCount) {}
|
||||
XiangCIELABClusterer::~XiangCIELABClusterer() {}
|
||||
|
||||
glm::vec3 XiangCIELABClusterer::ScaleColor(glm::u8vec3 color) const
|
||||
{
|
||||
return ColorHelper::RGBtoLAB(color);
|
||||
}
|
||||
glm::u8vec3 XiangCIELABClusterer::ScaleBackColor(glm::vec3 color) const
|
||||
{
|
||||
return ColorHelper::LABtoRGB(color);
|
||||
}
|
||||
|
||||
std::string XiangCIELABClusterer::GetQuantizerDescriptor() const
|
||||
{
|
||||
return "lab" + std::to_string(mQuantizedColorCount);
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
#include "XiangClusterer.h"
|
||||
|
||||
class XiangCIELABClusterer :
|
||||
public XiangClusterer
|
||||
{
|
||||
public:
|
||||
// Quantize the colors to the given amount of colors, using the default RGB scaling, 0.5:1.0:0.25.
|
||||
XiangCIELABClusterer(unsigned quantizedColorCount);
|
||||
virtual ~XiangCIELABClusterer() override;
|
||||
|
||||
std::string GetQuantizerDescriptor() const override;
|
||||
protected:
|
||||
glm::vec3 ScaleColor(glm::u8vec3 color) const override;
|
||||
glm::u8vec3 ScaleBackColor(glm::vec3 color) const override;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
#include "XiangClusterer.h"
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#include "../../../../inc/glm/geometric.hpp"
|
||||
|
||||
XiangClusterer::XiangClusterer(unsigned quantizedColorCount, glm::vec3 colorScale)
|
||||
{
|
||||
mQuantizedColorCount = quantizedColorCount;
|
||||
mColorScale = colorScale;
|
||||
mInvColorScale = 1.0f / mColorScale;
|
||||
}
|
||||
|
||||
XiangClusterer::XiangClusterer(unsigned quantizedColorCount) : XiangClusterer(quantizedColorCount, glm::vec3(0.5, 1.0, 0.25)) {}
|
||||
|
||||
XiangClusterer::~XiangClusterer()
|
||||
{
|
||||
}
|
||||
|
||||
std::map<glm::u8vec3, glm::u8vec3, u8vec3comparer>* XiangClusterer::QuantizeColors(std::vector<glm::u8vec3> colors) const
|
||||
{
|
||||
// Set the initial cluster head to the first color in the set
|
||||
std::vector<glm::vec3> h(mQuantizedColorCount);
|
||||
h[0] = *colors.begin();
|
||||
|
||||
// Initialize all colors to be in the same cluster (cluster 0)
|
||||
std::vector<ClusterColor*> B(colors.size());
|
||||
int i = 0;
|
||||
for (auto color : colors)
|
||||
{
|
||||
ClusterColor* cur = new ClusterColor();
|
||||
cur->originalColor = color;
|
||||
cur->color = ScaleColor(color);
|
||||
cur->centerDistance = glm::distance(glm::vec3(color), h[0]);
|
||||
cur->clusterID = 0;
|
||||
B[i++] = cur;
|
||||
}
|
||||
|
||||
ClusterColor* max = B[0];
|
||||
|
||||
// Start the algorithm: in each iteration create a new cluster
|
||||
for (unsigned x = 1; x < mQuantizedColorCount; x++)
|
||||
{
|
||||
// Find the point with the maximum distance to the cluster center
|
||||
for (auto color : B)
|
||||
if (color->centerDistance > max->centerDistance)
|
||||
max = color;
|
||||
// Define this point as the center of a new cluster
|
||||
max->clusterID = x;
|
||||
h[x] = max->color;
|
||||
|
||||
// Move all colors that are closer to this new cluster than to their current cluster center over to the new cluster.
|
||||
for (auto color : B)
|
||||
{
|
||||
float newDistance = glm::distance(color->color, h[x]);
|
||||
if (newDistance < color->centerDistance)
|
||||
{
|
||||
color->clusterID = x;
|
||||
color->centerDistance = newDistance;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Find all cluster centers:
|
||||
std::vector<glm::vec3> clusterSums(mQuantizedColorCount);
|
||||
std::vector<float> invClusterCounts(mQuantizedColorCount);
|
||||
for (auto color : B)
|
||||
{
|
||||
clusterSums[color->clusterID] += color->color;
|
||||
invClusterCounts[color->clusterID]++;
|
||||
}
|
||||
// Inverse the cluster counts:
|
||||
for (size_t i = 0; i < invClusterCounts.size(); i++) invClusterCounts[i] = 1.0f / invClusterCounts[i];
|
||||
|
||||
// Calculate the color replacers
|
||||
std::vector<glm::u8vec3> clusterReplacers(mQuantizedColorCount);
|
||||
for (unsigned i = 0; i < mQuantizedColorCount; i++)
|
||||
clusterReplacers[i] = ScaleBackColor(clusterSums[i] * invClusterCounts[i]);
|
||||
|
||||
// Now that we have the clusters, build the replacement map
|
||||
auto replacements = new std::map<glm::u8vec3, glm::u8vec3, u8vec3comparer>();
|
||||
for (auto color : B)
|
||||
replacements->insert(std::pair<glm::u8vec3, glm::u8vec3>(color->originalColor, clusterReplacers[color->clusterID]));
|
||||
|
||||
for (auto color : B)
|
||||
delete color;
|
||||
|
||||
return replacements;
|
||||
}
|
||||
|
||||
glm::vec3 XiangClusterer::ScaleColor(glm::u8vec3 color) const
|
||||
{
|
||||
return glm::vec3(color) * mColorScale;
|
||||
}
|
||||
|
||||
glm::u8vec3 XiangClusterer::ScaleBackColor(glm::vec3 color) const
|
||||
{
|
||||
return glm::u8vec3(glm::round(color * mInvColorScale));
|
||||
}
|
||||
|
||||
std::string XiangClusterer::GetQuantizerDescriptor() const
|
||||
{
|
||||
return std::to_string(mQuantizedColorCount);
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
#pragma once
|
||||
#include "BaseColorQuantizer.h"
|
||||
|
||||
class XiangClusterer :
|
||||
public BaseColorQuantizer
|
||||
{
|
||||
public:
|
||||
XiangClusterer(unsigned quantizedColorCount, glm::vec3 colorScale);
|
||||
// Quantize the colors to the given amount of colors, using the default RGB scaling, 0.5:1.0:0.25.
|
||||
XiangClusterer(unsigned quantizedColorCount);
|
||||
~XiangClusterer() override;
|
||||
|
||||
std::map<glm::u8vec3, glm::u8vec3, u8vec3comparer>* QuantizeColors(std::vector<glm::u8vec3> colors) const override;
|
||||
std::string GetQuantizerDescriptor() const override;
|
||||
protected:
|
||||
virtual glm::vec3 ScaleColor(glm::u8vec3 color) const;
|
||||
virtual glm::u8vec3 ScaleBackColor(glm::vec3 color) const;
|
||||
unsigned mQuantizedColorCount;
|
||||
private:
|
||||
glm::vec3 mColorScale;
|
||||
glm::vec3 mInvColorScale;
|
||||
|
||||
struct ClusterColor
|
||||
{
|
||||
public:
|
||||
glm::u8vec3 originalColor;
|
||||
glm::vec3 color;
|
||||
float centerDistance;
|
||||
int clusterID;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
#pragma once
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include "NormalQuantizer.h"
|
||||
#include "../../../core/BitHelper.h"
|
||||
|
||||
|
||||
NormalQuantizer::NormalQuantizer(unsigned8 bits): mBits(bits)
|
||||
{
|
||||
// Bits must be an even number, as there are two channels for an ONV
|
||||
assert(bits % 2 == 0);
|
||||
|
||||
// Precalculate the channel mask
|
||||
unsigned32 channelStartHS = 32 - SmallNormal::BITS / 2;
|
||||
mChannelMask = BitHelper::GetHSMask<unsigned32>(channelStartHS, channelStartHS + mBits / 2);
|
||||
}
|
||||
|
||||
std::map<SmallNormal, SmallNormal, NormalCompare>* NormalQuantizer::QuantizeMaterials(std::vector<SmallNormal> normals) const
|
||||
{
|
||||
std::map<SmallNormal, SmallNormal, NormalCompare>* res = new std::map<SmallNormal, SmallNormal, NormalCompare>();
|
||||
for (const SmallNormal& normal : normals)
|
||||
{
|
||||
res->insert(std::make_pair(normal, Quantize(normal)));
|
||||
}
|
||||
if (mBits <= QUANTIZE_ALL_UP_TO)
|
||||
{
|
||||
unsigned32 maxPerChannel = 1 << (mBits / 2);
|
||||
unsigned8 shift = (SmallNormal::BITS - mBits) / 2;
|
||||
for (unsigned32 x = 0; x < maxPerChannel; x++)
|
||||
for (unsigned32 y = 0; y < maxPerChannel; y++)
|
||||
{
|
||||
SmallNormal v;
|
||||
v.SetXComponent(x << shift);
|
||||
v.SetYComponent(y << shift);
|
||||
res->insert(std::make_pair(v, v));
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
SmallNormal NormalQuantizer::Quantize(const SmallNormal& normal) const
|
||||
{
|
||||
SmallNormal quantized;
|
||||
quantized.SetXComponent(normal.GetXComponent() & mChannelMask);
|
||||
quantized.SetYComponent(normal.GetYComponent() & mChannelMask);
|
||||
return quantized;
|
||||
}
|
||||
|
||||
std::string NormalQuantizer::GetQuantizerDescriptor() const
|
||||
{
|
||||
return std::to_string(mBits);
|
||||
}
|
||||
20
Research/scene/Material/MaterialQuantizer/NormalQuantizer.h
Normal file
20
Research/scene/Material/MaterialQuantizer/NormalQuantizer.h
Normal file
@@ -0,0 +1,20 @@
|
||||
#pragma once
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include "../SmallNormal.h"
|
||||
#include "BaseQuantizer.h"
|
||||
|
||||
// Super simple quantizer: takes the original value, sets some bits to zero so that only the given number of bits remain
|
||||
class NormalQuantizer : public BaseQuantizer<SmallNormal, NormalCompare>, public QuickQuantizer<SmallNormal>
|
||||
{
|
||||
public:
|
||||
NormalQuantizer(unsigned8 bits);
|
||||
std::map<SmallNormal, SmallNormal, NormalCompare>* QuantizeMaterials(std::vector<SmallNormal> materials) const override;
|
||||
std::string GetQuantizerDescriptor() const override;
|
||||
SmallNormal Quantize(const SmallNormal& normal) const override;
|
||||
private:
|
||||
// if the number of bits is smaller than or equal to this number, all possible quantization values will be added.
|
||||
static const unsigned8 QUANTIZE_ALL_UP_TO = 14;
|
||||
unsigned8 mBits;
|
||||
unsigned32 mChannelMask;
|
||||
};
|
||||
Reference in New Issue
Block a user