Browse Source

合并小三角形

ManualUV
hesuicong 1 week ago
parent
commit
e208883638
  1. 800
      libs/MVS/SceneTexture.cpp

800
libs/MVS/SceneTexture.cpp

@ -539,6 +539,14 @@ struct MeshTexture { @@ -539,6 +539,14 @@ struct MeshTexture {
}
};
struct VirtualFaceGeometry {
Point3f center; // 面片中心(世界坐标)
Point3f normal; // 面片法线
AABB2f uvBounds; // UV 包围盒
cv::Mat1f homography; // 3x3 单应矩阵(从 UV 到视图)
bool isValid = false;
};
// used to interpolate adjustments color over the whole texture patch
typedef TImage<Color> ColorMap;
@ -550,6 +558,7 @@ struct MeshTexture { @@ -550,6 +558,7 @@ struct MeshTexture {
: r(_r), g(_g), b(_b), a(_a) {}
};
*/
std::vector<VirtualFaceGeometry> m_virtualFaceGeometries;
public:
MeshTexture(Scene& _scene, unsigned _nResolutionLevel=0, unsigned _nMinResolution=640);
@ -621,12 +630,20 @@ public: @@ -621,12 +630,20 @@ public:
unsigned minCommonCameras, float fOutlierThreshold,
float fRatioDataSmoothness, int nIgnoreMaskLabel,
const IIndexArr& views);
bool ComputeVirtualFaceGeometry(const VirtualFaceMap& virtualFaceMap);
bool ComputeHomographyForVirtualFace(
const VirtualFace& vf,
IIndex viewID,
VirtualFaceGeometry& geom);
std::vector<std::vector<IIndex>> faceViews;
std::vector<std::vector<float>> faceViewWeights;
std::vector<VirtualFaceData> virtualFaceDatas;
std::vector<std::vector<IIndex>> faceNeighbors;
VirtualFaceGeometryArr m_virtualFaceGeometries;
// VirtualFaceGeometryArr m_virtualFaceGeometries;
inline Point3f NormalizePoint3(Point3f& p)
{
@ -14161,6 +14178,9 @@ void MeshTexture::FillTextureHoles(std::vector<Image8U3>& textures, Pixel8U colE @@ -14161,6 +14178,9 @@ void MeshTexture::FillTextureHoles(std::vector<Image8U3>& textures, Pixel8U colE
DEBUG_EXTRA("Hole filling completed");
}
// ============================================================
// 3. RC 风格光栅化主函数
// ============================================================
bool MeshTexture::RasterizeVirtualFaces(
const VirtualFaceMap& virtualFaceMap,
const std::vector<std::vector<IIndex>>& virtualFaceViews,
@ -14169,7 +14189,7 @@ bool MeshTexture::RasterizeVirtualFaces( @@ -14169,7 +14189,7 @@ bool MeshTexture::RasterizeVirtualFaces(
Pixel8U colEmpty,
Mesh::Image8U3Arr& outTextures)
{
DEBUG_EXTRA("Forward Rasterization Engine: Starting...");
DEBUG_EXTRA("RC-style Rasterization Engine: Starting...");
TD_TIMER_START();
if (virtualFaceMap.empty() || virtualFaceViews.size() != virtualFaceMap.size())
@ -14190,162 +14210,109 @@ bool MeshTexture::RasterizeVirtualFaces( @@ -14190,162 +14210,109 @@ bool MeshTexture::RasterizeVirtualFaces(
int textureSize = ComputeOptimalTextureSize(uvWidth, uvHeight, nTextureSizeMultiple);
// --------------------------------------------------
// 2. 创建纹理与缓冲器
// 2. 创建纹理
// --------------------------------------------------
outTextures.emplace_back(textureSize, textureSize);
Image8U3& atlas = outTextures.back();
atlas.setTo(cv::Scalar(colEmpty.b, colEmpty.g, colEmpty.r));
// ✅ 深度缓冲器初始化为正无穷(越小越近)
cv::Mat1f depthBuffer(textureSize, textureSize, FLT_MAX);
cv::Mat3f colorBuffer(textureSize, textureSize, cv::Vec3f(0.f, 0.f, 0.f));
cv::Mat1b validBuffer(textureSize, textureSize, (uchar)0);
// ✅ 计算所有虚拟面的几何和映射矩阵
if (!ComputeVirtualFaceGeometry(virtualFaceMap)) {
DEBUG_EXTRA("Failed to compute virtual face geometries");
return false;
}
// --------------------------------------------------
// 3. 正向光栅化主循环
// 3. RC 风格光栅化:按虚拟面批量处理
// --------------------------------------------------
#ifdef _USE_OPENMP
#pragma omp parallel for schedule(dynamic)
#endif
for (int_t idxVF = 0; idxVF < (int_t)virtualFaceMap.size(); ++idxVF) {
if (virtualFaceViews[idxVF].empty())
for (int i = 0; i < (int)virtualFaceMap.size(); ++i) {
const VirtualFace& vf = virtualFaceMap[i];
const VirtualFaceGeometry& geom = m_virtualFaceGeometries[i];
if (!geom.isValid || vf.faces.empty() || virtualFaceViews[i].empty())
continue;
const IIndex viewID = virtualFaceViews[idxVF][0];
IIndex viewID = virtualFaceViews[i][0];
if (viewID >= (IIndex)images.size()) continue;
const Image& srcImg = images[viewID];
if (srcImg.image.empty() || srcImg.image.cols < 2 || srcImg.image.rows < 2)
continue;
const Camera& cam = srcImg.camera;
const int srcW = srcImg.image.cols;
const int srcH = srcImg.image.rows;
for (FIndex faceID : virtualFaceMap[idxVF].faces) {
if (faceID >= (FIndex)scene.mesh.faces.size()) continue;
const Face& face = scene.mesh.faces[faceID];
const TexCoord* uv = &scene.mesh.faceTexcoords[faceID * 3];
// 验证顶点索引
bool validIndices = true;
for (int i = 0; i < 3; ++i) {
if (face[i] >= scene.mesh.vertices.size()) {
validIndices = false;
break;
}
}
if (!validIndices) continue;
const Point3f* verts[3] = {
&scene.mesh.vertices[face[0]],
&scene.mesh.vertices[face[1]],
&scene.mesh.vertices[face[2]]
};
// ✅ UV 包围盒 → 纹理像素范围
int minX = std::max(0, (int)floor(geom.uvBounds.ptMin.x() * textureSize));
int maxX = std::min(textureSize - 1, (int)ceil(geom.uvBounds.ptMax.x() * textureSize));
int minY = std::max(0, (int)floor(geom.uvBounds.ptMin.y() * textureSize));
int maxY = std::min(textureSize - 1, (int)ceil(geom.uvBounds.ptMax.y() * textureSize));
// 计算包围盒
float minU = std::min({uv[0].x, uv[1].x, uv[2].x});
float maxU = std::max({uv[0].x, uv[1].x, uv[2].x});
float minV = std::min({uv[0].y, uv[1].y, uv[2].y});
float maxV = std::max({uv[0].y, uv[1].y, uv[2].y});
int minX = std::max(0, (int)floor(minU * textureSize));
int maxX = std::min(textureSize - 1, (int)ceil(maxU * textureSize));
int minY = std::max(0, (int)floor(minV * textureSize));
int maxY = std::min(textureSize - 1, (int)ceil(maxV * textureSize));
if (minX > maxX || minY > maxY) continue;
if (minX > maxX || minY > maxY) continue;
// ✅ 预计算顶点深度(用于透视校正)
float vertexDepths[3];
for (int i = 0; i < 3; ++i) {
vertexDepths[i] = cam.PointDepth(*verts[i]);
if (vertexDepths[i] <= 0.0f) {
validIndices = false;
break;
int patchW = maxX - minX + 1;
int patchH = maxY - minY + 1;
// ✅ 映射矩阵
cv::Mat mapX(patchH, patchW, CV_32FC1);
cv::Mat mapY(patchH, patchW, CV_32FC1);
// ✅ 直接展开 H 系数(无临时 Mat,RC 标准写法)
const float* H = geom.homography.ptr<float>();
for (int y = minY; y <= maxY; ++y) {
for (int x = minX; x <= maxX; ++x) {
float u = (float)x / (float)textureSize;
float v = (float)y / (float)textureSize;
float w = H[6] * u + H[7] * v + H[8];
// ✅ 数值保护(防止除零)
if (std::abs(w) < 1e-12f) {
mapX.at<float>(y - minY, x - minX) = -1.0f;
mapY.at<float>(y - minY, x - minX) = -1.0f;
continue;
}
}
if (!validIndices) continue;
for (int y = minY; y <= maxY; ++y) {
for (int x = minX; x <= maxX; ++x) {
Point2f texCoord(
(x + 0.5f) / textureSize,
(y + 0.5f) / textureSize
);
float imgX = (H[0] * u + H[1] * v + H[2]) / w;
float imgY = (H[3] * u + H[4] * v + H[5]) / w;
Point3f bary;
if (!PointInTriangle(texCoord, uv[0], uv[1], uv[2], bary))
continue;
mapX.at<float>(y - minY, x - minX) = imgX;
mapY.at<float>(y - minY, x - minX) = imgY;
}
}
// ✅ 透视校正插值(double 精度)
double invZ = bary.x / vertexDepths[0] +
bary.y / vertexDepths[1] +
bary.z / vertexDepths[2];
if (invZ <= 0.0) continue;
// ✅ 校正后的重心坐标
double u0 = (bary.x / vertexDepths[0]) / invZ;
double u1 = (bary.y / vertexDepths[1]) / invZ;
double u2 = (bary.z / vertexDepths[2]) / invZ;
// ✅ 透视校正的世界坐标(double)
Point3d P_double(
verts[0]->x * u0 + verts[1]->x * u1 + verts[2]->x * u2,
verts[0]->y * u0 + verts[1]->y * u1 + verts[2]->y * u2,
verts[0]->z * u0 + verts[1]->z * u1 + verts[2]->z * u2
);
// ✅ 正确的投影(double → float)
Point2d imgPtDouble = cam.ProjectPoint(P_double);
Point2f imgPt(static_cast<float>(imgPtDouble.x),
static_cast<float>(imgPtDouble.y));
// ✅ 边界检查
if (imgPt.x < 0.5f || imgPt.y < 0.5f ||
imgPt.x >= srcW - 0.5f || imgPt.y >= srcH - 0.5f)
continue;
// ✅ 一次性 remap 整个 patch
cv::Mat patch;
cv::remap(srcImg.image, patch, mapX, mapY,
cv::INTER_LINEAR, cv::BORDER_CONSTANT,
cv::Scalar(0, 0, 0));
// ✅ 双线性采样
Color color = BilinearSample(srcImg.image, imgPt);
if (color[0] < 0 || color[1] < 0 || color[2] < 0) continue;
// ✅ 拷贝到 atlas(OpenMP critical 区)
#pragma omp critical
{
for (int y = 0; y < patchH; ++y) {
for (int x = 0; x < patchW; ++x) {
cv::Vec3b color = patch.at<cv::Vec3b>(y, x);
// 跳过无效像素(BORDER_CONSTANT 产生的黑色)
if (color[0] == 0 && color[1] == 0 && color[2] == 0)
continue;
// ✅ 深度测试(float 缓冲,double 比较)
float depthFloat = static_cast<float>(1.0 / invZ);
int atlasX = x + minX;
int atlasY = y + minY;
#pragma omp critical
{
if (depthFloat < depthBuffer(y, x)) {
depthBuffer(y, x) = depthFloat;
colorBuffer(y, x) = cv::Vec3f(
color[0], color[1], color[2]
);
validBuffer(y, x) = 1;
}
}
}
}
}
}
// ✅ 边界保护
if (atlasX < 0 || atlasX >= textureSize ||
atlasY < 0 || atlasY >= textureSize)
continue;
// --------------------------------------------------
// 4. 最终写入纹理
// --------------------------------------------------
for (int y = 0; y < textureSize; ++y) {
for (int x = 0; x < textureSize; ++x) {
if (validBuffer(y, x)) {
cv::Vec3f c = colorBuffer(y, x);
atlas(y, x) = Pixel8U{
(unsigned char)cv::saturate_cast<uchar>(c[0]),
(unsigned char)cv::saturate_cast<uchar>(c[1]),
(unsigned char)cv::saturate_cast<uchar>(c[2])
};
atlas(atlasY, atlasX) = Pixel8U{color[2], color[1], color[0]};
}
}
}
}
DEBUG_EXTRA("Forward Rasterization completed: %s", TD_TIMER_GET_FMT().c_str());
DEBUG_EXTRA("RC-style Rasterization completed: %s", TD_TIMER_GET_FMT().c_str());
return true;
}
@ -14639,92 +14606,76 @@ bool MeshTexture::GenerateTextureWithVirtualFaces(bool bGlobalSeamLeveling, bool @@ -14639,92 +14606,76 @@ bool MeshTexture::GenerateTextureWithVirtualFaces(bool bGlobalSeamLeveling, bool
}
}
bool MeshTexture::SelectBestViewsForVirtualFaces(VirtualFaceMap& virtualFaceMap,
unsigned minCommonCameras, float fOutlierThreshold,
float fRatioDataSmoothness, int nIgnoreMaskLabel,
const IIndexArr& views)
// ============================================================
// 5. SelectBestViewsForVirtualFaces(带 patch 一致性传播)
// ============================================================
bool MeshTexture::SelectBestViewsForVirtualFaces(
VirtualFaceMap& virtualFaceMap,
unsigned minCommonCameras, float fOutlierThreshold,
float fRatioDataSmoothness, int nIgnoreMaskLabel,
const IIndexArr& views)
{
DEBUG_EXTRA("Selecting best views for %zu virtual faces", virtualFaceMap.size());
faceViews.resize(virtualFaceMap.size());
faceViewWeights.resize(virtualFaceMap.size());
if (m_virtualFaceGeometries.empty() ||
m_virtualFaceGeometries.size() < virtualFaceMap.size()) {
m_virtualFaceGeometries.Resize(virtualFaceMap.size());
for (auto& v : faceViews) v.clear();
for (auto& w : faceViewWeights) w.clear();
// 确保 faceNeighbors 已填充
if (faceNeighbors.empty()) {
DEBUG_EXTRA("faceNeighbors empty, running ComputePureFaceVisibility first");
if (!ComputePureFaceVisibility(fOutlierThreshold, nIgnoreMaskLabel, views)) {
return false;
}
}
for (auto& viewList : faceViews) viewList.clear();
for (auto& weightList : faceViewWeights) weightList.clear();
// faceToView 映射
std::vector<IIndex> faceToView(scene.mesh.faces.size(), NO_ID);
// ===== Debug 统计 =====
// ---------- 1. 初始视图分配 ----------
size_t emptyCandidateViews = 0;
size_t emptyCommonViews = 0;
size_t fallbackByCenterFace = 0;
size_t successVF = 0;
// ✅ 面片 → 视图 映射表
std::vector<IIndex> faceToView(scene.mesh.faces.size(), NO_ID);
// ----------------------------------------------------------------
// 1. 初始视图分配
// ----------------------------------------------------------------
for (size_t i = 0; i < virtualFaceMap.size(); ++i) {
const VirtualFace& vf = virtualFaceMap[i];
if (vf.faces.empty()) continue;
FIndex faceID2 = vf.faces[0];
if (faceID2 >= faceNeighbors.size()) {
DEBUG_EXTRA("FATAL: faceID %u out of range!", faceID2);
continue;
}
FIndex faceID = vf.faces[0];
if (faceID >= faceNeighbors.size()) continue;
// 收集候选视图
std::unordered_set<IIndex> candidateViews;
for (FIndex faceID : vf.faces) {
if (faceID >= faceNeighbors.size()) continue;
for (IIndex viewID : faceNeighbors[faceID]) {
if (views.empty() || views.FindFirst(viewID) != NO_ID) {
candidateViews.insert(viewID);
for (FIndex fid : vf.faces) {
if (fid >= faceNeighbors.size()) continue;
for (IIndex vid : faceNeighbors[fid]) {
if (views.empty() || views.FindFirst(vid) != NO_ID) {
candidateViews.insert(vid);
}
}
}
// ------------------------------------------------------------
// 2. 兜底:候选视图为空
// ------------------------------------------------------------
if (candidateViews.empty()) {
++emptyCandidateViews;
IIndex forcedView = NO_ID;
if (!views.empty()) {
forcedView = views[0];
} else if (!images.empty()) {
forcedView = 0;
}
// 兜底:用第一个可用视图
IIndex forcedView = (!views.empty()) ? views[0] :
(!images.empty()) ? 0 : NO_ID;
if (forcedView != NO_ID) {
faceViews[i].push_back(forcedView);
faceViewWeights[i].push_back(1.0f);
for (FIndex fid : vf.faces) {
if (fid < faceToView.size())
faceToView[fid] = forcedView;
}
++fallbackByCenterFace;
continue;
}
DEBUG_EXTRA("VF[%zu] truly hopeless: no images available", i);
continue;
}
// ------------------------------------------------------------
// 3. 选择最佳视图(简单策略:第一个候选)
// ------------------------------------------------------------
// 选第一个候选(简单策略,后续可优化为角度最优)
IIndex bestView = *candidateViews.begin();
faceViews[i].push_back(bestView);
faceViewWeights[i].push_back(1.0f);
@ -14732,13 +14683,10 @@ bool MeshTexture::SelectBestViewsForVirtualFaces(VirtualFaceMap& virtualFaceMap, @@ -14732,13 +14683,10 @@ bool MeshTexture::SelectBestViewsForVirtualFaces(VirtualFaceMap& virtualFaceMap,
if (fid < faceToView.size())
faceToView[fid] = bestView;
}
++successVF;
}
// ----------------------------------------------------------------
// 4. 【轻量 Patch 一致性传播】
// ----------------------------------------------------------------
// ---------- 2. Patch 一致性传播 ----------
if (scene.mesh.faceFaces.empty()) {
scene.mesh.ListIncidenteFaceFaces();
}
@ -14777,13 +14725,10 @@ bool MeshTexture::SelectBestViewsForVirtualFaces(VirtualFaceMap& virtualFaceMap, @@ -14777,13 +14725,10 @@ bool MeshTexture::SelectBestViewsForVirtualFaces(VirtualFaceMap& virtualFaceMap,
newFaceToView[fid] = majorityView;
}
}
faceToView.swap(newFaceToView);
}
// ----------------------------------------------------------------
// 5. 根据传播后的结果,更新 virtual face 的视图
// ----------------------------------------------------------------
// ---------- 3. 写回 ----------
for (size_t i = 0; i < virtualFaceMap.size(); ++i) {
const VirtualFace& vf = virtualFaceMap[i];
if (vf.faces.empty() || faceViews[i].empty()) continue;
@ -14796,22 +14741,150 @@ bool MeshTexture::SelectBestViewsForVirtualFaces(VirtualFaceMap& virtualFaceMap, @@ -14796,22 +14741,150 @@ bool MeshTexture::SelectBestViewsForVirtualFaces(VirtualFaceMap& virtualFaceMap,
}
}
// ----------------------------------------------------------------
// 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;
}
// ============================================================
// 1. 计算虚拟面几何(Affine for triangle, Homography for patch)
// ============================================================
bool MeshTexture::ComputeVirtualFaceGeometry(const VirtualFaceMap& virtualFaceMap) {
// ✅ std::vector 用 resize
m_virtualFaceGeometries.resize(virtualFaceMap.size());
#ifdef _USE_OPENMP
#pragma omp parallel for schedule(dynamic)
#endif
for (int i = 0; i < (int)virtualFaceMap.size(); ++i) {
const VirtualFace& vf = virtualFaceMap[i];
VirtualFaceGeometry& geom = m_virtualFaceGeometries[i];
if (vf.faces.empty() || faceViews[i].empty()) {
geom.isValid = false;
continue;
}
IIndex viewID = faceViews[i][0];
geom.isValid = ComputeHomographyForVirtualFace(vf, viewID, geom);
}
return true;
}
// ============================================================
// 2. 核心:计算单应矩阵 / 仿射矩阵
// - 3 个点 → Affine(getAffineTransform)
// - ≥ 4 个点 → Homography(findHomography)
// ============================================================
bool MeshTexture::ComputeHomographyForVirtualFace(
const VirtualFace& vf,
IIndex viewID,
VirtualFaceGeometry& geom)
{
if (viewID >= (IIndex)images.size()) return false;
const Camera& cam = images[viewID].camera;
// ---------- 1. 收集顶点和 UV ----------
std::vector<Point3f> points3D;
std::vector<Point2f> pointsUV;
points3D.reserve(vf.faces.size() * 3);
pointsUV.reserve(vf.faces.size() * 3);
for (FIndex faceID : vf.faces) {
if (faceID >= (FIndex)scene.mesh.faces.size()) continue;
const Face& face = scene.mesh.faces[faceID];
const TexCoord* uv = &scene.mesh.faceTexcoords[faceID * 3];
for (int i = 0; i < 3; ++i) {
if (face[i] >= scene.mesh.vertices.size()) continue;
points3D.push_back(scene.mesh.vertices[face[i]]);
pointsUV.push_back(Point2f(uv[i].x, uv[i].y));
}
}
if (points3D.size() < 3) return false;
// ---------- 2. 计算中心(OpenCV 风格)----------
geom.center = Point3f(0, 0, 0);
for (const auto& p : points3D) geom.center += p;
geom.center *= 1.0f / (float)points3D.size();
// ---------- 3. 计算法线(OpenCV 风格)----------
if (!vf.faces.empty()) {
FIndex faceID = vf.faces[0];
const Face& face = scene.mesh.faces[faceID];
const Point3f& v0 = scene.mesh.vertices[face[0]];
const Point3f& v1 = scene.mesh.vertices[face[1]];
const Point3f& v2 = scene.mesh.vertices[face[2]];
Point3f edge1 = v1 - v0;
Point3f edge2 = v2 - v0;
Point3f normal = edge1.cross(edge2);
float length = cv::norm(normal);
if (length > 1e-8f) {
normal *= 1.0f / length;
} else {
normal = Point3f(0, 0, 1);
}
geom.normal = normal;
}
// ---------- 4. UV 包围盒 ----------
geom.uvBounds.Reset();
for (const auto& uv : pointsUV) {
geom.uvBounds.InsertFull(uv);
}
// ---------- 5. 投影到图像空间(double → float)----------
std::vector<Point2f> pointsImage;
pointsImage.reserve(points3D.size());
for (const auto& p3D : points3D) {
Point3d p64(p3D.x, p3D.y, p3D.z);
Point2d proj = cam.ProjectPoint(p64);
pointsImage.emplace_back((float)proj.x, (float)proj.y);
}
// ---------- 6. 核心分支:Affine vs Homography ----------
if (pointsUV.size() == 3) {
// ✅ 三角形:用仿射变换(Affine = 精确映射)
cv::Point2f src[3] = {pointsUV[0], pointsUV[1], pointsUV[2]};
cv::Point2f dst[3] = {pointsImage[0], pointsImage[1], pointsImage[2]};
cv::Mat affine = cv::getAffineTransform(src, dst);
if (affine.empty()) return false;
// 转成 3x3 齐次矩阵(与 Homography 统一格式)
geom.homography = cv::Mat1f(3, 3, 0.0f);
for (int r = 0; r < 2; ++r) {
for (int c = 0; c < 3; ++c) {
geom.homography(r, c) = affine.at<double>(r, c);
}
}
geom.homography(2, 2) = 1.0f;
}
else if (pointsUV.size() >= 4) {
// ✅ Patch:用 RANSAC 单应矩阵
geom.homography = cv::findHomography(
pointsUV, pointsImage, cv::RANSAC, 2.0);
}
else {
return false;
}
geom.isValid = !geom.homography.empty();
return geom.isValid;
}
bool MeshTexture::GenerateTextureWithVirtualFacesInternal(bool bGlobalSeamLeveling, bool bLocalSeamLeveling,
unsigned nTextureSizeMultiple, unsigned nRectPackingHeuristic,
Pixel8U colEmpty, float fSharpnessWeight, int maxTextureSize,
@ -14918,282 +14991,34 @@ bool MeshTexture::ConvertVectorToVirtualFaceDataArr(const std::vector<VirtualFac @@ -14918,282 +14991,34 @@ bool MeshTexture::ConvertVectorToVirtualFaceDataArr(const std::vector<VirtualFac
return true;
}
// ============================================================
// 4. CreateVirtualFacesForExistingUV(简化版)
// ============================================================
bool MeshTexture::CreateVirtualFacesForExistingUV(VirtualFaceMap& virtualFaceMap) {
DEBUG_EXTRA("Creating virtual faces for existing UV texture mapping");
DEBUG_EXTRA("Creating virtual faces for existing UV (RC style)");
// 0. 详细的输入验证
DEBUG_EXTRA("=== Detailed Input Validation ===");
DEBUG_EXTRA("Scene pointer: %p", &scene);
DEBUG_EXTRA("Mesh pointer: %p", &scene.mesh);
// 检查基本数据结构
// 输入验证
if (scene.mesh.faces.empty()) {
DEBUG_EXTRA("ERROR: Mesh has no faces!");
return false;
}
if (scene.mesh.vertices.empty()) {
DEBUG_EXTRA("ERROR: Mesh has no vertices!");
return false;
}
virtualFaceMap.resize(scene.mesh.faces.size());
if (scene.mesh.faceTexcoords.empty()) {
DEBUG_EXTRA("ERROR: Mesh has no texture coordinates!");
return false;
}
// ✅ RC 风格:每个三角形一个虚拟面(1:1)
virtualFaceMap.resize(scene.mesh.faces.size());
for (FIndex i = 0; i < (FIndex)scene.mesh.faces.size(); ++i) {
virtualFaceMap[i].faces = {i};
}
return true;
// 验证faces数组的大小
size_t numFaces = scene.mesh.faces.size();
size_t numVertices = scene.mesh.vertices.size();
size_t numFaceTexcoords = scene.mesh.faceTexcoords.size();
DEBUG_EXTRA("Number of faces: %zu", numFaces);
DEBUG_EXTRA("Number of vertices: %zu", numVertices);
DEBUG_EXTRA("Number of texture coordinates: %zu", numFaceTexcoords);
// 关键检查:必须有纹理坐标才能使用此方法
if (numFaceTexcoords == 0) {
DEBUG_EXTRA("ERROR: Mesh has no texture coordinates. Cannot create virtual faces for existing UV.");
return false;
}
if (numFaceTexcoords < numFaces * 3) {
DEBUG_EXTRA("ERROR: Not enough UV coordinates! Expected %zu (faces * 3), have %zu",
numFaces * 3, numFaceTexcoords);
return false;
}
// 验证面片索引
DEBUG_EXTRA("Validating face indices...");
for (size_t i = 0; i < std::min(numFaces, static_cast<size_t>(10)); ++i) { // 使用static_cast
const Mesh::Face& face = scene.mesh.faces[i];
bool valid = true;
for (int j = 0; j < 3; ++j) {
if (face[j] >= numVertices) {
DEBUG_EXTRA("ERROR: Face %zu has invalid vertex index %u (max: %zu)",
i, face[j], numVertices - 1);
valid = false;
}
}
if (valid) {
DEBUG_EXTRA("Face %zu: vertices [%u, %u, %u] - OK",
i, face[0], face[1], face[2]);
}
}
// 验证UV坐标索引
if (numFaceTexcoords > 0) {
DEBUG_EXTRA("Validating UV coordinate indices...");
if (numFaceTexcoords < numFaces * 3) {
DEBUG_EXTRA("ERROR: Not enough UV coordinates! Expected %zu, have %zu",
numFaces * 3, numFaceTexcoords);
return false;
}
}
// 1. 确保网格拓扑已计算
DEBUG_EXTRA("Computing mesh topology...");
if (scene.mesh.faceFaces.empty()) {
DEBUG_EXTRA(" Computing incident faces...");
try {
scene.mesh.ListIncidenteFaces();
scene.mesh.ListIncidenteFaceFaces();
DEBUG_EXTRA(" Done computing incident faces");
} catch (const std::exception& e) {
DEBUG_EXTRA(" ERROR computing incident faces: %s", e.what());
return false;
}
}
if (scene.mesh.faceNormals.empty()) {
DEBUG_EXTRA(" Computing face normals...");
try {
scene.mesh.ComputeNormalFaces();
DEBUG_EXTRA(" Done computing face normals");
} catch (const std::exception& e) {
DEBUG_EXTRA(" ERROR computing face normals: %s", e.what());
return false;
}
}
std::vector<bool> processedFaces(numFaces, false);
// 3. 基于曲率分割网格
DEBUG_EXTRA("Segmenting mesh based on curvature...");
Mesh::FaceIdxArr regionMap;
try {
scene.SegmentMeshBasedOnCurvature(regionMap, 0.2f);
DEBUG_EXTRA("Mesh segmentation completed, regionMap size: %zu", regionMap.size());
if (regionMap.size() != numFaces) {
DEBUG_EXTRA("ERROR: regionMap size (%zu) doesn't match number of faces (%u)",
regionMap.size(), numFaces);
return false;
}
} catch (const std::exception& e) {
DEBUG_EXTRA("ERROR during mesh segmentation: %s", e.what());
return false;
}
// 4. 统计每个区域的面积
DEBUG_EXTRA("Calculating region areas...");
std::unordered_map<int, float> regionAreas;
for (FIndex fid = 0; fid < numFaces; ++fid) {
if (fid % 10000 == 0 && fid > 0) {
DEBUG_EXTRA(" Processed %u/%u faces", fid, numFaces);
}
int region = regionMap[fid];
// 验证面片索引
if (fid >= scene.mesh.faces.size()) {
DEBUG_EXTRA("ERROR: Face index %u out of bounds (mesh has %zu faces)",
fid, scene.mesh.faces.size());
continue;
}
const Mesh::Face& face = scene.mesh.faces[fid];
// 验证顶点索引
for (int i = 0; i < 3; ++i) {
if (face[i] >= scene.mesh.vertices.size()) {
DEBUG_EXTRA("ERROR: Vertex index %u out of bounds in face %u (mesh has %zu vertices)",
face[i], fid, scene.mesh.vertices.size());
continue;
}
}
const Point3f& v0 = scene.mesh.vertices[face[0]];
const Point3f& v1 = scene.mesh.vertices[face[1]];
const Point3f& v2 = scene.mesh.vertices[face[2]];
// 计算三角形面积
Point3f edge1 = v1 - v0;
Point3f edge2 = v2 - v0;
Point3f crossProd(
edge1.y * edge2.z - edge1.z * edge2.y,
edge1.z * edge2.x - edge1.x * edge2.z,
edge1.x * edge2.y - edge1.y * edge2.x
);
float area = 0.5f * std::sqrt(
crossProd.x * crossProd.x +
crossProd.y * crossProd.y +
crossProd.z * crossProd.z
);
if (area < 0) {
DEBUG_EXTRA("WARNING: Negative area calculated for face %u: %f", fid, area);
area = 0.0f;
}
regionAreas[region] += area;
}
DEBUG_EXTRA("Region area calculation completed, found %zu regions", regionAreas.size());
// 5. 为每个区域收集面片
DEBUG_EXTRA("Grouping faces by region...");
std::unordered_map<int, std::vector<FIndex>> regionFaces;
for (FIndex fid = 0; fid < numFaces; ++fid) {
int region = regionMap[fid];
regionFaces[region].push_back(fid);
}
DEBUG_EXTRA("Found %zu regions with faces", regionFaces.size());
// 6. 创建虚拟面
DEBUG_EXTRA("Creating virtual faces...");
virtualFaceMap.clear();
virtualFaceMap.reserve(regionFaces.size());
int regionCount = 0;
int smallRegionCount = 0;
int uvDiscontinuousCount = 0;
int createdVirtualFaces = 0;
for (const auto& region : regionFaces) {
regionCount++;
int regionID = region.first;
const std::vector<FIndex>& faceList = region.second;
if (regionCount % 100 == 0) {
DEBUG_EXTRA(" Processing region %d/%d (%zu faces)", regionCount, regionFaces.size(), faceList.size());
}
// 检查区域面积是否足够大
float regionArea = regionAreas[regionID];
if (regionArea < 0.001f) { // 面积阈值
DEBUG_EXTRA(" Region %d is too small (area: %f), using individual faces", regionID, regionArea);
smallRegionCount++;
// 区域太小,不创建虚拟面
for (FIndex fid : faceList) {
virtualFaceMap.push_back(VirtualFace());
virtualFaceMap.back().faces.push_back(fid);
}
continue;
}
// 检查UV连续性
if (!CheckUVContinuity(faceList)) {
DEBUG_EXTRA(" Region %d has discontinuous UV, using individual faces", regionID);
uvDiscontinuousCount++;
// UV不连续,保持原始面片
for (FIndex fid : faceList) {
virtualFaceMap.push_back(VirtualFace());
virtualFaceMap.back().faces.push_back(fid);
}
continue;
}
// 创建虚拟面
VirtualFace vf;
vf.faces = faceList;
// 计算虚拟面的中心、法线和面积
if (!CalculateVirtualFaceProperties(vf)) {
DEBUG_EXTRA(" Failed to calculate properties for virtual face in region %d", regionID);
// 计算失败,回退到原始面片
for (FIndex fid : faceList) {
virtualFaceMap.push_back(VirtualFace());
virtualFaceMap.back().faces.push_back(fid);
}
continue;
}
// 计算虚拟面的UV边界
if (!CalculateVirtualFaceUVBounds(vf)) {
DEBUG_EXTRA(" Failed to calculate UV bounds for virtual face in region %d", regionID);
// 计算失败,回退到原始面片
for (FIndex fid : faceList) {
virtualFaceMap.push_back(VirtualFace());
virtualFaceMap.back().faces.push_back(fid);
}
continue;
}
virtualFaceMap.push_back(vf);
createdVirtualFaces++;
}
DEBUG_EXTRA("Virtual face creation completed:");
DEBUG_EXTRA(" Total regions: %zu", regionFaces.size());
DEBUG_EXTRA(" Small regions (area < 0.001): %d", smallRegionCount);
DEBUG_EXTRA(" UV discontinuous regions: %d", uvDiscontinuousCount);
DEBUG_EXTRA(" Created virtual faces: %d", createdVirtualFaces);
DEBUG_EXTRA(" Total virtual faces (including individual faces): %zu", virtualFaceMap.size());
if (virtualFaceMap.empty()) {
DEBUG_EXTRA("ERROR: No virtual faces created!");
return false;
}
DEBUG_EXTRA("Created %zu virtual faces (one per triangle)", virtualFaceMap.size());
return true;
}
@ -18813,49 +18638,48 @@ bool Scene::TextureMesh(unsigned nResolutionLevel, unsigned nMinResolution, unsi @@ -18813,49 +18638,48 @@ bool Scene::TextureMesh(unsigned nResolutionLevel, unsigned nMinResolution, unsi
return false;
}
// ✅✅✅ 关键修复:重新计算拓扑(否则 faceFaces 是坏的)
mesh.ListIncidenteFaces();
mesh.ListIncidenteFaceFaces();
mesh.ComputeNormalFaces();
mesh.ListBoundaryVertices();
// 纯可见性计算(初始化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;
}
// ✅ 确保拓扑信息存在
if (mesh.faceFaces.empty()) {
mesh.ListIncidenteFaces();
mesh.ListIncidenteFaceFaces();
}
if (mesh.faceNormals.empty()) {
mesh.ComputeNormalFaces();
}
if (mesh.vertexBoundary.empty()) {
mesh.ListBoundaryVertices();
}
// 创建虚拟面(1:1映射)
MeshTexture::VirtualFaceMap virtualFaceMap;
if (!texture.CreateVirtualFacesForExistingUV(virtualFaceMap)) return false;
// ✅ 1. 创建虚拟面(每三角形一个)
MeshTexture::VirtualFaceMap virtualFaceMap;
if (!texture.CreateVirtualFacesForExistingUV(virtualFaceMap))
return false;
// 选最佳视图(带patch一致性)
if (!texture.SelectBestViewsForVirtualFaces(
virtualFaceMap, 1, fOutlierThreshold, fRatioDataSmoothness, nIgnoreMaskLabel, views))
return false;
// ✅ 2. 计算可见性(填充 faceNeighbors)
if (!texture.ComputePureFaceVisibility(
fOutlierThreshold, nIgnoreMaskLabel, views)) {
return false;
}
// 直接光栅化(不需要生成图集)
Mesh::Image8U3Arr textures;
if (!texture.RasterizeVirtualFaces(
virtualFaceMap, texture.faceViews, texture.faceViewWeights,
nTextureSizeMultiple, colEmpty, textures))
return false;
// ✅ 3. 选择最佳视图(带 patch 一致性)
if (!texture.SelectBestViewsForVirtualFaces(
virtualFaceMap, 1, fOutlierThreshold,
fRatioDataSmoothness, nIgnoreMaskLabel, views))
return false;
// ✅ 4. RC 风格光栅化(Affine + Homography 混合)
Mesh::Image8U3Arr textures;
if (!texture.RasterizeVirtualFaces(
virtualFaceMap, texture.faceViews,
texture.faceViewWeights,
nTextureSizeMultiple, colEmpty, textures))
return false;
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;
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(

Loading…
Cancel
Save