Browse Source

中间流程

ManualUV
hesuicong 4 weeks ago
parent
commit
3adc1c012a
  1. 169
      libs/MVS/SceneTexture.cpp

169
libs/MVS/SceneTexture.cpp

@ -14266,7 +14266,7 @@ bool MeshTexture::TextureWithExistingUVVirtualFaces(const IIndexArr& views, int @@ -14266,7 +14266,7 @@ bool MeshTexture::TextureWithExistingUVVirtualFaces(const IIndexArr& views, int
float fOutlierThreshold, unsigned nTextureSizeMultiple,
Pixel8U colEmpty, float fSharpnessWeight)
{
DEBUG_EXTRA("TextureWithExistingUVVirtualFaces with multi-view blending");
DEBUG_EXTRA("TextureWithExistingUVVirtualFaces (STABLE MODE: 1 Face = 1 VirtualFace)");
TD_TIMER_START();
// 1. 验证输入
@ -14281,134 +14281,131 @@ bool MeshTexture::TextureWithExistingUVVirtualFaces(const IIndexArr& views, int @@ -14281,134 +14281,131 @@ bool MeshTexture::TextureWithExistingUVVirtualFaces(const IIndexArr& views, int
return false;
}
// 2. 创建虚拟面
DEBUG_EXTRA("Creating virtual faces for existing UV texture mapping...");
const size_t numFaces = scene.mesh.faces.size();
// ==========================================================
// 关键修改点 1:强制 1:1 映射,绕过有问题的 VirtualFace 合并逻辑
// ==========================================================
VirtualFaceMap virtualFaceMap;
if (!CreateVirtualFacesForExistingUV(virtualFaceMap)) {
DEBUG_EXTRA("Failed to create virtual faces, falling back to original faces");
// 回退到原始面片
virtualFaceMap.clear();
for (FIndex fid = 0; fid < faces.size(); ++fid) {
virtualFaceMap.push_back(VirtualFace());
VirtualFace& vf = virtualFaceMap.back();
vf.faces.push_back(fid);
}
virtualFaceMap.reserve(numFaces);
for (FIndex fid = 0; fid < numFaces; ++fid) {
VirtualFace vf;
vf.faces.push_back(fid);
virtualFaceMap.push_back(vf);
}
DEBUG_EXTRA("Forced 1-to-1 mapping: %zu virtual faces for %zu original faces",
virtualFaceMap.size(), numFaces);
DEBUG_EXTRA("Created %zu virtual faces (original faces: %zu)", virtualFaceMap.size(), faces.size());
// 3. 为每个虚拟面收集视图数据
// 2. 为每个虚拟面(其实就是原始面片)收集视图数据
// ListCameraVirtualFaces 内部会调用 Rasterize,用于可见性判断
VirtualFaceDataArr virtualFaceDatas;
if (!ListCameraVirtualFaces(virtualFaceMap, virtualFaceDatas, fOutlierThreshold, nIgnoreMaskLabel, views, false)) {
return false;
}
// 4. 为每个虚拟面选择最佳视图,支持多视图融合
// ==========================================================
// 关键修改点 2:不再做多视图融合,直接选 Best View
// ==========================================================
std::vector<std::vector<IIndex>> virtualFaceViews(virtualFaceMap.size());
std::vector<std::vector<float>> virtualFaceViewWeights(virtualFaceMap.size());
#ifdef _USE_OPENMP
#pragma omp parallel for schedule(dynamic)
for (int_t idxVF = 0; idxVF < (int_t)virtualFaceMap.size(); ++idxVF) {
#else
for (size_t idxVF = 0; idxVF < virtualFaceMap.size(); ++idxVF) {
#endif
for (int_t idxVF = 0; idxVF < (int_t)virtualFaceMap.size(); ++idxVF) {
const FIndex fid = virtualFaceMap[idxVF].faces[0]; // 取出唯一的原始面片ID
const FaceDataArr& vfDatas = virtualFaceDatas[idxVF];
std::vector<std::pair<float, IIndex>> viewScores;
// 收集所有有效视图
float bestWeight = -1.0f;
IIndex bestViewID = IIndex(-1);
// 遍历能看到这个面片的所有相机
for (const FaceData& data : vfDatas) {
if (!data.bInvalidFacesRelative) {
// 使用 FaceData 中的视图质量
float weight = data.quality;
// 添加视角与法线夹角的权重
const Image& image = images[data.idxView];
const Normal& faceNormal = scene.mesh.faceNormals[virtualFaceMap[idxVF].faces[0]]; // 使用第一个面的法线
// 计算相机方向
Point3f cameraForward(0, 0, -1); // 相机前方
Point3f cameraForwardWorld;
cameraForwardWorld.x = (float)(image.camera.R(0,0) * cameraForward.x +
image.camera.R(0,1) * cameraForward.y +
image.camera.R(0,2) * cameraForward.z);
cameraForwardWorld.y = (float)(image.camera.R(1,0) * cameraForward.x +
image.camera.R(1,1) * cameraForward.y +
image.camera.R(1,2) * cameraForward.z);
cameraForwardWorld.z = (float)(image.camera.R(2,0) * cameraForward.x +
image.camera.R(2,1) * cameraForward.y +
image.camera.R(2,2) * cameraForward.z);
cameraForward = cameraForwardWorld;
float len = sqrt(cameraForward.x * cameraForward.x +
cameraForward.y * cameraForward.y +
cameraForward.z * cameraForward.z);
if (len > 0) {
cameraForward.x /= len;
cameraForward.y /= len;
cameraForward.z /= len;
}
if (data.bInvalidFacesRelative) continue;
// 法线与相机方向的点积(越大越好,表示面正对相机)
float dotProduct = faceNormal.dot(cameraForward);
float angleWeight = (dotProduct + 1.0f) * 0.5f; // 归一化到[0,1]
// 基础质量分数
float weight = data.quality;
// 综合权重
float finalWeight = weight * 0.7f + angleWeight * 0.3f;
// 加上法线夹角权重(正对相机的权重更高)
const Image& image = images[data.idxView];
// ✅ 使用 double 向量,和 RMatrix 精度一致
Point3d camDir(0, 0, -1);
camDir = image.camera.R * camDir; // ✅ RMatrix × Point3d
viewScores.emplace_back(finalWeight, data.idxView);
}
}
// ✅ 归一化(double 版本)
const double len = sqrt(
camDir.x * camDir.x +
camDir.y * camDir.y +
camDir.z * camDir.z
);
if (len > 0.0) {
camDir.x /= len;
camDir.y /= len;
camDir.z /= len;
}
// 按权重排序,选择前N个视图
std::sort(viewScores.begin(), viewScores.end(),
[](const auto& a, const auto& b) { return a.first > b.first; });
// ✅ 转回 float,用于和法线点积
Point3f cameraForward(
static_cast<float>(camDir.x),
static_cast<float>(camDir.y),
static_cast<float>(camDir.z)
);
const int maxViews = 5; // 最多使用5个视图进行融合
float totalWeight = 0.0f;
// ✅ 法线夹角权重
const Normal& faceNormal = scene.mesh.faceNormals[fid];
float dotProduct = faceNormal.dot(cameraForward);
float angleWeight = (dotProduct + 1.0f) * 0.5f;
for (int i = 0; i < std::min((int)viewScores.size(), maxViews); ++i) {
if (viewScores[i].first > 0.1f) { // 质量阈值
virtualFaceViews[idxVF].push_back(viewScores[i].second);
virtualFaceViewWeights[idxVF].push_back(viewScores[i].first);
totalWeight += viewScores[i].first;
// 综合权重
float finalWeight = weight * 0.7f + angleWeight * 0.3f;
if (finalWeight > bestWeight) {
bestWeight = finalWeight;
bestViewID = data.idxView;
}
}
// 归一化权重
if (totalWeight > 0.0f) {
for (float& w : virtualFaceViewWeights[idxVF]) {
w /= totalWeight;
}
// 如果找到了有效的视图
if (bestViewID != IIndex(-1) && bestWeight > 0.1f) {
virtualFaceViews[idxVF] = { bestViewID };
virtualFaceViewWeights[idxVF] = { 1.0f }; // 单视图权重设为1
}
}
// 5. 为虚拟面生成纹理图集(使用多视图融合)
Mesh::Image8U3Arr textures = GenerateMultiViewTextureAtlasWithVirtualFaces(virtualFaceMap, virtualFaceDatas,
virtualFaceViews, virtualFaceViewWeights,
nTextureSizeMultiple, colEmpty, fSharpnessWeight);
// 3. 生成纹理图集
// 此时调用的 GenerateMultiViewTextureAtlasWithVirtualFaces 内部,
// 虽然名字带 MultiView,但因为权重都是1且只有一个View,
// 实际上执行的是 Single View Rendering。
// 配合之前的 MSAA 代码,就能得到清晰且无锯齿的结果。
Mesh::Image8U3Arr textures = GenerateMultiViewTextureAtlasWithVirtualFaces(
virtualFaceMap,
virtualFaceDatas,
virtualFaceViews,
virtualFaceViewWeights,
nTextureSizeMultiple,
colEmpty,
fSharpnessWeight
);
if (!textures.empty()) {
scene.mesh.texturesDiffuse = std::move(textures);
// 设置纹理索引
scene.mesh.faceTexindices.resize(scene.mesh.faces.size());
for (size_t i = 0; i < scene.mesh.faces.size(); ++i) {
// 设置纹理索引(所有面片使用第0张纹理图)
scene.mesh.faceTexindices.resize(numFaces);
for (size_t i = 0; i < numFaces; ++i) {
scene.mesh.faceTexindices[i] = 0;
}
DEBUG_EXTRA("Successfully generated %zu texture atlases with virtual faces", scene.mesh.texturesDiffuse.size());
DEBUG_EXTRA("Successfully generated %zu texture atlases (Stable Mode)", scene.mesh.texturesDiffuse.size());
// 保存纹理
std::string outputDir = "texture_output";
if (SaveGeneratedTextures(scene.mesh.texturesDiffuse, outputDir)) {
DEBUG_EXTRA("Textures saved to: %s", outputDir.c_str());
}
SaveGeneratedTextures(scene.mesh.texturesDiffuse, outputDir);
return true;
}
DEBUG_EXTRA("Texture generation with virtual faces failed");
DEBUG_EXTRA("Texture generation failed in stable mode");
return false;
}

Loading…
Cancel
Save