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