|
|
|
|
@ -9213,8 +9213,6 @@ void MeshTexture::GlobalSeamLeveling4()
@@ -9213,8 +9213,6 @@ void MeshTexture::GlobalSeamLeveling4()
|
|
|
|
|
i, components[i], texturePatches.size()); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
DEBUG_EXTRA("Input validation done. seamVertices=%zu, faces=%u, vertices=%zu", |
|
|
|
|
seamVertices.GetSize(), faces.GetSize(), vertices.size()); |
|
|
|
|
|
|
|
|
|
// ========== 标记无效顶点 ==========
|
|
|
|
|
BoolArr vertexInvalid(vertices.size()); |
|
|
|
|
@ -9234,7 +9232,7 @@ void MeshTexture::GlobalSeamLeveling4()
@@ -9234,7 +9232,7 @@ void MeshTexture::GlobalSeamLeveling4()
|
|
|
|
|
if (components[f] == NO_ID) { |
|
|
|
|
const Face& face = faces[f]; |
|
|
|
|
for (int v = 0; v < 3; ++v) |
|
|
|
|
patchIndices[face[v]].idxPatch = numPatches; // dummy,后面跳过
|
|
|
|
|
patchIndices[face[v]].idxPatch = numPatches; |
|
|
|
|
continue; |
|
|
|
|
} |
|
|
|
|
const uint32_t idxPatch(mapIdxPatch[components[f]]); |
|
|
|
|
@ -9252,7 +9250,7 @@ void MeshTexture::GlobalSeamLeveling4()
@@ -9252,7 +9250,7 @@ void MeshTexture::GlobalSeamLeveling4()
|
|
|
|
|
patchIndex.idxSeamVertex = i; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// ========== 构建 vertpatch2rows(块列号 → 连续行)==========
|
|
|
|
|
// ========== 构建 vertpatch2rows ==========
|
|
|
|
|
ASSERT(vertices.size() < static_cast<VIndex>(std::numeric_limits<MatIdx>::max())); |
|
|
|
|
MatIdx rowsX(0); |
|
|
|
|
typedef std::unordered_map<uint32_t, MatIdx> VertexPatch2RowMap; |
|
|
|
|
@ -9268,18 +9266,18 @@ void MeshTexture::GlobalSeamLeveling4()
@@ -9268,18 +9266,18 @@ void MeshTexture::GlobalSeamLeveling4()
|
|
|
|
|
ASSERT(patch.idxPatch != numPatches); |
|
|
|
|
ASSERT(patch.idxPatch < numPatches); |
|
|
|
|
if (vertpatch2row.find(patch.idxPatch) != vertpatch2row.end()) |
|
|
|
|
continue; // 去重
|
|
|
|
|
continue; |
|
|
|
|
vertpatch2row[patch.idxPatch] = rowsX++; |
|
|
|
|
} |
|
|
|
|
} else if (patchIndex.idxPatch < numPatches) { |
|
|
|
|
vertpatch2row[patchIndex.idxPatch] = rowsX++; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
const Eigen::Index scalarCols = (Eigen::Index)rowsX * 3; // 每块 3 个标量列 (RGB)
|
|
|
|
|
DEBUG_EXTRA("vertpatch2rows built: rowsX(blocks)=%u, scalarCols=%lld", rowsX, (long long)scalarCols); |
|
|
|
|
const Eigen::Index scalarCols = (Eigen::Index)rowsX * 3; |
|
|
|
|
DEBUG_EXTRA("vertpatch2rows built: rowsX=%u, scalarCols=%lld", rowsX, (long long)scalarCols); |
|
|
|
|
|
|
|
|
|
// ============================================================
|
|
|
|
|
// ========== 构建 Gamma(Tikhonov 正则)========== [修复1: 去重]
|
|
|
|
|
// ========== 构建 Gamma(Tikhonov 正则)==========
|
|
|
|
|
// ============================================================
|
|
|
|
|
std::vector<GSLTriplet> gammaTriplets; |
|
|
|
|
gammaTriplets.reserve((size_t)vertices.size() * 8); |
|
|
|
|
@ -9293,7 +9291,7 @@ void MeshTexture::GlobalSeamLeveling4()
@@ -9293,7 +9291,7 @@ void MeshTexture::GlobalSeamLeveling4()
|
|
|
|
|
adjVerts.Empty(); |
|
|
|
|
scene.mesh.GetAdjVertices(v, adjVerts); |
|
|
|
|
|
|
|
|
|
const size_t MAX_ADJ = 8; // ★ 限制邻接度数,控制规模
|
|
|
|
|
const size_t MAX_ADJ = 8; |
|
|
|
|
if (adjVerts.GetSize() > MAX_ADJ) adjVerts.Resize(MAX_ADJ); |
|
|
|
|
|
|
|
|
|
VertexPatchIterator itV(patchIndices[v], seamVertices); |
|
|
|
|
@ -9305,11 +9303,11 @@ void MeshTexture::GlobalSeamLeveling4()
@@ -9305,11 +9303,11 @@ void MeshTexture::GlobalSeamLeveling4()
|
|
|
|
|
const Eigen::Index colA = it_row->second; |
|
|
|
|
|
|
|
|
|
for (const VIndex vAdj : adjVerts) { |
|
|
|
|
if (v >= vAdj) continue; // ★ 无向边只处理一次(去重关键)
|
|
|
|
|
if (v >= vAdj) continue; |
|
|
|
|
VertexPatchIterator itVAdj(patchIndices[vAdj], seamVertices); |
|
|
|
|
while (itVAdj.Next()) { |
|
|
|
|
const uint32_t idxPatchAdj(itVAdj); |
|
|
|
|
if (idxPatch != idxPatchAdj) continue; // 同一 patch 才正则化
|
|
|
|
|
if (idxPatch != idxPatchAdj) continue; |
|
|
|
|
auto it_rowAdj = vertpatch2rows[vAdj].find(idxPatchAdj); |
|
|
|
|
if (it_rowAdj == vertpatch2rows[vAdj].end()) continue; |
|
|
|
|
const Eigen::Index colB = it_rowAdj->second; |
|
|
|
|
@ -9321,7 +9319,6 @@ void MeshTexture::GlobalSeamLeveling4()
@@ -9321,7 +9319,6 @@ void MeshTexture::GlobalSeamLeveling4()
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// ★ 排序 + 去重合并(消除重复邻接 → 保证矩阵性质良好)
|
|
|
|
|
std::sort(rawGamma.begin(), rawGamma.end(), |
|
|
|
|
[](const GammaRaw& a, const GammaRaw& b) { |
|
|
|
|
return a.colA < b.colA || (a.colA == b.colA && a.colB < b.colB); |
|
|
|
|
@ -9339,16 +9336,12 @@ void MeshTexture::GlobalSeamLeveling4()
@@ -9339,16 +9336,12 @@ void MeshTexture::GlobalSeamLeveling4()
|
|
|
|
|
i = j; |
|
|
|
|
} |
|
|
|
|
const Eigen::Index rowsGamma = rowG; |
|
|
|
|
DEBUG_EXTRA("Gamma after dedup: triplets=%zu, rowsGamma=%lld, scalarCols=%lld", |
|
|
|
|
gammaTriplets.size(), (long long)rowsGamma, (long long)scalarCols); |
|
|
|
|
|
|
|
|
|
SparseMat Gamma(rowsGamma, scalarCols); |
|
|
|
|
Gamma.setFromTriplets(gammaTriplets.begin(), gammaTriplets.end()); |
|
|
|
|
Gamma.makeCompressed(); |
|
|
|
|
gammaTriplets.clear(); gammaTriplets.shrink_to_fit(); |
|
|
|
|
rawGamma.clear(); rawGamma.shrink_to_fit(); |
|
|
|
|
DEBUG_EXTRA("Gamma built: %lld x %lld, nnz=%lld", (long long)Gamma.rows(), |
|
|
|
|
(long long)Gamma.cols(), (long long)Gamma.nonZeros()); |
|
|
|
|
|
|
|
|
|
// ============================================================
|
|
|
|
|
// ========== 构建矩阵 A 和 b(颜色一致性约束)==========
|
|
|
|
|
@ -9373,13 +9366,26 @@ void MeshTexture::GlobalSeamLeveling4()
@@ -9373,13 +9366,26 @@ void MeshTexture::GlobalSeamLeveling4()
|
|
|
|
|
const TexturePatch& tpRef = texturePatches[patch0.idxPatch]; |
|
|
|
|
if (tpRef.label < 0 || tpRef.label >= (IIndex)images.size()) continue; |
|
|
|
|
|
|
|
|
|
// ★FIX: 检查 patch0.proj 是否为 NaN/Inf(崩溃根源)
|
|
|
|
|
if (std::isnan(patch0.proj.x) || std::isnan(patch0.proj.y) || |
|
|
|
|
std::isinf(patch0.proj.x) || std::isinf(patch0.proj.y)) { |
|
|
|
|
vertexColors[i] = Color::ZERO; |
|
|
|
|
continue; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
SampleImage sampler(images[tpRef.label].image); |
|
|
|
|
for (const SeamVertex::Patch::Edge& edge : patch0.edges) { |
|
|
|
|
if (edge.idxSeamVertex >= seamVertices.GetSize()) continue; // 越界保护
|
|
|
|
|
if (edge.idxSeamVertex >= seamVertices.GetSize()) continue; |
|
|
|
|
const SeamVertex& seamVertex1 = seamVertices[edge.idxSeamVertex]; |
|
|
|
|
const auto idxPatch1 = seamVertex1.patches.Find(patch0.idxPatch); |
|
|
|
|
if (idxPatch1 == SeamVertex::Patches::NO_INDEX) continue; |
|
|
|
|
const SeamVertex::Patch& patch1 = seamVertex1.patches[idxPatch1]; |
|
|
|
|
|
|
|
|
|
// ★FIX: 检查 patch1.proj 是否为 NaN/Inf,防止 AddEdge 崩溃
|
|
|
|
|
if (std::isnan(patch1.proj.x) || std::isnan(patch1.proj.y) || |
|
|
|
|
std::isinf(patch1.proj.x) || std::isinf(patch1.proj.y)) |
|
|
|
|
continue; |
|
|
|
|
|
|
|
|
|
sampler.AddEdge(patch0.proj, patch1.proj); |
|
|
|
|
} |
|
|
|
|
vertexColors[i] = sampler.GetColor(); |
|
|
|
|
@ -9398,87 +9404,69 @@ void MeshTexture::GlobalSeamLeveling4()
@@ -9398,87 +9404,69 @@ void MeshTexture::GlobalSeamLeveling4()
|
|
|
|
|
const Color& ca = vertexColors[i]; |
|
|
|
|
const Color& cb = vertexColors[j]; |
|
|
|
|
for (int c = 0; c < 3; ++c) { |
|
|
|
|
const Eigen::Index colA = baseA * 3 + c; // ★ 标量列 = base*3 + c
|
|
|
|
|
const Eigen::Index colA = baseA * 3 + c; |
|
|
|
|
const Eigen::Index colB = baseB * 3 + c; |
|
|
|
|
ATriplets.emplace_back(rowA, colA, 1.0f); |
|
|
|
|
ATriplets.emplace_back(rowA, colB, -1.0f); |
|
|
|
|
if ((size_t)rowA >= b_coeff.size()) b_coeff.push_back(0); |
|
|
|
|
b_coeff[rowA] = cb[c] - ca[c]; // 差值方程
|
|
|
|
|
b_coeff[rowA] = cb[c] - ca[c]; |
|
|
|
|
++rowA; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
const Eigen::Index rowsA = rowA; |
|
|
|
|
ASSERT(rowsA <= (Eigen::Index)b_coeff.size()); |
|
|
|
|
SparseMat A(rowsA, scalarCols); |
|
|
|
|
A.setFromTriplets(ATriplets.begin(), ATriplets.end()); |
|
|
|
|
A.makeCompressed(); |
|
|
|
|
ATriplets.clear(); ATriplets.shrink_to_fit(); |
|
|
|
|
DEBUG_EXTRA("Matrix A built: %lld constraints, scalarCols=%lld, nnz=%lld", |
|
|
|
|
(long long)rowsA, (long long)scalarCols, (long long)A.nonZeros()); |
|
|
|
|
|
|
|
|
|
// ============================================================
|
|
|
|
|
// ========== 求解:Lhs = AᵀA + λ²ΓᵀΓ,对角扰动保证正定 [修复2]
|
|
|
|
|
// ========== 求解 ==========
|
|
|
|
|
// ============================================================
|
|
|
|
|
std::vector<Color> colorAdjustments; |
|
|
|
|
colorAdjustments.assign(rowsX, Color::ZERO); |
|
|
|
|
|
|
|
|
|
if (rowsA > 0 && rowsX > 0) { |
|
|
|
|
// ★ Lhs = AᵀA + λ² ΓᵀΓ
|
|
|
|
|
SparseMat ATA = A.transpose() * A; |
|
|
|
|
SparseMat GTG = Gamma.transpose() * Gamma; |
|
|
|
|
const float lambda = 0.5f; // ★ 正则化强度(可调)
|
|
|
|
|
const float lambda = 0.1f; |
|
|
|
|
GTG *= lambda * lambda; |
|
|
|
|
ASSERT(ATA.rows() == GTG.rows() && ATA.cols() == GTG.cols()); // 尺寸一致性检查
|
|
|
|
|
ATA += GTG; |
|
|
|
|
SparseMat& Lhs = ATA; |
|
|
|
|
|
|
|
|
|
// ★★★ 对角加扰动,严格保证正定 ★★★
|
|
|
|
|
const float eps = 1e-3f; // 足够小不影响结果,保证正定
|
|
|
|
|
const float eps = 1e-3f; |
|
|
|
|
for (Eigen::Index i = 0; i < (Eigen::Index)Lhs.rows(); ++i) { |
|
|
|
|
Lhs.coeffRef(i, i) += eps; |
|
|
|
|
} |
|
|
|
|
DEBUG_EXTRA("Lhs built: %lld x %lld, nnz=%lld (diag += %g)", |
|
|
|
|
(long long)Lhs.rows(), (long long)Lhs.cols(), |
|
|
|
|
(long long)Lhs.nonZeros(), eps); |
|
|
|
|
|
|
|
|
|
// ★ 用 ConjugateGradient(只需对称,不要求严格 SPD)
|
|
|
|
|
Eigen::ConjugateGradient<SparseMat, Eigen::Lower> solver; |
|
|
|
|
solver.setMaxIterations(2000); |
|
|
|
|
solver.setTolerance(0.001f); |
|
|
|
|
solver.compute(Lhs); |
|
|
|
|
if (solver.info() != Eigen::Success) { |
|
|
|
|
DEBUG_EXTRA("WARN: Lhs compute failed (info=%d), skipping solve", (int)solver.info()); |
|
|
|
|
} else { |
|
|
|
|
// ★ b 与通道无关 → 一次求解,结果按 InnerStride<3> 分通道
|
|
|
|
|
if (solver.info() == Eigen::Success) { |
|
|
|
|
Eigen::VectorXf b(rowsA); |
|
|
|
|
for (Eigen::Index k = 0; k < rowsA; ++k) b(k) = b_coeff[k]; |
|
|
|
|
const Eigen::VectorXf rhs = A.transpose() * b; |
|
|
|
|
const Eigen::VectorXf x = solver.solve(rhs); |
|
|
|
|
DEBUG_EXTRA("solve: %d iterations, residual=%g", solver.iterations(), solver.error()); |
|
|
|
|
|
|
|
|
|
// ★ 从 x 提取 colorAdjustments(每块一个 Color,显式循环避免对齐问题)
|
|
|
|
|
if (solver.info() == Eigen::Success && (Eigen::Index)(x.size()) >= scalarCols) { |
|
|
|
|
colorAdjustments.assign(rowsX, Color::ZERO); |
|
|
|
|
for (Eigen::Index v = 0; v < (Eigen::Index)rowsX; ++v) { |
|
|
|
|
const float r = x(v * 3 + 0); |
|
|
|
|
const float g = x(v * 3 + 1); |
|
|
|
|
const float b_ch = x(v * 3 + 2); |
|
|
|
|
|
|
|
|
|
// ★ 恢复原版逻辑:计算均值并减去(消除亮度偏移,只保留色度调整)
|
|
|
|
|
const float mean = (r + g + b_ch) / 3.0f; |
|
|
|
|
// colorAdjustments[v] = Color(r, g, b_ch);
|
|
|
|
|
colorAdjustments[v] = Color(r - mean, g - mean, b_ch - mean); |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
DEBUG_EXTRA("WARN: solve not successful, using zero adjustments"); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
DEBUG_EXTRA("WARN: no constraints (rowsA=%lld), skip solve", (long long)rowsA); |
|
|
|
|
} |
|
|
|
|
DEBUG_EXTRA("solve done. colorAdjustments: %zux3", rowsX); |
|
|
|
|
b_coeff.clear(); b_coeff.shrink_to_fit(); |
|
|
|
|
|
|
|
|
|
// ========== 应用颜色修正(输出到 correctedPatchImages,不碰 images)==========
|
|
|
|
|
// ========== 应用颜色修正 ==========
|
|
|
|
|
correctedPatchImages.resize(numPatches); |
|
|
|
|
|
|
|
|
|
#ifdef TEXOPT_USE_OPENMP |
|
|
|
|
@ -9491,11 +9479,9 @@ void MeshTexture::GlobalSeamLeveling4()
@@ -9491,11 +9479,9 @@ void MeshTexture::GlobalSeamLeveling4()
|
|
|
|
|
if (texturePatch.label < 0 || texturePatch.label >= (int)images.size()) continue; |
|
|
|
|
if (texturePatch.rect.width <= 0 || texturePatch.rect.height <= 0) continue; |
|
|
|
|
|
|
|
|
|
// ★ 从原始 images 读(只读,不修改)
|
|
|
|
|
const cv::Mat& srcROI = images[texturePatch.label].image(texturePatch.rect); |
|
|
|
|
if (srcROI.empty()) continue; |
|
|
|
|
|
|
|
|
|
// ★ 创建独立输出 buffer
|
|
|
|
|
cv::Mat& outPatch = correctedPatchImages[idxPatch]; |
|
|
|
|
outPatch = cv::Mat::zeros(texturePatch.rect.size(), CV_8UC3); |
|
|
|
|
|
|
|
|
|
@ -9509,48 +9495,38 @@ void MeshTexture::GlobalSeamLeveling4()
@@ -9509,48 +9495,38 @@ void MeshTexture::GlobalSeamLeveling4()
|
|
|
|
|
RasterPatch(ColorMap& _image) : image(_image) {} |
|
|
|
|
inline cv::Size Size() const { return image.size(); } |
|
|
|
|
void operator()(const ImageRef& pt, const Point3f& bary) { |
|
|
|
|
image(pt) = colors[0]*bary.x + colors[1]*bary.y + colors[2]*bary.z; |
|
|
|
|
Color c = colors[0]*bary.x + colors[1]*bary.y + colors[2]*bary.z; |
|
|
|
|
// ★ 过滤 NaN/Inf 调整值
|
|
|
|
|
if (std::isnan(c[0]) || std::isnan(c[1]) || std::isnan(c[2]) || |
|
|
|
|
std::isinf(c[0]) || std::isinf(c[1]) || std::isinf(c[2])) { |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
image(pt) = c; |
|
|
|
|
} |
|
|
|
|
} data(imageAdj); |
|
|
|
|
ASSERT(texturePatch.faces.size() < 1000000); // 合理范围
|
|
|
|
|
|
|
|
|
|
for (const FIndex idxFace : texturePatch.faces) { |
|
|
|
|
if (idxFace >= faces.GetSize()) continue; |
|
|
|
|
const Face& face = faces[idxFace]; |
|
|
|
|
|
|
|
|
|
ASSERT(idxFace * 3 + 2 < faceTexcoords.GetSize()); |
|
|
|
|
for (int v = 0; v < 3; ++v) { |
|
|
|
|
ASSERT(face[v] < vertices.size()); |
|
|
|
|
ASSERT(face[v] < vertpatch2rows.size()); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// // ★ UV [0,1] → patch 局部像素坐标
|
|
|
|
|
// const cv::Size patchSize = texturePatch.rect.size();
|
|
|
|
|
// TexCoord localTri[3];
|
|
|
|
|
// const TexCoord* uvTri = faceTexcoords.Begin() + idxFace * 3;
|
|
|
|
|
// for (int v = 0; v < 3; ++v) {
|
|
|
|
|
// localTri[v] = TexCoord(uvTri[v].x * patchSize.width,
|
|
|
|
|
// uvTri[v].y * patchSize.height);
|
|
|
|
|
// }
|
|
|
|
|
// data.tri = localTri;
|
|
|
|
|
// 改回直接用,不乘
|
|
|
|
|
data.tri = faceTexcoords.Begin() + idxFace * 3; |
|
|
|
|
|
|
|
|
|
for (int v = 0; v < 3; ++v) { |
|
|
|
|
ASSERT(face[v] < vertices.size()); |
|
|
|
|
auto search = vertpatch2rows[face[v]].find(idxPatch); |
|
|
|
|
if (search != vertpatch2rows[face[v]].end()) |
|
|
|
|
{ |
|
|
|
|
if (search != vertpatch2rows[face[v]].end()) { |
|
|
|
|
ASSERT(search->second < (Eigen::Index)colorAdjustments.size()); |
|
|
|
|
data.colors[v] = colorAdjustments[search->second]; |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
} else { |
|
|
|
|
data.colors[v] = Color::ZERO; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
ColorMap::RasterizeTriangleBary(data.tri[0], data.tri[1], data.tri[2], data); |
|
|
|
|
} |
|
|
|
|
imageAdj.DilateMean<5>(imageAdj, Color::ZERO); |
|
|
|
|
|
|
|
|
|
// ★ 把修正叠加到 outPatch(从 srcROI 读原始颜色)
|
|
|
|
|
// ★FIX: 改回 DilateMean<1>(和原版一致,之前 <5> 过度模糊)
|
|
|
|
|
imageAdj.DilateMean<1>(imageAdj, Color::ZERO); |
|
|
|
|
|
|
|
|
|
// ★FIX: 去掉 GAIN=10,Y/Cb/Cr 全部 1:1 微调(和原版 GSL3 一致)
|
|
|
|
|
for (int r = 0; r < srcROI.rows; ++r) { |
|
|
|
|
for (int c = 0; c < srcROI.cols; ++c) { |
|
|
|
|
const Color& a = imageAdj(r, c); |
|
|
|
|
@ -9560,15 +9536,8 @@ void MeshTexture::GlobalSeamLeveling4()
@@ -9560,15 +9536,8 @@ void MeshTexture::GlobalSeamLeveling4()
|
|
|
|
|
} |
|
|
|
|
const Pixel8U& v = srcROI.at<Pixel8U>(r, c); |
|
|
|
|
const Color col(RGB2YCBCR(Color(v))); |
|
|
|
|
|
|
|
|
|
// const Color acol(YCBCR2RGB(Color(col + a)));
|
|
|
|
|
const float GAIN = 10.0f; // ★ 增益,可调(5~20)
|
|
|
|
|
const Color acol(YCBCR2RGB(Color( |
|
|
|
|
col[0] + a[0] * 1.0f, // Y 微调
|
|
|
|
|
col[1] + a[1] * GAIN, // Cb 大幅调
|
|
|
|
|
col[2] + a[2] * GAIN // Cr 大幅调
|
|
|
|
|
))); |
|
|
|
|
|
|
|
|
|
// ★ 直接加,不放大任何通道
|
|
|
|
|
const Color acol(YCBCR2RGB(Color(col + a))); |
|
|
|
|
outPatch.at<cv::Vec3b>(r, c) = cv::Vec3b( |
|
|
|
|
(uint8_t)CLAMP(ROUND2INT(acol[0]), 0, 255), |
|
|
|
|
(uint8_t)CLAMP(ROUND2INT(acol[1]), 0, 255), |
|
|
|
|
@ -9576,7 +9545,6 @@ void MeshTexture::GlobalSeamLeveling4()
@@ -9576,7 +9545,6 @@ void MeshTexture::GlobalSeamLeveling4()
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
DEBUG_EXTRA("All patch adjustments applied (to local buffers)"); |
|
|
|
|
|
|
|
|
|
DEBUG_EXTRA("GlobalSeamLeveling4 finished successfully."); |
|
|
|
|
} |
|
|
|
|
|