可以生成纹理,不过还是不清晰
This commit is contained in:
1 parent
93e7d60416
commit
46d5d65b3f
1 file changed
+3
-603
+3
-603
@@ -645,9 +645,6 @@ public:
|
|||||||
void LocalSeamLevelingExternalUV();
|
void LocalSeamLevelingExternalUV();
|
||||||
|
|
||||||
void GenerateTexture(bool bGlobalSeamLeveling, bool bLocalSeamLeveling, unsigned nTextureSizeMultiple, unsigned nRectPackingHeuristic, Pixel8U colEmpty, float fSharpnessWeight, int maxTextureSize, const SEACAVE::String& baseFileName, bool bOriginFaceview, Scene *pScene);
|
void GenerateTexture(bool bGlobalSeamLeveling, bool bLocalSeamLeveling, unsigned nTextureSizeMultiple, unsigned nRectPackingHeuristic, Pixel8U colEmpty, float fSharpnessWeight, int maxTextureSize, const SEACAVE::String& baseFileName, bool bOriginFaceview, Scene *pScene);
|
||||||
|
|
||||||
void GenerateTextureForUV(bool bGlobalSeamLeveling, bool bLocalSeamLeveling, unsigned nTextureSizeMultiple, unsigned nRectPackingHeuristic, Pixel8U colEmpty, float fSharpnessWeight, int maxTextureSize, const SEACAVE::String& basename, bool bOriginFaceview, Scene *pScene, Mesh::TexCoordArr& existingTexcoords, Mesh::TexIndexArr& existingTexindices);
|
|
||||||
void GenerateTexture2(bool bGlobalSeamLeveling, bool bLocalSeamLeveling, unsigned nTextureSizeMultiple, unsigned nRectPackingHeuristic, Pixel8U colEmpty, float fSharpnessWeight, int maxTextureSize, const SEACAVE::String& baseFileName);
|
|
||||||
bool TextureWithExistingUV(
|
bool TextureWithExistingUV(
|
||||||
const IIndexArr& views,
|
const IIndexArr& views,
|
||||||
int nIgnoreMaskLabel,
|
int nIgnoreMaskLabel,
|
||||||
@@ -9870,358 +9867,6 @@ void MeshTexture::GenerateTexture(bool bGlobalSeamLeveling, bool bLocalSeamLevel
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MeshTexture::GenerateTextureForUV(bool bGlobalSeamLeveling, bool bLocalSeamLeveling, unsigned nTextureSizeMultiple, unsigned nRectPackingHeuristic, Pixel8U colEmpty, float fSharpnessWeight, int maxTextureSize, const SEACAVE::String& basename, bool bOriginFaceview, Scene *pScene, Mesh::TexCoordArr& existingTexcoords, Mesh::TexIndexArr& existingTexindices)
|
|
||||||
{
|
|
||||||
int border = 2;
|
|
||||||
if (!bOriginFaceview)
|
|
||||||
border = 4;
|
|
||||||
|
|
||||||
Mesh::TexCoordArr& faceTexcoords2 = existingTexcoords;
|
|
||||||
Mesh::TexIndexArr& faceTexindices2 = existingTexindices;
|
|
||||||
|
|
||||||
faceTexcoords2.resize(faces.size()*3);
|
|
||||||
faceTexindices2.resize(faces.size());
|
|
||||||
|
|
||||||
#ifdef TEXOPT_USE_OPENMP
|
|
||||||
// LOG_OUT() << "def TEXOPT_USE_OPENMP" << std::endl;
|
|
||||||
const unsigned numPatches(texturePatches.size()-1);
|
|
||||||
|
|
||||||
// ===== 修改:只在非外部UV模式下执行投影计算 =====
|
|
||||||
|
|
||||||
{
|
|
||||||
#pragma omp parallel for schedule(dynamic)
|
|
||||||
for (int_t idx=0; idx<(int_t)numPatches; ++idx) {
|
|
||||||
TexturePatch& texturePatch = texturePatches[(uint32_t)idx];
|
|
||||||
#else
|
|
||||||
for (TexturePatch *pTexturePatch=texturePatches.Begin(), *pTexturePatchEnd=texturePatches.End()-1; pTexturePatch<pTexturePatchEnd; ++pTexturePatch) {
|
|
||||||
TexturePatch& texturePatch = *pTexturePatch;
|
|
||||||
#endif
|
|
||||||
const Image& imageData = images[texturePatch.label];
|
|
||||||
AABB2f aabb(true);
|
|
||||||
for (const FIndex idxFace: texturePatch.faces) {
|
|
||||||
const Face& face = faces[idxFace];
|
|
||||||
TexCoord* texcoords = faceTexcoords2.data()+idxFace*3;
|
|
||||||
for (int i=0; i<3; ++i) {
|
|
||||||
texcoords[i] = imageData.camera.ProjectPointP(vertices[face[i]]);
|
|
||||||
ASSERT(imageData.image.isInsideWithBorder(texcoords[i], border));
|
|
||||||
aabb.InsertFull(texcoords[i]);
|
|
||||||
|
|
||||||
if (false)
|
|
||||||
{
|
|
||||||
const Point2f& a = texcoords[0];
|
|
||||||
const Point2f& b = texcoords[1];
|
|
||||||
const Point2f& c = texcoords[2];
|
|
||||||
|
|
||||||
// 计算边向量
|
|
||||||
Point2f v0 = b - a;
|
|
||||||
Point2f v1 = c - a;
|
|
||||||
float denom = (v0.x * v0.x + v0.y * v0.y) * (v1.x * v1.x + v1.y * v1.y) -
|
|
||||||
std::pow(v0.x * v1.x + v0.y * v1.y, 2);
|
|
||||||
|
|
||||||
// 处理退化三角形情况(面积接近0)
|
|
||||||
const float epsilon = 1e-6f;
|
|
||||||
if (std::abs(denom) < epsilon)
|
|
||||||
{
|
|
||||||
// DEBUG_EXTRA("PointInTriangle - Degenerate triangle, denom=%.10f", denom);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// DEBUG_EXTRA("PointInTriangle Yes idxFace=%d", idxFace);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// compute relative texture coordinates
|
|
||||||
ASSERT(imageData.image.isInside(Point2f(aabb.ptMin)));
|
|
||||||
ASSERT(imageData.image.isInside(Point2f(aabb.ptMax)));
|
|
||||||
|
|
||||||
if (bOriginFaceview)
|
|
||||||
{
|
|
||||||
texturePatch.rect.x = FLOOR2INT(aabb.ptMin[0])-border;
|
|
||||||
texturePatch.rect.y = FLOOR2INT(aabb.ptMin[1])-border;
|
|
||||||
texturePatch.rect.width = CEIL2INT(aabb.ptMax[0]-aabb.ptMin[0])+border*2;
|
|
||||||
texturePatch.rect.height = CEIL2INT(aabb.ptMax[1]-aabb.ptMin[1])+border*2;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
texturePatch.rect.x = std::max(0, FLOOR2INT(aabb.ptMin[0])-border);
|
|
||||||
texturePatch.rect.y = std::max(0, FLOOR2INT(aabb.ptMin[1])-border);
|
|
||||||
// 限制尺寸不超过图像实际范围
|
|
||||||
const cv::Mat& img = images[texturePatch.label].image;
|
|
||||||
texturePatch.rect.width = std::min(
|
|
||||||
CEIL2INT(aabb.ptMax[0]-aabb.ptMin[0])+border*2,
|
|
||||||
img.cols - texturePatch.rect.x
|
|
||||||
);
|
|
||||||
texturePatch.rect.height = std::min(
|
|
||||||
CEIL2INT(aabb.ptMax[1]-aabb.ptMin[1])+border*2,
|
|
||||||
img.rows - texturePatch.rect.y
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
ASSERT(imageData.image.isInside(texturePatch.rect.tl()));
|
|
||||||
ASSERT(imageData.image.isInside(texturePatch.rect.br()));
|
|
||||||
const TexCoord offset(texturePatch.rect.tl());
|
|
||||||
for (const FIndex idxFace: texturePatch.faces) {
|
|
||||||
TexCoord* texcoords = faceTexcoords2.data()+idxFace*3;
|
|
||||||
for (int v=0; v<3; ++v)
|
|
||||||
{
|
|
||||||
texcoords[v] -= offset;
|
|
||||||
if (false)
|
|
||||||
{
|
|
||||||
const Point2f& a = texcoords[0];
|
|
||||||
const Point2f& b = texcoords[1];
|
|
||||||
const Point2f& c = texcoords[2];
|
|
||||||
|
|
||||||
// 计算边向量
|
|
||||||
Point2f v0 = b - a;
|
|
||||||
Point2f v1 = c - a;
|
|
||||||
float denom = (v0.x * v0.x + v0.y * v0.y) * (v1.x * v1.x + v1.y * v1.y) -
|
|
||||||
std::pow(v0.x * v1.x + v0.y * v1.y, 2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
// init last patch to point to a small uniform color patch
|
|
||||||
TexturePatch& texturePatch = texturePatches.back();
|
|
||||||
const int sizePatch(border*2+1);
|
|
||||||
texturePatch.rect = cv::Rect(0,0, sizePatch,sizePatch);
|
|
||||||
for (const FIndex idxFace: texturePatch.faces) {
|
|
||||||
TexCoord* texcoords = faceTexcoords2.data()+idxFace*3;
|
|
||||||
for (int i=0; i<3; ++i)
|
|
||||||
texcoords[i] = TexCoord(0.5f, 0.5f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
LOG_OUT() << "First loop completed" << std::endl;
|
|
||||||
|
|
||||||
/*
|
|
||||||
TD_TIMER_STARTD();
|
|
||||||
// perform seam leveling
|
|
||||||
if (texturePatches.size() > 2 && (bGlobalSeamLeveling || bLocalSeamLeveling)) {
|
|
||||||
// create seam vertices and edges
|
|
||||||
CreateSeamVertices();
|
|
||||||
|
|
||||||
// perform global seam leveling
|
|
||||||
if (bGlobalSeamLeveling) {
|
|
||||||
TD_TIMER_STARTD();
|
|
||||||
if (bUseExternalUV) {
|
|
||||||
// 外部UV数据可能需要更温和的接缝处理
|
|
||||||
GlobalSeamLevelingExternalUV();
|
|
||||||
} else {
|
|
||||||
GlobalSeamLeveling3();
|
|
||||||
}
|
|
||||||
DEBUG_EXTRA("\tglobal seam leveling completed (%s)", TD_TIMER_GET_FMT().c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
// perform local seam leveling
|
|
||||||
if (bLocalSeamLeveling) {
|
|
||||||
TD_TIMER_STARTD();
|
|
||||||
// LocalSeamLeveling();
|
|
||||||
if (bUseExternalUV) {
|
|
||||||
// 外部UV数据可能需要不同的局部接缝处理
|
|
||||||
LocalSeamLevelingExternalUV();
|
|
||||||
} else {
|
|
||||||
LocalSeamLeveling3();
|
|
||||||
}
|
|
||||||
DEBUG_EXTRA("\tlocal seam leveling completed (%s)", TD_TIMER_GET_FMT().c_str());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
DEBUG_EXTRA("seam (%s)", TD_TIMER_GET_FMT().c_str());
|
|
||||||
*/
|
|
||||||
|
|
||||||
{
|
|
||||||
// merge texture patches with overlapping rectangles
|
|
||||||
for (unsigned i=0; i<texturePatches.size()-1; ++i) {
|
|
||||||
TexturePatch& texturePatchBig = texturePatches[i];
|
|
||||||
for (unsigned j=1; j<texturePatches.size(); ++j) {
|
|
||||||
if (i == j)
|
|
||||||
continue;
|
|
||||||
TexturePatch& texturePatchSmall = texturePatches[j];
|
|
||||||
if (texturePatchBig.label != texturePatchSmall.label)
|
|
||||||
continue;
|
|
||||||
if (!RectsBinPack::IsContainedIn(texturePatchSmall.rect, texturePatchBig.rect))
|
|
||||||
continue;
|
|
||||||
// translate texture coordinates
|
|
||||||
const TexCoord offset(texturePatchSmall.rect.tl()-texturePatchBig.rect.tl());
|
|
||||||
for (const FIndex idxFace: texturePatchSmall.faces) {
|
|
||||||
TexCoord* texcoords = faceTexcoords2.data()+idxFace*3;
|
|
||||||
for (int v=0; v<3; ++v)
|
|
||||||
texcoords[v] += offset;
|
|
||||||
}
|
|
||||||
// join faces lists
|
|
||||||
texturePatchBig.faces.JoinRemove(texturePatchSmall.faces);
|
|
||||||
// remove the small patch
|
|
||||||
texturePatches.RemoveAtMove(j--);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
LOG_OUT() << "Second loop completed" << std::endl;
|
|
||||||
// create texture
|
|
||||||
{
|
|
||||||
// arrange texture patches to fit the smallest possible texture image
|
|
||||||
// const unsigned minPatchSize = 20;
|
|
||||||
RectsBinPack::RectWIdxArr unplacedRects(texturePatches.size());
|
|
||||||
FOREACH(i, texturePatches) {
|
|
||||||
if (texturePatches[i].label == NO_ID) {
|
|
||||||
}
|
|
||||||
|
|
||||||
// LOG_OUT() << "Third loop completed" << std::endl;
|
|
||||||
if (maxTextureSize > 0 && (texturePatches[i].rect.width > maxTextureSize || texturePatches[i].rect.height > maxTextureSize)) {
|
|
||||||
DEBUG("error: a patch of size %u x %u does not fit the texture", texturePatches[i].rect.width, texturePatches[i].rect.height);
|
|
||||||
ABORT("the maximum texture size chosen cannot fit a patch");
|
|
||||||
}
|
|
||||||
unplacedRects[i] = {texturePatches[i].rect, i};
|
|
||||||
}
|
|
||||||
LOG_OUT() << "unplacedRects loop completed" << std::endl;
|
|
||||||
|
|
||||||
LOG_OUT() << "pack patches: one pack per texture file loop completed" << std::endl;
|
|
||||||
// pack patches: one pack per texture file
|
|
||||||
CLISTDEF2IDX(RectsBinPack::RectWIdxArr, TexIndex) placedRects; {
|
|
||||||
// increase texture size till all patches fit
|
|
||||||
// Bruce
|
|
||||||
unsigned typeRectsBinPack(nRectPackingHeuristic/100);
|
|
||||||
unsigned typeSplit((nRectPackingHeuristic-typeRectsBinPack*100)/10);
|
|
||||||
unsigned typeHeuristic(nRectPackingHeuristic%10);
|
|
||||||
if (!bOriginFaceview && false)
|
|
||||||
{
|
|
||||||
typeRectsBinPack = 1;
|
|
||||||
typeSplit = 0;
|
|
||||||
typeHeuristic = 1;
|
|
||||||
}
|
|
||||||
int textureSize = 0;
|
|
||||||
|
|
||||||
{
|
|
||||||
while (!unplacedRects.empty()) {
|
|
||||||
TD_TIMER_STARTD();
|
|
||||||
if (textureSize == 0) {
|
|
||||||
textureSize = RectsBinPack::ComputeTextureSize(unplacedRects, nTextureSizeMultiple);
|
|
||||||
if (maxTextureSize > 0 && textureSize > maxTextureSize)
|
|
||||||
textureSize = maxTextureSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
RectsBinPack::RectWIdxArr newPlacedRects;
|
|
||||||
switch (typeRectsBinPack) {
|
|
||||||
case 0: {
|
|
||||||
MaxRectsBinPack pack(textureSize, textureSize);
|
|
||||||
newPlacedRects = pack.Insert(unplacedRects, (MaxRectsBinPack::FreeRectChoiceHeuristic)typeHeuristic);
|
|
||||||
break; }
|
|
||||||
case 1: {
|
|
||||||
SkylineBinPack pack(textureSize, textureSize, typeSplit!=0);
|
|
||||||
newPlacedRects = pack.Insert(unplacedRects, (SkylineBinPack::LevelChoiceHeuristic)typeHeuristic);
|
|
||||||
break; }
|
|
||||||
case 2: {
|
|
||||||
GuillotineBinPack pack(textureSize, textureSize);
|
|
||||||
newPlacedRects = pack.Insert(unplacedRects, false, (GuillotineBinPack::FreeRectChoiceHeuristic)typeHeuristic, (GuillotineBinPack::GuillotineSplitHeuristic)typeSplit);
|
|
||||||
break; }
|
|
||||||
default:
|
|
||||||
ABORT("error: unknown RectsBinPack type");
|
|
||||||
}
|
|
||||||
DEBUG_ULTIMATE("\tpacking texture completed: %u initial patches, %u placed patches, %u texture-size, %u textures (%s)", texturePatches.size(), newPlacedRects.size(), textureSize, placedRects.size(), TD_TIMER_GET_FMT().c_str());
|
|
||||||
|
|
||||||
if (textureSize == maxTextureSize || unplacedRects.empty()) {
|
|
||||||
// create texture image
|
|
||||||
placedRects.emplace_back(std::move(newPlacedRects));
|
|
||||||
// Pixel8U colEmpty2=Pixel8U(0,0,255);
|
|
||||||
texturesDiffuseTemp.emplace_back(textureSize, textureSize).setTo(cv::Scalar(colEmpty.b, colEmpty.g, colEmpty.r));
|
|
||||||
textureSize = 0;
|
|
||||||
} else {
|
|
||||||
// try again with a bigger texture
|
|
||||||
textureSize *= 2;
|
|
||||||
if (maxTextureSize > 0)
|
|
||||||
textureSize = std::max(textureSize, maxTextureSize);
|
|
||||||
unplacedRects.JoinRemove(newPlacedRects);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
LOG_OUT() << "Third loop completed" << std::endl;
|
|
||||||
|
|
||||||
Mesh::FaceIdxArr emptyFaceIndexes;
|
|
||||||
|
|
||||||
{
|
|
||||||
#ifdef TEXOPT_USE_OPENMP
|
|
||||||
#pragma omp parallel for schedule(dynamic)
|
|
||||||
for (int_t i=0; i<(int_t)placedRects.size(); ++i) {
|
|
||||||
for (int_t j=0; j<(int_t)placedRects[(TexIndex)i].size(); ++j) {
|
|
||||||
const TexIndex idxTexture((TexIndex)i);
|
|
||||||
const uint32_t idxPlacedPatch((uint32_t)j);
|
|
||||||
#else
|
|
||||||
FOREACH(idxTexture, placedRects) {
|
|
||||||
FOREACH(idxPlacedPatch, placedRects[idxTexture]) {
|
|
||||||
#endif
|
|
||||||
const TexturePatch& texturePatch = texturePatches[placedRects[idxTexture][idxPlacedPatch].patchIdx];
|
|
||||||
const RectsBinPack::Rect& rect = placedRects[idxTexture][idxPlacedPatch].rect;
|
|
||||||
// copy patch image
|
|
||||||
ASSERT((rect.width == texturePatch.rect.width && rect.height == texturePatch.rect.height) ||
|
|
||||||
(rect.height == texturePatch.rect.width && rect.width == texturePatch.rect.height));
|
|
||||||
int x(0), y(1);
|
|
||||||
if (texturePatch.label != NO_ID) {
|
|
||||||
const Image& imageData = images[texturePatch.label];
|
|
||||||
cv::Mat patch(imageData.image(texturePatch.rect));
|
|
||||||
if (rect.width != texturePatch.rect.width) {
|
|
||||||
// flip patch and texture-coordinates
|
|
||||||
patch = patch.t();
|
|
||||||
x = 1; y = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
patch.copyTo(texturesDiffuseTemp[idxTexture](rect));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
auto it = texturePatch.faces.begin();
|
|
||||||
while (it != texturePatch.faces.end())
|
|
||||||
{
|
|
||||||
emptyFaceIndexes.push_back(*it);
|
|
||||||
++it;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// compute final texture coordinates
|
|
||||||
const TexCoord offset(rect.tl());
|
|
||||||
for (const FIndex idxFace: texturePatch.faces) {
|
|
||||||
TexCoord* texcoords = faceTexcoords2.data()+idxFace*3;
|
|
||||||
faceTexindices2[idxFace] = idxTexture;
|
|
||||||
for (int v=0; v<3; ++v) {
|
|
||||||
TexCoord& texcoord = texcoords[v];
|
|
||||||
texcoord = TexCoord(
|
|
||||||
texcoord[x]+offset.x,
|
|
||||||
texcoord[y]+offset.y
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (texturesDiffuseTemp.size() == 1)
|
|
||||||
faceTexindices2.Release();
|
|
||||||
|
|
||||||
// apply some sharpening
|
|
||||||
if (fSharpnessWeight > 0) {
|
|
||||||
constexpr double sigma = 1.5;
|
|
||||||
for (auto &textureDiffuse: texturesDiffuseTemp) {
|
|
||||||
Image8U3 blurryTextureDiffuse;
|
|
||||||
cv::GaussianBlur(textureDiffuse, blurryTextureDiffuse, cv::Size(), sigma);
|
|
||||||
cv::addWeighted(textureDiffuse, 1+fSharpnessWeight, blurryTextureDiffuse, -fSharpnessWeight, 0, textureDiffuse);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
LOG_OUT() << "Fourth loop completed" << std::endl;
|
|
||||||
|
|
||||||
std::ofstream out(basename + "_empty_color_triangles.txt");
|
|
||||||
RFOREACHPTR(pIdxF, emptyFaceIndexes) {
|
|
||||||
out << *pIdxF << "\n";
|
|
||||||
}
|
|
||||||
out.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void MeshTexture::GlobalSeamLevelingExternalUV()
|
void MeshTexture::GlobalSeamLevelingExternalUV()
|
||||||
{
|
{
|
||||||
// 针对外部UV数据的全局接缝处理
|
// 针对外部UV数据的全局接缝处理
|
||||||
@@ -10679,251 +10324,6 @@ void MeshTexture::LocalSeamLeveling()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MeshTexture::GenerateTexture2(bool bGlobalSeamLeveling, bool bLocalSeamLeveling, unsigned nTextureSizeMultiple, unsigned nRectPackingHeuristic, Pixel8U colEmpty, float fSharpnessWeight, int maxTextureSize, const SEACAVE::String& basename)
|
|
||||||
{
|
|
||||||
// Bruce
|
|
||||||
bGlobalSeamLeveling = false;
|
|
||||||
bLocalSeamLeveling = false;
|
|
||||||
// project patches in the corresponding view and compute texture-coordinates and bounding-box
|
|
||||||
const int border(2);
|
|
||||||
faceTexcoords.resize(faces.size()*3);
|
|
||||||
faceTexindices.resize(faces.size());
|
|
||||||
#ifdef TEXOPT_USE_OPENMP
|
|
||||||
// LOG_OUT() << "def TEXOPT_USE_OPENMP" << std::endl;
|
|
||||||
const unsigned numPatches(texturePatches.size()-1);
|
|
||||||
#pragma omp parallel for schedule(dynamic)
|
|
||||||
for (int_t idx=0; idx<(int_t)numPatches; ++idx) {
|
|
||||||
TexturePatch& texturePatch = texturePatches[(uint32_t)idx];
|
|
||||||
#else
|
|
||||||
for (TexturePatch *pTexturePatch=texturePatches.Begin(), *pTexturePatchEnd=texturePatches.End()-1; pTexturePatch<pTexturePatchEnd; ++pTexturePatch) {
|
|
||||||
TexturePatch& texturePatch = *pTexturePatch;
|
|
||||||
#endif
|
|
||||||
const Image& imageData = images[texturePatch.label];
|
|
||||||
AABB2f aabb(true);
|
|
||||||
for (const FIndex idxFace: texturePatch.faces) {
|
|
||||||
const Face& face = faces[idxFace];
|
|
||||||
TexCoord* texcoords = faceTexcoords.data()+idxFace*3;
|
|
||||||
for (int i=0; i<3; ++i) {
|
|
||||||
texcoords[i] = imageData.camera.ProjectPointP(vertices[face[i]]);
|
|
||||||
ASSERT(imageData.image.isInsideWithBorder(texcoords[i], border));
|
|
||||||
aabb.InsertFull(texcoords[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// compute relative texture coordinates
|
|
||||||
ASSERT(imageData.image.isInside(Point2f(aabb.ptMin)));
|
|
||||||
ASSERT(imageData.image.isInside(Point2f(aabb.ptMax)));
|
|
||||||
texturePatch.rect.x = FLOOR2INT(aabb.ptMin[0])-border;
|
|
||||||
texturePatch.rect.y = FLOOR2INT(aabb.ptMin[1])-border;
|
|
||||||
texturePatch.rect.width = CEIL2INT(aabb.ptMax[0]-aabb.ptMin[0])+border*2;
|
|
||||||
texturePatch.rect.height = CEIL2INT(aabb.ptMax[1]-aabb.ptMin[1])+border*2;
|
|
||||||
ASSERT(imageData.image.isInside(texturePatch.rect.tl()));
|
|
||||||
ASSERT(imageData.image.isInside(texturePatch.rect.br()));
|
|
||||||
const TexCoord offset(texturePatch.rect.tl());
|
|
||||||
for (const FIndex idxFace: texturePatch.faces) {
|
|
||||||
TexCoord* texcoords = faceTexcoords.data()+idxFace*3;
|
|
||||||
for (int v=0; v<3; ++v)
|
|
||||||
texcoords[v] -= offset;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
{
|
|
||||||
// init last patch to point to a small uniform color patch
|
|
||||||
TexturePatch& texturePatch = texturePatches.back();
|
|
||||||
const int sizePatch(border*2+1);
|
|
||||||
texturePatch.rect = cv::Rect(0,0, sizePatch,sizePatch);
|
|
||||||
for (const FIndex idxFace: texturePatch.faces) {
|
|
||||||
TexCoord* texcoords = faceTexcoords.data()+idxFace*3;
|
|
||||||
for (int i=0; i<3; ++i)
|
|
||||||
texcoords[i] = TexCoord(0.5f, 0.5f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
LOG_OUT() << "First loop completed" << std::endl;
|
|
||||||
// perform seam leveling
|
|
||||||
if (texturePatches.size() > 2 && (bGlobalSeamLeveling || bLocalSeamLeveling)) {
|
|
||||||
// create seam vertices and edges
|
|
||||||
CreateSeamVertices();
|
|
||||||
|
|
||||||
// perform global seam leveling
|
|
||||||
if (bGlobalSeamLeveling) {
|
|
||||||
TD_TIMER_STARTD();
|
|
||||||
GlobalSeamLeveling();
|
|
||||||
DEBUG_ULTIMATE("\tglobal seam leveling completed (%s)", TD_TIMER_GET_FMT().c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
// perform local seam leveling
|
|
||||||
if (bLocalSeamLeveling) {
|
|
||||||
TD_TIMER_STARTD();
|
|
||||||
LocalSeamLeveling();
|
|
||||||
DEBUG_ULTIMATE("\tlocal seam leveling completed (%s)", TD_TIMER_GET_FMT().c_str());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// merge texture patches with overlapping rectangles
|
|
||||||
for (unsigned i=0; i<texturePatches.size()-1; ++i) {
|
|
||||||
TexturePatch& texturePatchBig = texturePatches[i];
|
|
||||||
for (unsigned j=1; j<texturePatches.size(); ++j) {
|
|
||||||
if (i == j)
|
|
||||||
continue;
|
|
||||||
TexturePatch& texturePatchSmall = texturePatches[j];
|
|
||||||
if (texturePatchBig.label != texturePatchSmall.label)
|
|
||||||
continue;
|
|
||||||
if (!RectsBinPack::IsContainedIn(texturePatchSmall.rect, texturePatchBig.rect))
|
|
||||||
continue;
|
|
||||||
// translate texture coordinates
|
|
||||||
const TexCoord offset(texturePatchSmall.rect.tl()-texturePatchBig.rect.tl());
|
|
||||||
for (const FIndex idxFace: texturePatchSmall.faces) {
|
|
||||||
TexCoord* texcoords = faceTexcoords.data()+idxFace*3;
|
|
||||||
for (int v=0; v<3; ++v)
|
|
||||||
texcoords[v] += offset;
|
|
||||||
}
|
|
||||||
// join faces lists
|
|
||||||
texturePatchBig.faces.JoinRemove(texturePatchSmall.faces);
|
|
||||||
// remove the small patch
|
|
||||||
texturePatches.RemoveAtMove(j--);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
LOG_OUT() << "Second loop completed" << std::endl;
|
|
||||||
// create texture
|
|
||||||
{
|
|
||||||
// arrange texture patches to fit the smallest possible texture image
|
|
||||||
// const unsigned minPatchSize = 20;
|
|
||||||
RectsBinPack::RectWIdxArr unplacedRects(texturePatches.size());
|
|
||||||
FOREACH(i, texturePatches) {
|
|
||||||
|
|
||||||
// LOG_OUT() << "Third loop completed" << std::endl;
|
|
||||||
if (maxTextureSize > 0 && (texturePatches[i].rect.width > maxTextureSize || texturePatches[i].rect.height > maxTextureSize)) {
|
|
||||||
DEBUG("error: a patch of size %u x %u does not fit the texture", texturePatches[i].rect.width, texturePatches[i].rect.height);
|
|
||||||
ABORT("the maximum texture size chosen cannot fit a patch");
|
|
||||||
}
|
|
||||||
unplacedRects[i] = {texturePatches[i].rect, i};
|
|
||||||
}
|
|
||||||
LOG_OUT() << "unplacedRects loop completed" << std::endl;
|
|
||||||
|
|
||||||
LOG_OUT() << "pack patches: one pack per texture file loop completed" << std::endl;
|
|
||||||
// pack patches: one pack per texture file
|
|
||||||
CLISTDEF2IDX(RectsBinPack::RectWIdxArr, TexIndex) placedRects; {
|
|
||||||
// increase texture size till all patches fit
|
|
||||||
const unsigned typeRectsBinPack(nRectPackingHeuristic/100);
|
|
||||||
const unsigned typeSplit((nRectPackingHeuristic-typeRectsBinPack*100)/10);
|
|
||||||
const unsigned typeHeuristic(nRectPackingHeuristic%10);
|
|
||||||
int textureSize = 0;
|
|
||||||
while (!unplacedRects.empty()) {
|
|
||||||
TD_TIMER_STARTD();
|
|
||||||
if (textureSize == 0) {
|
|
||||||
textureSize = RectsBinPack::ComputeTextureSize(unplacedRects, nTextureSizeMultiple);
|
|
||||||
if (maxTextureSize > 0 && textureSize > maxTextureSize)
|
|
||||||
textureSize = maxTextureSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
RectsBinPack::RectWIdxArr newPlacedRects;
|
|
||||||
switch (typeRectsBinPack) {
|
|
||||||
case 0: {
|
|
||||||
MaxRectsBinPack pack(textureSize, textureSize);
|
|
||||||
newPlacedRects = pack.Insert(unplacedRects, (MaxRectsBinPack::FreeRectChoiceHeuristic)typeHeuristic);
|
|
||||||
break; }
|
|
||||||
case 1: {
|
|
||||||
SkylineBinPack pack(textureSize, textureSize, typeSplit!=0);
|
|
||||||
newPlacedRects = pack.Insert(unplacedRects, (SkylineBinPack::LevelChoiceHeuristic)typeHeuristic);
|
|
||||||
break; }
|
|
||||||
case 2: {
|
|
||||||
GuillotineBinPack pack(textureSize, textureSize);
|
|
||||||
newPlacedRects = pack.Insert(unplacedRects, false, (GuillotineBinPack::FreeRectChoiceHeuristic)typeHeuristic, (GuillotineBinPack::GuillotineSplitHeuristic)typeSplit);
|
|
||||||
break; }
|
|
||||||
default:
|
|
||||||
ABORT("error: unknown RectsBinPack type");
|
|
||||||
}
|
|
||||||
DEBUG_ULTIMATE("\tpacking texture completed: %u initial patches, %u placed patches, %u texture-size, %u textures (%s)", texturePatches.size(), newPlacedRects.size(), textureSize, placedRects.size(), TD_TIMER_GET_FMT().c_str());
|
|
||||||
|
|
||||||
if (textureSize == maxTextureSize || unplacedRects.empty()) {
|
|
||||||
// create texture image
|
|
||||||
placedRects.emplace_back(std::move(newPlacedRects));
|
|
||||||
texturesDiffuse.emplace_back(textureSize, textureSize).setTo(cv::Scalar(colEmpty.b, colEmpty.g, colEmpty.r));
|
|
||||||
textureSize = 0;
|
|
||||||
} else {
|
|
||||||
// try again with a bigger texture
|
|
||||||
textureSize *= 2;
|
|
||||||
if (maxTextureSize > 0)
|
|
||||||
textureSize = std::max(textureSize, maxTextureSize);
|
|
||||||
unplacedRects.JoinRemove(newPlacedRects);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
LOG_OUT() << "Third loop completed" << std::endl;
|
|
||||||
Mesh::FaceIdxArr emptyFaceIndexes;
|
|
||||||
|
|
||||||
#ifdef TEXOPT_USE_OPENMP
|
|
||||||
#pragma omp parallel for schedule(dynamic)
|
|
||||||
for (int_t i=0; i<(int_t)placedRects.size(); ++i) {
|
|
||||||
for (int_t j=0; j<(int_t)placedRects[(TexIndex)i].size(); ++j) {
|
|
||||||
const TexIndex idxTexture((TexIndex)i);
|
|
||||||
const uint32_t idxPlacedPatch((uint32_t)j);
|
|
||||||
#else
|
|
||||||
FOREACH(idxTexture, placedRects) {
|
|
||||||
FOREACH(idxPlacedPatch, placedRects[idxTexture]) {
|
|
||||||
#endif
|
|
||||||
const TexturePatch& texturePatch = texturePatches[placedRects[idxTexture][idxPlacedPatch].patchIdx];
|
|
||||||
const RectsBinPack::Rect& rect = placedRects[idxTexture][idxPlacedPatch].rect;
|
|
||||||
// copy patch image
|
|
||||||
ASSERT((rect.width == texturePatch.rect.width && rect.height == texturePatch.rect.height) ||
|
|
||||||
(rect.height == texturePatch.rect.width && rect.width == texturePatch.rect.height));
|
|
||||||
int x(0), y(1);
|
|
||||||
if (texturePatch.label != NO_ID) {
|
|
||||||
const Image& imageData = images[texturePatch.label];
|
|
||||||
cv::Mat patch(imageData.image(texturePatch.rect));
|
|
||||||
if (rect.width != texturePatch.rect.width) {
|
|
||||||
// flip patch and texture-coordinates
|
|
||||||
patch = patch.t();
|
|
||||||
x = 1; y = 0;
|
|
||||||
}
|
|
||||||
patch.copyTo(texturesDiffuse[idxTexture](rect));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
auto it = texturePatch.faces.begin();
|
|
||||||
while (it != texturePatch.faces.end())
|
|
||||||
{
|
|
||||||
emptyFaceIndexes.push_back(*it);
|
|
||||||
++it;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// compute final texture coordinates
|
|
||||||
const TexCoord offset(rect.tl());
|
|
||||||
for (const FIndex idxFace: texturePatch.faces) {
|
|
||||||
TexCoord* texcoords = faceTexcoords.data()+idxFace*3;
|
|
||||||
faceTexindices[idxFace] = idxTexture;
|
|
||||||
for (int v=0; v<3; ++v) {
|
|
||||||
TexCoord& texcoord = texcoords[v];
|
|
||||||
texcoord = TexCoord(
|
|
||||||
texcoord[x]+offset.x,
|
|
||||||
texcoord[y]+offset.y
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (texturesDiffuse.size() == 1)
|
|
||||||
faceTexindices.Release();
|
|
||||||
// apply some sharpening
|
|
||||||
if (fSharpnessWeight > 0) {
|
|
||||||
constexpr double sigma = 1.5;
|
|
||||||
for (auto &textureDiffuse: texturesDiffuse) {
|
|
||||||
Image8U3 blurryTextureDiffuse;
|
|
||||||
cv::GaussianBlur(textureDiffuse, blurryTextureDiffuse, cv::Size(), sigma);
|
|
||||||
cv::addWeighted(textureDiffuse, 1+fSharpnessWeight, blurryTextureDiffuse, -fSharpnessWeight, 0, textureDiffuse);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
LOG_OUT() << "Fourth loop completed" << std::endl;
|
|
||||||
|
|
||||||
std::ofstream out(basename + "_empty_color_triangles.txt");
|
|
||||||
RFOREACHPTR(pIdxF, emptyFaceIndexes) {
|
|
||||||
out << *pIdxF << "\n";
|
|
||||||
}
|
|
||||||
out.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#include <opencv2/imgcodecs.hpp>
|
#include <opencv2/imgcodecs.hpp>
|
||||||
|
|
||||||
// 保存生成的纹理图集
|
// 保存生成的纹理图集
|
||||||
@@ -18538,7 +17938,7 @@ bool Scene::TextureMesh(unsigned nResolutionLevel, unsigned nMinResolution, unsi
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 检查UV有效性
|
// 检查UV有效性
|
||||||
mesh.CheckUVValid();
|
// mesh.CheckUVValid();
|
||||||
|
|
||||||
DEBUG_EXTRA("TextureMesh bUseExistingUV=%d, UVMeshFile=%s", bUseExistingUV, strUVMeshFileName.c_str());
|
DEBUG_EXTRA("TextureMesh bUseExistingUV=%d, UVMeshFile=%s", bUseExistingUV, strUVMeshFileName.c_str());
|
||||||
|
|
||||||
@@ -18552,7 +17952,7 @@ bool Scene::TextureMesh(unsigned nResolutionLevel, unsigned nMinResolution, unsi
|
|||||||
// }
|
// }
|
||||||
|
|
||||||
VERBOSE("2faceTexcoords.size=%d, faces.size=%d", mesh.faceTexcoords.size(), mesh.faces.size() * 3);
|
VERBOSE("2faceTexcoords.size=%d, faces.size=%d", mesh.faceTexcoords.size(), mesh.faces.size() * 3);
|
||||||
mesh.CheckUVValid();
|
// mesh.CheckUVValid();
|
||||||
|
|
||||||
// 确保网格包含UV坐标
|
// 确保网格包含UV坐标
|
||||||
if (mesh.faceTexcoords.empty()) {
|
if (mesh.faceTexcoords.empty()) {
|
||||||
@@ -18580,7 +17980,7 @@ bool Scene::TextureMesh(unsigned nResolutionLevel, unsigned nMinResolution, unsi
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 最终UV检查
|
// 最终UV检查
|
||||||
mesh.CheckUVValid();
|
// mesh.CheckUVValid();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
} // TextureMesh
|
} // TextureMesh
|
||||||
|
|||||||
Reference in new issue
Block a user