进一步优化
This commit is contained in:
1 parent
a86f98ea46
commit
4713198454
1 file changed
+170
@@ -18543,6 +18543,176 @@ bool MeshTexture::SelectBestViewsForVirtualFaces(
|
|||||||
DEBUG_EXTRA("Fallback by center face : %zu", fallbackByCenterFace);
|
DEBUG_EXTRA("Fallback by center face : %zu", fallbackByCenterFace);
|
||||||
DEBUG_EXTRA("=================================================");
|
DEBUG_EXTRA("=================================================");
|
||||||
|
|
||||||
|
// ================================================================
|
||||||
|
// ★★★ 连通域强制统一视角(消除色差碎片)★★★
|
||||||
|
// ================================================================
|
||||||
|
{
|
||||||
|
TD_TIMER_START();
|
||||||
|
|
||||||
|
const FIndex NF = (FIndex)faceToView.size();
|
||||||
|
if (NF == 0) return true;
|
||||||
|
|
||||||
|
// 1. 构建面片邻接关系(只考虑有效面片)
|
||||||
|
std::vector<std::vector<FIndex>> adjList(NF);
|
||||||
|
for (FIndex fid = 0; fid < NF; ++fid) {
|
||||||
|
if (faceToView[fid] == NO_ID) continue;
|
||||||
|
if (fid >= (FIndex)scene.mesh.faceFaces.size()) continue;
|
||||||
|
|
||||||
|
const Mesh::FaceFaces& neighbors = scene.mesh.faceFaces[fid];
|
||||||
|
for (int k = 0; k < 3; ++k) {
|
||||||
|
FIndex nb = neighbors[k];
|
||||||
|
if (nb == NO_ID || nb >= NF) continue;
|
||||||
|
if (faceToView[nb] == NO_ID) continue;
|
||||||
|
adjList[fid].push_back(nb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 连通域标记(BFS)
|
||||||
|
std::vector<int> component(NF, -1);
|
||||||
|
int numComponents = 0;
|
||||||
|
|
||||||
|
for (FIndex fid = 0; fid < NF; ++fid) {
|
||||||
|
if (faceToView[fid] == NO_ID) continue;
|
||||||
|
if (component[fid] >= 0) continue;
|
||||||
|
|
||||||
|
std::queue<FIndex> q;
|
||||||
|
q.push(fid);
|
||||||
|
component[fid] = numComponents;
|
||||||
|
|
||||||
|
while (!q.empty()) {
|
||||||
|
FIndex cur = q.front(); q.pop();
|
||||||
|
for (FIndex nb : adjList[cur]) {
|
||||||
|
if (component[nb] < 0) {
|
||||||
|
component[nb] = numComponents;
|
||||||
|
q.push(nb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
numComponents++;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUG_EXTRA("Connected components: %d components from %d faces", numComponents, NF);
|
||||||
|
|
||||||
|
// 3. 统计每个连通域的视角分布
|
||||||
|
struct CompInfo {
|
||||||
|
std::vector<FIndex> faces;
|
||||||
|
std::map<IIndex, int> viewVotes;
|
||||||
|
std::map<IIndex, float> viewScoreSum;
|
||||||
|
std::map<IIndex, float> viewAvgScore;
|
||||||
|
};
|
||||||
|
std::vector<CompInfo> comps(numComponents);
|
||||||
|
|
||||||
|
for (FIndex fid = 0; fid < NF; ++fid) {
|
||||||
|
if (faceToView[fid] == NO_ID) continue;
|
||||||
|
int c = component[fid];
|
||||||
|
if (c < 0) continue;
|
||||||
|
|
||||||
|
IIndex vid = faceToView[fid];
|
||||||
|
float score = faceScores[fid];
|
||||||
|
|
||||||
|
comps[c].faces.push_back(fid);
|
||||||
|
comps[c].viewVotes[vid]++;
|
||||||
|
comps[c].viewScoreSum[vid] += score;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int c = 0; c < numComponents; ++c) {
|
||||||
|
for (auto& vs : comps[c].viewScoreSum) {
|
||||||
|
IIndex vid = vs.first;
|
||||||
|
int votes = comps[c].viewVotes[vid];
|
||||||
|
comps[c].viewAvgScore[vid] = vs.second / votes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. 每个连通域选最佳视角
|
||||||
|
int changedFaces = 0;
|
||||||
|
int smallComponents = 0;
|
||||||
|
|
||||||
|
for (int c = 0; c < numComponents; ++c) {
|
||||||
|
auto& comp = comps[c];
|
||||||
|
if (comp.faces.empty()) continue;
|
||||||
|
|
||||||
|
// 小连通域合并
|
||||||
|
if ((int)comp.faces.size() < 5) {
|
||||||
|
smallComponents++;
|
||||||
|
|
||||||
|
std::map<int, int> neighborCompVotes;
|
||||||
|
for (FIndex fid : comp.faces) {
|
||||||
|
for (FIndex nb : adjList[fid]) {
|
||||||
|
int nc = component[nb];
|
||||||
|
if (nc >= 0 && nc != c) {
|
||||||
|
neighborCompVotes[nc]++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!neighborCompVotes.empty()) {
|
||||||
|
auto bestNb = std::max_element(neighborCompVotes.begin(), neighborCompVotes.end(),
|
||||||
|
[](const auto& a, const auto& b) { return a.second < b.second; });
|
||||||
|
|
||||||
|
int targetComp = bestNb->first;
|
||||||
|
IIndex targetView = NO_ID;
|
||||||
|
int maxVotes = 0;
|
||||||
|
for (const auto& vv : comps[targetComp].viewVotes) {
|
||||||
|
if (vv.second > maxVotes) {
|
||||||
|
maxVotes = vv.second;
|
||||||
|
targetView = vv.first;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (targetView != NO_ID) {
|
||||||
|
for (FIndex fid : comp.faces) {
|
||||||
|
if (faceToView[fid] != targetView) {
|
||||||
|
faceToView[fid] = targetView;
|
||||||
|
faceScores[fid] = comps[targetComp].viewAvgScore[targetView];
|
||||||
|
changedFaces++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 正常连通域选视角
|
||||||
|
IIndex bestView = NO_ID;
|
||||||
|
float bestWeightedScore = -FLT_MAX;
|
||||||
|
int totalFaces = (int)comp.faces.size();
|
||||||
|
|
||||||
|
for (const auto& vv : comp.viewVotes) {
|
||||||
|
IIndex vid = vv.first;
|
||||||
|
int votes = vv.second;
|
||||||
|
float avgScore = comp.viewAvgScore[vid];
|
||||||
|
|
||||||
|
float voteRatio = (float)votes / totalFaces;
|
||||||
|
float normalizedScore = std::max(0.0f, std::min(1.0f, avgScore));
|
||||||
|
float weightedScore = 0.6f * voteRatio + 0.4f * normalizedScore;
|
||||||
|
|
||||||
|
if (weightedScore > bestWeightedScore) {
|
||||||
|
bestWeightedScore = weightedScore;
|
||||||
|
bestView = vid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bestView == NO_ID) continue;
|
||||||
|
|
||||||
|
for (FIndex fid : comp.faces) {
|
||||||
|
if (faceToView[fid] != bestView) {
|
||||||
|
faceToView[fid] = bestView;
|
||||||
|
faceScores[fid] = comp.viewAvgScore[bestView];
|
||||||
|
changedFaces++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUG_EXTRA("Component unification: %d faces changed, %d small components merged (%s)",
|
||||||
|
changedFaces, smallComponents, TD_TIMER_GET_FMT().c_str());
|
||||||
|
|
||||||
|
// ★★★ 注意:不要在这里更新 faceViews/faceViewWeights!
|
||||||
|
// faceViews 会在视图选择阶段的末尾,由 SelectBestViewsForVirtualFaces 根据 faceToView 重建
|
||||||
|
// 如果在这里强行同步,会破坏虚拟面片与视图的映射关系,导致采样坐标错误
|
||||||
|
|
||||||
|
DEBUG_EXTRA("Unification complete: %d components processed.", numComponents);
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user