|
|
|
@ -16099,7 +16099,7 @@ void MeshTexture::ApplyGlobalSeamLevelingOnRCPatches( |
|
|
|
|
|
|
|
|
|
|
|
// ★ 如果求逆策略全部越界,尝试直接用 H(不逆)
|
|
|
|
// ★ 如果求逆策略全部越界,尝试直接用 H(不逆)
|
|
|
|
if (allOutOfRange) { |
|
|
|
if (allOutOfRange) { |
|
|
|
printf("[DIAG] Invert strategy failed for pi=%d, trying direct H...\n", pi); |
|
|
|
// printf("[DIAG] Invert strategy failed for pi=%d, trying direct H...\n", pi);
|
|
|
|
|
|
|
|
|
|
|
|
const float* H_direct = geom.homography.ptr<float>(); |
|
|
|
const float* H_direct = geom.homography.ptr<float>(); |
|
|
|
allOutOfRange = true; |
|
|
|
allOutOfRange = true; |
|
|
|
@ -16143,7 +16143,7 @@ void MeshTexture::ApplyGlobalSeamLevelingOnRCPatches( |
|
|
|
|
|
|
|
|
|
|
|
// 如果两种策略都失败,跳过这个虚拟面
|
|
|
|
// 如果两种策略都失败,跳过这个虚拟面
|
|
|
|
if (allOutOfRange) { |
|
|
|
if (allOutOfRange) { |
|
|
|
printf("[WARN] Both mapping strategies failed for pi=%d, vfID=%u\n", pi, vfID); |
|
|
|
// printf("[WARN] Both mapping strategies failed for pi=%d, vfID=%u\n", pi, vfID);
|
|
|
|
continue; |
|
|
|
continue; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@ -17905,6 +17905,63 @@ bool MeshTexture::SelectBestViewsForVirtualFaces( |
|
|
|
|
|
|
|
|
|
|
|
DEBUG_EXTRA("Selecting best views for %zu virtual faces", virtualFaceMap.size()); |
|
|
|
DEBUG_EXTRA("Selecting best views for %zu virtual faces", virtualFaceMap.size()); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// ---------- 准备禁用视图列表(禁用最后一个单独数字 = 最大值的【所有】相机) ----------
|
|
|
|
|
|
|
|
std::unordered_set<IIndex> disabledViews; |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
struct ViewDigitPair { |
|
|
|
|
|
|
|
IIndex idx; |
|
|
|
|
|
|
|
int digit; |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
std::vector<ViewDigitPair> viewDigits; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (IIndex idx = 0; idx < (IIndex)images.size(); ++idx) { |
|
|
|
|
|
|
|
const Image& img = images[idx]; |
|
|
|
|
|
|
|
if (!img.IsValid()) continue; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 提取文件名(不含路径和扩展名)
|
|
|
|
|
|
|
|
std::string path = img.name; |
|
|
|
|
|
|
|
size_t lastSlash = path.find_last_of("/\\"); |
|
|
|
|
|
|
|
size_t start = (lastSlash == std::string::npos) ? 0 : lastSlash + 1; |
|
|
|
|
|
|
|
size_t lastDot = path.find_last_of('.'); |
|
|
|
|
|
|
|
if (lastDot == std::string::npos) lastDot = path.size(); |
|
|
|
|
|
|
|
std::string strName = path.substr(start, lastDot - start); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 提取最后一个 _ 前面的最后一个数字字符
|
|
|
|
|
|
|
|
int digit = -1; |
|
|
|
|
|
|
|
size_t lastUnderscore = strName.find_last_of('_'); |
|
|
|
|
|
|
|
if (lastUnderscore != std::string::npos && lastUnderscore > 0) { |
|
|
|
|
|
|
|
for (size_t pos = lastUnderscore - 1; ; --pos) { |
|
|
|
|
|
|
|
if (std::isdigit(strName[pos])) { |
|
|
|
|
|
|
|
digit = strName[pos] - '0'; |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (pos == 0) break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (digit >= 0) { |
|
|
|
|
|
|
|
viewDigits.push_back({idx, digit}); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// ★ 找到最大的 digit 值
|
|
|
|
|
|
|
|
int maxDigit = -1; |
|
|
|
|
|
|
|
for (const auto& vd : viewDigits) { |
|
|
|
|
|
|
|
if (vd.digit > maxDigit) maxDigit = vd.digit; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// ★ 禁用【所有】digit == maxDigit 的视图(不再只禁前 N 个)
|
|
|
|
|
|
|
|
for (const auto& vd : viewDigits) { |
|
|
|
|
|
|
|
if (vd.digit == maxDigit) { |
|
|
|
|
|
|
|
disabledViews.insert(vd.idx); |
|
|
|
|
|
|
|
DEBUG_EXTRA("[DisabledView] idx=%d name=%s digit=%d (maxDigit=%d)", |
|
|
|
|
|
|
|
vd.idx, images[vd.idx].name.c_str(), vd.digit, maxDigit); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
DEBUG_EXTRA("[DisabledView] %zu views disabled (all with digit=%d)", |
|
|
|
|
|
|
|
disabledViews.size(), maxDigit); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// ---------- 初始化 ----------
|
|
|
|
// ---------- 初始化 ----------
|
|
|
|
faceViews.resize(virtualFaceMap.size()); |
|
|
|
faceViews.resize(virtualFaceMap.size()); |
|
|
|
faceViewWeights.resize(virtualFaceMap.size()); |
|
|
|
faceViewWeights.resize(virtualFaceMap.size()); |
|
|
|
@ -17968,6 +18025,20 @@ bool MeshTexture::SelectBestViewsForVirtualFaces( |
|
|
|
if (faceID >= faceNeighbors.size()) continue; |
|
|
|
if (faceID >= faceNeighbors.size()) continue; |
|
|
|
|
|
|
|
|
|
|
|
std::unordered_set<IIndex> candidateViews; |
|
|
|
std::unordered_set<IIndex> candidateViews; |
|
|
|
|
|
|
|
for (FIndex fid : vf.faces) { |
|
|
|
|
|
|
|
if (fid >= faceNeighbors.size()) continue; |
|
|
|
|
|
|
|
for (IIndex vid : faceNeighbors[fid]) { |
|
|
|
|
|
|
|
if (views.empty() || views.FindFirst(vid) != NO_ID) { |
|
|
|
|
|
|
|
// ★ 排除禁用视图(优先选择小数字的视图)
|
|
|
|
|
|
|
|
if (disabledViews.count(vid) == 0) { |
|
|
|
|
|
|
|
candidateViews.insert(vid); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// ★ 如果候选视图为空,放宽限制允许禁用视图参与
|
|
|
|
|
|
|
|
if (candidateViews.empty()) { |
|
|
|
for (FIndex fid : vf.faces) { |
|
|
|
for (FIndex fid : vf.faces) { |
|
|
|
if (fid >= faceNeighbors.size()) continue; |
|
|
|
if (fid >= faceNeighbors.size()) continue; |
|
|
|
for (IIndex vid : faceNeighbors[fid]) { |
|
|
|
for (IIndex vid : faceNeighbors[fid]) { |
|
|
|
@ -17976,6 +18047,9 @@ bool MeshTexture::SelectBestViewsForVirtualFaces( |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// DEBUG_EXTRA("[Fallback] pi=%zu: allowed disabled views, got %zu candidates",
|
|
|
|
|
|
|
|
// i, candidateViews.size());
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (candidateViews.empty()) { |
|
|
|
if (candidateViews.empty()) { |
|
|
|
++emptyCandidateViews; |
|
|
|
++emptyCandidateViews; |
|
|
|
|