进一步优化
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("=================================================");
|
||||
|
||||
// ================================================================
|
||||
// ★★★ 连通域强制统一视角(消除色差碎片)★★★
|
||||
// ================================================================
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user