From 1b9cf3ea4688b6d2b78463e16b86b0887fbe2177 Mon Sep 17 00:00:00 2001 From: hesuicong Date: Tue, 11 Aug 2026 09:53:14 +0800 Subject: [PATCH] =?UTF-8?q?=E9=9B=86=E6=88=90Gutter=20=E8=BE=B9=E7=BC=98?= =?UTF-8?q?=E7=BC=93=E5=86=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- libs/MVS/SceneTexture.cpp | 60 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 57 insertions(+), 3 deletions(-) diff --git a/libs/MVS/SceneTexture.cpp b/libs/MVS/SceneTexture.cpp index 9c2a736..40876d4 100644 --- a/libs/MVS/SceneTexture.cpp +++ b/libs/MVS/SceneTexture.cpp @@ -14332,6 +14332,8 @@ bool MeshTexture::RasterizeVirtualFaces( // ✅ 拷贝到 atlas(OpenMP critical 区) #pragma omp critical { + const int gutter = 4; // 4像素边缘缓冲 + for (int y = 0; y < patchH; ++y) { for (int x = 0; x < patchW; ++x) { cv::Vec3b color = patch.at(y, x); @@ -14344,6 +14346,56 @@ bool MeshTexture::RasterizeVirtualFaces( atlasY < 0 || atlasY >= textureSize) continue; + // ✅ 计算当前像素的 UV 坐标 + float u = (float)atlasX / (float)textureSize; + float v = (float)atlasY / (float)textureSize; + + // ✅ 获取三角形的三个 UV 点 + const TexCoord& uv0 = scene.mesh.faceTexcoords[vf.faces[0] * 3 + 0]; + const TexCoord& uv1 = scene.mesh.faceTexcoords[vf.faces[0] * 3 + 1]; + const TexCoord& uv2 = scene.mesh.faceTexcoords[vf.faces[0] * 3 + 2]; + + // ✅ 计算点到三角形三条边的有符号距离(UV空间) + // 使用重心坐标或点到线段的距离公式 + auto pointToLineDistance = [](float px, float py, + float x1, float y1, + float x2, float y2) -> float { + float dx = x2 - x1; + float dy = y2 - y1; + if (dx == 0.0f && dy == 0.0f) return std::sqrt((px-x1)*(px-x1) + (py-y1)*(py-y1)); + + float t = ((px - x1) * dx + (py - y1) * dy) / (dx*dx + dy*dy); + t = std::max(0.0f, std::min(1.0f, t)); + + float closestX = x1 + t * dx; + float closestY = y1 + t * dy; + return std::sqrt((px - closestX)*(px - closestX) + + (py - closestY)*(py - closestY)); + }; + + // 计算到三条边的距离 + float d0 = pointToLineDistance(u, v, uv0.x, uv0.y, uv1.x, uv1.y); + float d1 = pointToLineDistance(u, v, uv1.x, uv1.y, uv2.x, uv2.y); + float d2 = pointToLineDistance(u, v, uv2.x, uv2.y, uv0.x, uv0.y); + + // 取最小距离作为到三角形边界的距离 + float distToEdge = std::min({d0, d1, d2}); + + // 转换为像素距离 + float pixelDist = distToEdge * textureSize; + + // ✅ Gutter 衰减逻辑(只衰减评分,不修改颜色!) + float gutterWeight = 1.0f; + if (pixelDist < gutter) { + // 使用平滑衰减函数(二次曲线) + gutterWeight = (pixelDist * pixelDist) / (gutter * gutter); + + // 极边缘处给极低权重,但不跳过 + if (pixelDist < 0.5f) { + gutterWeight = 0.01f; // 极低权重,几乎不会被选中 + } + } + size_t idx = atlasY * textureSize + atlasX; TexelScore& ts = m_texelScores[idx]; @@ -14352,11 +14404,13 @@ bool MeshTexture::RasterizeVirtualFaces( ? -1.0f : virtualFaceViewWeights[i][0]; - // ✅ 只接受更高评分的写入 - if (currentScore > ts.score) { + // ✅ 只衰减评分,不修改颜色! + float finalScore = currentScore * gutterWeight; + + if (finalScore > ts.score) { atlas(atlasY, atlasX) = Pixel8U{color[2], color[1], color[0]}; - ts.score = currentScore; + ts.score = finalScore; ts.viewID = viewID; } }