修正一些问题
This commit is contained in:
1 parent
1fb47e1afe
commit
1fe47d9448
1 file changed
+253
-198
+253
-198
@@ -606,7 +606,7 @@ public:
|
||||
bool FaceViewSelectionWithVirtualFaces(unsigned minCommonCameras, float fOutlierThreshold,
|
||||
float fRatioDataSmoothness, int nIgnoreMaskLabel,
|
||||
const IIndexArr& views, bool bUseExistingUV);
|
||||
|
||||
bool ComputePureFaceVisibility(float fOutlierThreshold, int nIgnoreMaskLabel, const IIndexArr& views);
|
||||
bool GenerateTextureWithVirtualFaces(bool bGlobalSeamLeveling, bool bLocalSeamLeveling,
|
||||
unsigned nTextureSizeMultiple, unsigned nRectPackingHeuristic,
|
||||
Pixel8U colEmpty, float fSharpnessWeight, int maxTextureSize,
|
||||
@@ -6948,7 +6948,7 @@ bool MeshTexture::FaceViewSelection3( unsigned minCommonCameras, float fOutlierT
|
||||
// printf("FaceViewSelection3 2 scene.mesh.vertices.size=%d\n", scene.mesh.vertices.size());
|
||||
|
||||
bool bUseVirtualFaces(minCommonCameras > 0);
|
||||
bUseVirtualFaces = false;
|
||||
// bUseVirtualFaces = false;
|
||||
|
||||
// list all views for each face
|
||||
FaceDataViewArr facesDatas;
|
||||
@@ -12784,7 +12784,7 @@ float MeshTexture::ComputeFaceDistance(FIndex fid1, FIndex fid2)
|
||||
Point3f diff = center2 - center1;
|
||||
return std::sqrt(diff.x * diff.x + diff.y * diff.y + diff.z * diff.z);
|
||||
}
|
||||
// 判断面是否在视图中可见
|
||||
|
||||
// 判断面是否在视图中可见
|
||||
bool MeshTexture::IsFaceVisibleFromView(FIndex idxFace, int viewID)
|
||||
{
|
||||
@@ -14073,6 +14073,14 @@ bool MeshTexture::RasterizeVirtualFaces(
|
||||
DEBUG_EXTRA("Forward Rasterization Engine: Starting...");
|
||||
TD_TIMER_START();
|
||||
|
||||
int totalVF = virtualFaceMap.size();
|
||||
int emptyVF = 0;
|
||||
for (auto& vf : virtualFaceViews)
|
||||
if (vf.empty()) ++emptyVF;
|
||||
|
||||
DEBUG_EXTRA("VirtualFaces: total=%d empty=%d (%.1f%%)",
|
||||
totalVF, emptyVF, 100.0f*emptyVF/totalVF);
|
||||
|
||||
if (virtualFaceMap.empty() || virtualFaceViews.size() != virtualFaceMap.size())
|
||||
return false;
|
||||
|
||||
@@ -14318,6 +14326,12 @@ bool MeshTexture::TextureWithExistingUVVirtualFaces(const IIndexArr& views, int
|
||||
DEBUG_EXTRA("Texture Pipeline: Steps 3-4 (View Selection + VirtualFace Mapping)");
|
||||
TD_TIMER_START();
|
||||
|
||||
// 不再重新选择视图!直接使用已有的 faceViews
|
||||
if (faceViews.empty()) {
|
||||
DEBUG_EXTRA("ERROR: faceViews is empty! Call FaceViewSelection first.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// 1. 验证输入
|
||||
if (scene.mesh.faceTexcoords.empty()) {
|
||||
VERBOSE("error: mesh does not contain UV coordinates");
|
||||
@@ -14348,74 +14362,8 @@ bool MeshTexture::TextureWithExistingUVVirtualFaces(const IIndexArr& views, int
|
||||
DEBUG_EXTRA("Step 4: Forced 1-to-1 mapping: %zu virtual faces for %zu original faces",
|
||||
virtualFaceMap.size(), numFaces);
|
||||
|
||||
// 4.2 为每个虚拟面收集视图数据(用于可见性判断)
|
||||
VirtualFaceDataArr virtualFaceDatas;
|
||||
if (!ListCameraVirtualFaces(virtualFaceMap, virtualFaceDatas, fOutlierThreshold, nIgnoreMaskLabel, views, false)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 4.3 单视图选择:为每个虚拟面选择最佳视图
|
||||
std::vector<std::vector<IIndex>> virtualFaceViews(virtualFaceMap.size());
|
||||
std::vector<std::vector<float>> virtualFaceViewWeights(virtualFaceMap.size());
|
||||
|
||||
size_t unassignedFaces = 0;
|
||||
|
||||
#ifdef _USE_OPENMP
|
||||
#pragma omp parallel for reduction(+:unassignedFaces) schedule(dynamic)
|
||||
#endif
|
||||
for (int_t idxVF = 0; idxVF < (int_t)virtualFaceMap.size(); ++idxVF) {
|
||||
const FIndex fid = virtualFaceMap[idxVF].faces[0];
|
||||
const FaceDataArr& vfDatas = virtualFaceDatas[idxVF];
|
||||
|
||||
float bestScore = -1.0f;
|
||||
IIndex bestViewID = IIndex(-1);
|
||||
|
||||
// 获取面片中心(用于计算距离和视角)
|
||||
const Face& face = scene.mesh.faces[fid];
|
||||
Point3f faceCenter = (scene.mesh.vertices[face[0]] +
|
||||
scene.mesh.vertices[face[1]] +
|
||||
scene.mesh.vertices[face[2]]) / 3.0f;
|
||||
|
||||
const Normal& faceNormal = scene.mesh.faceNormals[fid];
|
||||
|
||||
// 遍历能看到这个面片的所有相机
|
||||
for (const FaceData& data : vfDatas) {
|
||||
if (data.bInvalidFacesRelative) continue;
|
||||
|
||||
const Image& image = images[data.idxView];
|
||||
|
||||
// 使用综合评分函数
|
||||
float score = ComputeComprehensiveScore(data, faceNormal, faceCenter, image);
|
||||
|
||||
if (score > bestScore) {
|
||||
bestScore = score;
|
||||
bestViewID = data.idxView;
|
||||
}
|
||||
}
|
||||
|
||||
// 如果找到了有效的视图
|
||||
if (bestViewID != IIndex(-1) && bestScore > 0.1f) {
|
||||
virtualFaceViews[idxVF] = { bestViewID };
|
||||
virtualFaceViewWeights[idxVF] = { 1.0f }; // 单视图权重设为1
|
||||
} else {
|
||||
// virtualFaceViews[idxVF].clear();
|
||||
// virtualFaceViewWeights[idxVF].clear();
|
||||
// ++unassignedFaces;
|
||||
|
||||
float bestQuality = -1.0f;
|
||||
for (const FaceData& data : vfDatas) {
|
||||
if (data.quality > bestQuality) {
|
||||
bestQuality = data.quality;
|
||||
bestViewID = data.idxView;
|
||||
bestScore = data.quality;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DEBUG_EXTRA("Step 3-4 completed: %zu faces processed, %zu unassigned",
|
||||
numFaces, unassignedFaces);
|
||||
DEBUG_EXTRA("Proceeding to Step 5: Forward Rasterization");
|
||||
std::vector<std::vector<IIndex>> virtualFaceViews = faceViews;
|
||||
std::vector<std::vector<float>> virtualFaceViewWeights = faceViewWeights;
|
||||
|
||||
// ==========================================================
|
||||
// 步骤5:正向光栅化引擎
|
||||
@@ -14469,39 +14417,84 @@ bool MeshTexture::TextureWithExistingUVVirtualFaces(const IIndexArr& views, int
|
||||
|
||||
return true;
|
||||
}
|
||||
DEBUG_EXTRA("Unassigned faces: %zu / %zu", unassignedFaces, numFaces);
|
||||
// DEBUG_EXTRA("Unassigned faces: %zu / %zu", unassignedFaces, numFaces);
|
||||
DEBUG_EXTRA("Texture generation failed in stable mode");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MeshTexture::FaceViewSelectionWithVirtualFaces(unsigned minCommonCameras, float fOutlierThreshold,
|
||||
float fRatioDataSmoothness, int nIgnoreMaskLabel,
|
||||
const IIndexArr& views, bool bUseExistingUV)
|
||||
bool MeshTexture::FaceViewSelectionWithVirtualFaces(
|
||||
unsigned minCommonCameras,
|
||||
float fOutlierThreshold,
|
||||
float fRatioDataSmoothness,
|
||||
int nIgnoreMaskLabel,
|
||||
const IIndexArr& views,
|
||||
bool bUseExistingUV)
|
||||
{
|
||||
DEBUG_EXTRA("Performing face view selection with virtual faces (bUseExistingUV=%d)", bUseExistingUV);
|
||||
|
||||
|
||||
if (faceNeighbors.empty()) {
|
||||
DEBUG_EXTRA("Initializing faceNeighbors via ComputePureFaceVisibility...");
|
||||
if (!ComputePureFaceVisibility(fOutlierThreshold, nIgnoreMaskLabel, views)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (bUseExistingUV) {
|
||||
// 使用现有UV的虚拟面选择策略
|
||||
VirtualFaceMap virtualFaceMap;
|
||||
if (!CreateVirtualFacesForExistingUV(virtualFaceMap)) {
|
||||
DEBUG_EXTRA("Failed to create virtual faces for existing UV");
|
||||
return false;
|
||||
}
|
||||
|
||||
DEBUG_EXTRA("Created %zu virtual faces", virtualFaceMap.size());
|
||||
|
||||
// 为虚拟面选择最佳视图
|
||||
if (!SelectBestViewsForVirtualFaces(virtualFaceMap, minCommonCameras, fOutlierThreshold,
|
||||
fRatioDataSmoothness, nIgnoreMaskLabel, views)) {
|
||||
DEBUG_EXTRA("Failed to select best views for virtual faces");
|
||||
|
||||
if (!SelectBestViewsForVirtualFaces(
|
||||
virtualFaceMap, minCommonCameras, fOutlierThreshold,
|
||||
fRatioDataSmoothness, nIgnoreMaskLabel, views)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
} else {
|
||||
// 使用原始面片的虚拟面选择
|
||||
return FaceViewSelection(minCommonCameras, fOutlierThreshold, fRatioDataSmoothness, nIgnoreMaskLabel, views);
|
||||
}
|
||||
|
||||
// 非 UV 模式:走原生流程
|
||||
return FaceViewSelection(minCommonCameras, fOutlierThreshold,
|
||||
fRatioDataSmoothness, nIgnoreMaskLabel, views);
|
||||
}
|
||||
|
||||
bool MeshTexture::ComputePureFaceVisibility(
|
||||
float fOutlierThreshold,
|
||||
int nIgnoreMaskLabel,
|
||||
const IIndexArr& views)
|
||||
{
|
||||
DEBUG_EXTRA("Computing face visibility via ListCameraFaces (UV-safe)");
|
||||
|
||||
// 1. 调用 openMVS 原生的可见性计算
|
||||
FaceDataViewArr facesDatas;
|
||||
const bool bUseVirtualFaces = false; // ✅ 关键:禁用虚拟面,保持 1:1 映射
|
||||
|
||||
if (!ListCameraFaces(facesDatas, fOutlierThreshold, nIgnoreMaskLabel, views, bUseVirtualFaces)) {
|
||||
DEBUG_EXTRA("ERROR: ListCameraFaces failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
// 2. 从 facesDatas 中提取 faceNeighbors
|
||||
// facesDatas[i] 是第 i 个面的候选视图数组(FaceDataArr)
|
||||
// 每个 FaceData 有 .idxView 成员
|
||||
faceNeighbors.resize(facesDatas.size());
|
||||
for (size_t i = 0; i < facesDatas.size(); ++i) {
|
||||
faceNeighbors[i].clear();
|
||||
for (const FaceData& fd : facesDatas[i]) {
|
||||
faceNeighbors[i].push_back(fd.idxView);
|
||||
}
|
||||
}
|
||||
|
||||
// 3. 统计
|
||||
size_t visibleFaces = 0;
|
||||
for (const auto& v : faceNeighbors)
|
||||
if (!v.empty())
|
||||
++visibleFaces;
|
||||
|
||||
DEBUG_EXTRA("Visibility done: %zu/%zu faces have views",
|
||||
visibleFaces, facesDatas.size());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MeshTexture::GenerateTextureWithVirtualFaces(bool bGlobalSeamLeveling, bool bLocalSeamLeveling,
|
||||
@@ -14533,115 +14526,158 @@ bool MeshTexture::SelectBestViewsForVirtualFaces(VirtualFaceMap& virtualFaceMap,
|
||||
const IIndexArr& views)
|
||||
{
|
||||
DEBUG_EXTRA("Selecting best views for %zu virtual faces", virtualFaceMap.size());
|
||||
|
||||
// 为每个虚拟面计算最佳视图
|
||||
|
||||
faceViews.resize(virtualFaceMap.size());
|
||||
faceViewWeights.resize(virtualFaceMap.size());
|
||||
|
||||
// 检查 m_virtualFaceGeometries 是否已初始化
|
||||
if (m_virtualFaceGeometries.empty()) {
|
||||
m_virtualFaceGeometries.Resize(virtualFaceMap.size());
|
||||
} else if (m_virtualFaceGeometries.size() < virtualFaceMap.size()) {
|
||||
|
||||
if (m_virtualFaceGeometries.empty() ||
|
||||
m_virtualFaceGeometries.size() < virtualFaceMap.size()) {
|
||||
m_virtualFaceGeometries.Resize(virtualFaceMap.size());
|
||||
}
|
||||
|
||||
// 初始化每个虚拟面的视图数据数组
|
||||
for (auto& viewList : faceViews) {
|
||||
|
||||
for (auto& viewList : faceViews)
|
||||
viewList.clear();
|
||||
}
|
||||
for (auto& weightList : faceViewWeights) {
|
||||
for (auto& weightList : faceViewWeights)
|
||||
weightList.clear();
|
||||
}
|
||||
|
||||
|
||||
// ===== Debug 统计 =====
|
||||
size_t emptyCandidateViews = 0;
|
||||
size_t emptyCommonViews = 0;
|
||||
size_t fallbackByCenterFace = 0;
|
||||
size_t successVF = 0;
|
||||
|
||||
for (size_t i = 0; i < virtualFaceMap.size(); ++i) {
|
||||
const VirtualFace& vf = virtualFaceMap[i];
|
||||
|
||||
// 收集所有相关视图
|
||||
FIndex faceID2 = vf.faces[0];
|
||||
|
||||
if (faceID2 >= faceNeighbors.size()) {
|
||||
DEBUG_EXTRA("FATAL: faceID %u out of range!", faceID2);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (faceNeighbors[faceID2].empty()) {
|
||||
DEBUG_EXTRA("FATAL: faceNeighbors[%u] is empty! FaceViewSelection mode error.", faceID2);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// 1. 收集每个面片的候选视图
|
||||
//------------------------------------------------------------------
|
||||
std::unordered_set<IIndex> candidateViews;
|
||||
std::vector<std::vector<IIndex>> faceViewCandidates(vf.faces.size());
|
||||
|
||||
|
||||
for (size_t j = 0; j < vf.faces.size(); ++j) {
|
||||
FIndex faceID = vf.faces[j];
|
||||
if (faceID < faceNeighbors.size()) {
|
||||
for (size_t k = 0; k < faceNeighbors[faceID].size(); ++k) {
|
||||
IIndex viewID = faceNeighbors[faceID][k];
|
||||
if (views.empty() || views.FindFirst(viewID) != NO_ID) {
|
||||
candidateViews.insert(viewID);
|
||||
faceViewCandidates[j].push_back(viewID);
|
||||
}
|
||||
if (faceID >= faceNeighbors.size())
|
||||
continue;
|
||||
|
||||
for (IIndex viewID : faceNeighbors[faceID]) {
|
||||
if (views.empty() || views.FindFirst(viewID) != NO_ID) {
|
||||
candidateViews.insert(viewID);
|
||||
faceViewCandidates[j].push_back(viewID);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 如果候选视图为空,跳过这个虚拟面
|
||||
if (candidateViews.empty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 找到所有虚拟面都可见的视图
|
||||
std::vector<IIndex> commonViews;
|
||||
for (IIndex viewID : candidateViews) {
|
||||
bool allFacesVisible = true;
|
||||
for (size_t j = 0; j < vf.faces.size() && allFacesVisible; ++j) {
|
||||
if (std::find(faceViewCandidates[j].begin(), faceViewCandidates[j].end(), viewID) == faceViewCandidates[j].end()) {
|
||||
allFacesVisible = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (allFacesVisible) {
|
||||
commonViews.push_back(viewID);
|
||||
}
|
||||
}
|
||||
|
||||
// 如果共同视图太少,使用所有候选视图
|
||||
if (commonViews.size() < minCommonCameras) {
|
||||
// 将所有候选视图转换为vector
|
||||
faceViews[i].assign(candidateViews.begin(), candidateViews.end());
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// 2. 【终极兜底】候选视图为空 → 强制分配一个视图
|
||||
// 物理遮挡不重要,逻辑可见性最重要
|
||||
//------------------------------------------------------------------
|
||||
if (candidateViews.empty()) {
|
||||
++emptyCandidateViews;
|
||||
|
||||
// 找一个可用的相机ID
|
||||
// 优先级:views参数指定的 > 所有images中的第一个
|
||||
IIndex forcedView = NO_ID;
|
||||
|
||||
if (!views.empty()) {
|
||||
forcedView = views[0];
|
||||
} else if (!images.empty()) {
|
||||
forcedView = 0;
|
||||
}
|
||||
|
||||
if (forcedView != NO_ID) {
|
||||
faceViews[i].push_back(forcedView);
|
||||
faceViewWeights[i].push_back(1.0f);
|
||||
++fallbackByCenterFace;
|
||||
|
||||
// 降低日志级别,避免刷屏,用 DEBUG 而非 EXTRA
|
||||
DEBUG("VF[%zu] EMPTY -> FORCED view %d (ignoring physical occlusion)",
|
||||
i, forcedView);
|
||||
continue;
|
||||
}
|
||||
|
||||
// 实在没救(连images都没有),这才跳过
|
||||
DEBUG_EXTRA("VF[%zu] truly hopeless: no images available", i);
|
||||
continue;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// 3. 【关键放松】不再强求“所有面片共视”
|
||||
// 只要视图能看到任意一个面片即可
|
||||
//------------------------------------------------------------------
|
||||
std::vector<IIndex> usableViews(
|
||||
candidateViews.begin(), candidateViews.end()
|
||||
);
|
||||
|
||||
// (可选)按质量排序,取前 N 个
|
||||
// std::sort(usableViews.begin(), usableViews.end(),
|
||||
// [&](IIndex a, IIndex b) { return Quality(a) > Quality(b); });
|
||||
|
||||
if (usableViews.size() < minCommonCameras) {
|
||||
faceViews[i] = usableViews;
|
||||
} else {
|
||||
// 使用共同视图
|
||||
faceViews[i] = commonViews;
|
||||
// 仍尊重 minCommonCameras,但不强求共视
|
||||
faceViews[i].assign(
|
||||
usableViews.begin(),
|
||||
usableViews.begin() + minCommonCameras
|
||||
);
|
||||
}
|
||||
|
||||
// 如果仍然没有视图,则跳过
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// 4. 【二次兜底】usableViews 为空(理论上不会发生)
|
||||
//------------------------------------------------------------------
|
||||
if (faceViews[i].empty()) {
|
||||
++emptyCommonViews;
|
||||
|
||||
if (!vf.faces.empty()) {
|
||||
FIndex centerFace = vf.faces[0];
|
||||
if (centerFace < faceNeighbors.size() &&
|
||||
!faceNeighbors[centerFace].empty()) {
|
||||
|
||||
IIndex bestView = faceNeighbors[centerFace][0];
|
||||
faceViews[i].push_back(bestView);
|
||||
faceViewWeights[i].push_back(1.0f);
|
||||
|
||||
DEBUG_EXTRA("VF[%zu] empty usableViews -> force view %d",
|
||||
i, bestView);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// 分配相等的权重
|
||||
float weight = 1.0f / faceViews[i].size();
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// 5. 权重分配(均等,最稳定)
|
||||
//------------------------------------------------------------------
|
||||
float weight = 1.0f / static_cast<float>(faceViews[i].size());
|
||||
faceViewWeights[i].resize(faceViews[i].size(), weight);
|
||||
|
||||
// 计算每个视图的质量
|
||||
for (size_t k = 0; k < faceViews[i].size(); ++k) {
|
||||
IIndex viewID = faceViews[i][k];
|
||||
|
||||
// 创建FaceData
|
||||
FaceData faceData;
|
||||
faceData.idxView = viewID;
|
||||
faceData.quality = weight; // 使用权重作为质量
|
||||
|
||||
#if TEXOPT_FACEOUTLIER != TEXOPT_FACEOUTLIER_NA
|
||||
// 可以在这里计算和设置颜色
|
||||
// 例如:faceData.color = CalculateMeanColor(viewID, vf);
|
||||
#endif
|
||||
|
||||
faceData.bInvalidFacesRelative = false;
|
||||
|
||||
// 注意:m_virtualFaceGeometries 存储的是几何信息,不是视图数据
|
||||
// 如果您需要存储视图数据,可以:
|
||||
// 1. 创建单独的成员变量
|
||||
// 2. 扩展 VirtualFaceGeometryData
|
||||
// 3. 使用 faceViews 和 faceViewWeights
|
||||
}
|
||||
|
||||
#if TEXOPT_FACEOUTLIER != TEXOPT_FACEOUTLIER_NA
|
||||
if (fOutlierThreshold > 0) {
|
||||
// DetectAndRemoveOutliers(...);
|
||||
}
|
||||
#endif
|
||||
|
||||
++successVF;
|
||||
}
|
||||
|
||||
DEBUG_EXTRA("Best view selection completed for %zu virtual faces", virtualFaceMap.size());
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// 6. Debug 汇总(非常重要)
|
||||
//--------------------------------------------------------------------------
|
||||
DEBUG_EXTRA("====== Virtual Face View Selection Summary ======");
|
||||
DEBUG_EXTRA("Total virtual faces : %zu", virtualFaceMap.size());
|
||||
DEBUG_EXTRA("Successfully assigned : %zu", successVF);
|
||||
DEBUG_EXTRA("Empty candidates : %zu", emptyCandidateViews);
|
||||
DEBUG_EXTRA("Fallback by center face : %zu", fallbackByCenterFace);
|
||||
DEBUG_EXTRA("Empty after relaxation : %zu", emptyCommonViews);
|
||||
DEBUG_EXTRA("Expected empty ratio : %.2f%%",
|
||||
100.0 * (emptyCandidateViews - fallbackByCenterFace) / virtualFaceMap.size());
|
||||
DEBUG_EXTRA("=================================================");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -18633,29 +18669,48 @@ bool Scene::TextureMesh(unsigned nResolutionLevel, unsigned nMinResolution, unsi
|
||||
DEBUG_EXTRA("TextureMesh bUseExistingUV=%d, UVMeshFile=%s", bUseExistingUV, strUVMeshFileName.c_str());
|
||||
|
||||
// 处理已有UV的情况
|
||||
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;
|
||||
// }
|
||||
|
||||
VERBOSE("2faceTexcoords.size=%d, faces.size=%d", mesh.faceTexcoords.size(), mesh.faces.size() * 3);
|
||||
// mesh.CheckUVValid();
|
||||
|
||||
// 确保网格包含UV坐标
|
||||
if (mesh.faceTexcoords.empty()) {
|
||||
VERBOSE("error: the specified mesh does not contain UV coordinates");
|
||||
return false;
|
||||
}
|
||||
if (bUseExistingUV && !strUVMeshFileName.empty()) {
|
||||
MeshTexture texture(*this, nResolutionLevel, nMinResolution);
|
||||
|
||||
// 使用虚拟面优化的纹理生成
|
||||
if (!texture.TextureWithExistingUVVirtualFaces(views, nIgnoreMaskLabel, fOutlierThreshold, nTextureSizeMultiple, colEmpty, fSharpnessWeight)){
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
// ✅ 只用“纯可见性”,绝不碰 FaceViewSelection
|
||||
if (!texture.ComputePureFaceVisibility(
|
||||
fOutlierThreshold,
|
||||
nIgnoreMaskLabel,
|
||||
views)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// ✅ 现在 faces 没动过,faceNeighbors 是对齐的
|
||||
MeshTexture::VirtualFaceMap virtualFaceMap;
|
||||
if (!texture.CreateVirtualFacesForExistingUV(virtualFaceMap)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
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.texturesDiffuse = std::move(textures);
|
||||
return true;
|
||||
}
|
||||
|
||||
// generate the texture image and atlas
|
||||
{
|
||||
|
||||
Reference in new issue
Block a user