|
|
|
|
@ -18717,99 +18717,82 @@ bool Scene::TextureMesh(unsigned nResolutionLevel, unsigned nMinResolution, unsi
@@ -18717,99 +18717,82 @@ bool Scene::TextureMesh(unsigned nResolutionLevel, unsigned nMinResolution, unsi
|
|
|
|
|
} |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
// assign the best view to each face
|
|
|
|
|
// ========== 视图选择总入口 ==========
|
|
|
|
|
{ |
|
|
|
|
TD_TIMER_STARTD(); |
|
|
|
|
if (bOriginFaceview) |
|
|
|
|
{ |
|
|
|
|
// 使用原始面片视图选择
|
|
|
|
|
if (bOriginFaceview) { |
|
|
|
|
// 1. 原始面片模式
|
|
|
|
|
if (!texture.FaceViewSelection(minCommonCameras, fOutlierThreshold, fRatioDataSmoothness, nIgnoreMaskLabel, views)) |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
if (bUseExistingUV && !strUVMeshFileName.empty()) { |
|
|
|
|
VERBOSE("1faceTexcoords.size=%d, faces.size=%d", mesh.faceTexcoords.size(), mesh.faces.size() * 3); |
|
|
|
|
// 使用预计算UV模式
|
|
|
|
|
if (!mesh.Load(MAKE_PATH_SAFE(strUVMeshFileName), true)) { |
|
|
|
|
VERBOSE("error: cannot load mesh file with UV coordinates"); |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 使用虚拟面优化策略
|
|
|
|
|
if (!texture.FaceViewSelectionWithVirtualFaces(minCommonCameras, fOutlierThreshold, fRatioDataSmoothness, nIgnoreMaskLabel, views, bUseExistingUV)) |
|
|
|
|
return false; |
|
|
|
|
} else if (bUseExistingUV && !strUVMeshFileName.empty()) { |
|
|
|
|
// 2. 已有UV专用模式(只走这里,不要后面的重复分支)
|
|
|
|
|
VERBOSE("faceTexcoords.size=%d, faces.size=%d", mesh.faceTexcoords.size(), mesh.faces.size() * 3); |
|
|
|
|
|
|
|
|
|
DEBUG_EXTRA("Virtual face view selection completed: %u faces (%s)", mesh.faces.size(), TD_TIMER_GET_FMT().c_str()); |
|
|
|
|
} |
|
|
|
|
DEBUG_EXTRA("Assigning the best view to each face completed: %u faces (%s)", mesh.faces.size(), TD_TIMER_GET_FMT().c_str()); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 检查UV有效性
|
|
|
|
|
// mesh.CheckUVValid();
|
|
|
|
|
|
|
|
|
|
DEBUG_EXTRA("TextureMesh bUseExistingUV=%d, UVMeshFile=%s", bUseExistingUV, strUVMeshFileName.c_str()); |
|
|
|
|
|
|
|
|
|
// 处理已有UV的情况
|
|
|
|
|
if (bUseExistingUV && !strUVMeshFileName.empty()) { |
|
|
|
|
MeshTexture texture(*this, nResolutionLevel, nMinResolution); |
|
|
|
|
// 加载带UV的mesh
|
|
|
|
|
if (!mesh.Load(MAKE_PATH_SAFE(strUVMeshFileName), true)) { |
|
|
|
|
VERBOSE("error: cannot load mesh file with UV coordinates"); |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// ✅ 只用“纯可见性”,绝不碰 FaceViewSelection
|
|
|
|
|
if (!texture.ComputePureFaceVisibility( |
|
|
|
|
fOutlierThreshold, |
|
|
|
|
nIgnoreMaskLabel, |
|
|
|
|
views)) { |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
// 纯可见性计算(初始化faceNeighbors)
|
|
|
|
|
if (!texture.ComputePureFaceVisibility(fOutlierThreshold, nIgnoreMaskLabel, views)) { |
|
|
|
|
// ❗ 兜底:如果ComputePureFaceVisibility没初始化faceNeighbors,手动填充
|
|
|
|
|
if (texture.faceNeighbors.empty()) { |
|
|
|
|
texture.faceNeighbors.resize(mesh.faces.size()); |
|
|
|
|
for (FIndex fid = 0; fid < (FIndex)mesh.faces.size(); ++fid) { |
|
|
|
|
if (!views.empty()) { |
|
|
|
|
texture.faceNeighbors[fid].insert(texture.faceNeighbors[fid].end(), views.begin(), views.end()); |
|
|
|
|
} else { |
|
|
|
|
for (IIndex vid = 0; vid < (IIndex)images.size(); ++vid) |
|
|
|
|
texture.faceNeighbors[fid].push_back(vid); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
DEBUG_EXTRA("Forced fill faceNeighbors for %zu faces", mesh.faces.size()); |
|
|
|
|
} |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// ✅ 现在 faces 没动过,faceNeighbors 是对齐的
|
|
|
|
|
MeshTexture::VirtualFaceMap virtualFaceMap; |
|
|
|
|
if (!texture.CreateVirtualFacesForExistingUV(virtualFaceMap)) { |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
// 创建虚拟面(1:1映射)
|
|
|
|
|
MeshTexture::VirtualFaceMap virtualFaceMap; |
|
|
|
|
if (!texture.CreateVirtualFacesForExistingUV(virtualFaceMap)) return false; |
|
|
|
|
|
|
|
|
|
if (!texture.SelectBestViewsForVirtualFaces( |
|
|
|
|
virtualFaceMap, |
|
|
|
|
1, // 单视图就够了
|
|
|
|
|
fOutlierThreshold, |
|
|
|
|
fRatioDataSmoothness, |
|
|
|
|
nIgnoreMaskLabel, |
|
|
|
|
views)) { |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
// 选最佳视图(带patch一致性)
|
|
|
|
|
if (!texture.SelectBestViewsForVirtualFaces( |
|
|
|
|
virtualFaceMap, 1, fOutlierThreshold, fRatioDataSmoothness, nIgnoreMaskLabel, views)) |
|
|
|
|
return false; |
|
|
|
|
|
|
|
|
|
// 直接光栅化
|
|
|
|
|
Mesh::Image8U3Arr textures; |
|
|
|
|
if (!texture.RasterizeVirtualFaces( |
|
|
|
|
virtualFaceMap, |
|
|
|
|
texture.faceViews, |
|
|
|
|
texture.faceViewWeights, |
|
|
|
|
nTextureSizeMultiple, |
|
|
|
|
colEmpty, |
|
|
|
|
textures)) { |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
// 直接光栅化(不需要生成图集)
|
|
|
|
|
Mesh::Image8U3Arr textures; |
|
|
|
|
if (!texture.RasterizeVirtualFaces( |
|
|
|
|
virtualFaceMap, texture.faceViews, texture.faceViewWeights, |
|
|
|
|
nTextureSizeMultiple, colEmpty, textures)) |
|
|
|
|
return false; |
|
|
|
|
|
|
|
|
|
mesh.texturesDiffuse = std::move(textures); |
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|
mesh.texturesDiffuse = std::move(textures); |
|
|
|
|
DEBUG_EXTRA("Existing UV texturing completed: %u faces (%s)", mesh.faces.size(), TD_TIMER_GET_FMT().c_str()); |
|
|
|
|
return true; // 直接返回,不走后面的图集逻辑
|
|
|
|
|
} else { |
|
|
|
|
// 3. 通用虚拟面模式(无预计算UV)
|
|
|
|
|
if (!texture.FaceViewSelectionWithVirtualFaces( |
|
|
|
|
minCommonCameras, fOutlierThreshold, fRatioDataSmoothness, |
|
|
|
|
nIgnoreMaskLabel, views, bUseExistingUV)) |
|
|
|
|
return false; |
|
|
|
|
DEBUG_EXTRA("Virtual face view selection completed: %u faces (%s)", mesh.faces.size(), TD_TIMER_GET_FMT().c_str()); |
|
|
|
|
} |
|
|
|
|
DEBUG_EXTRA("Assigning the best view to each face completed: %u faces (%s)", mesh.faces.size(), TD_TIMER_GET_FMT().c_str()); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// generate the texture image and atlas
|
|
|
|
|
// ========== 非UV模式:生成纹理图集 ==========
|
|
|
|
|
{ |
|
|
|
|
TD_TIMER_STARTD(); |
|
|
|
|
if (!texture.GenerateTextureWithVirtualFaces(bGlobalSeamLeveling, bLocalSeamLeveling, nTextureSizeMultiple, nRectPackingHeuristic, |
|
|
|
|
colEmpty, fSharpnessWeight, maxTextureSize, baseFileName, bOriginFaceview, this)) |
|
|
|
|
{ |
|
|
|
|
if (!texture.GenerateTextureWithVirtualFaces( |
|
|
|
|
bGlobalSeamLeveling, bLocalSeamLeveling, nTextureSizeMultiple, nRectPackingHeuristic, |
|
|
|
|
colEmpty, fSharpnessWeight, maxTextureSize, baseFileName, bOriginFaceview, this)) |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
DEBUG_EXTRA("Generating texture atlas and image completed: %u patches, %u image size, %u textures (%s)", |
|
|
|
|
texture.texturePatches.size(), mesh.texturesDiffuse[0].width(), mesh.texturesDiffuse.size(), TD_TIMER_GET_FMT().c_str()); |
|
|
|
|
DEBUG_EXTRA("Generating texture atlas completed: %u textures (%s)", |
|
|
|
|
mesh.texturesDiffuse.size(), TD_TIMER_GET_FMT().c_str()); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 最终UV检查
|
|
|
|
|
// mesh.CheckUVValid();
|
|
|
|
|
|
|
|
|
|
return true; |
|
|
|
|
} // TextureMesh
|
|
|
|
|
|
|
|
|
|
|