@ -441,7 +441,7 @@ public:
MeshTexture ( Scene & _scene , unsigned _nResolutionLevel = 0 , unsigned _nMinResolution = 640 ) ;
MeshTexture ( Scene & _scene , unsigned _nResolutionLevel = 0 , unsigned _nMinResolution = 640 ) ;
~ MeshTexture ( ) ;
~ MeshTexture ( ) ;
void ListVertexFaces ( ) ;
void ListVertexFaces ( bool bUseExistingUV = false ) ;
bool ListCameraFaces ( FaceDataViewArr & , float fOutlierThreshold , int nIgnoreMaskLabel , const IIndexArr & views , bool bUseVirtualFaces ) ;
bool ListCameraFaces ( FaceDataViewArr & , float fOutlierThreshold , int nIgnoreMaskLabel , const IIndexArr & views , bool bUseVirtualFaces ) ;
bool CheckInvalidFaces ( FaceDataViewArr & facesDatas , float fOutlierThreshold , int nIgnoreMaskLabel , const IIndexArr & _views , bool bUseVirtualFaces ) ;
bool CheckInvalidFaces ( FaceDataViewArr & facesDatas , float fOutlierThreshold , int nIgnoreMaskLabel , const IIndexArr & _views , bool bUseVirtualFaces ) ;
@ -465,7 +465,7 @@ public:
bool FaceViewSelection ( unsigned minCommonCameras , float fOutlierThreshold , float fRatioDataSmoothness , int nIgnoreMaskLabel , const IIndexArr & views ) ;
bool FaceViewSelection ( unsigned minCommonCameras , float fOutlierThreshold , float fRatioDataSmoothness , int nIgnoreMaskLabel , const IIndexArr & views ) ;
bool FaceViewSelection2 ( unsigned minCommonCameras , float fOutlierThreshold , float fRatioDataSmoothness , int nIgnoreMaskLabel , const IIndexArr & views ) ;
bool FaceViewSelection2 ( unsigned minCommonCameras , float fOutlierThreshold , float fRatioDataSmoothness , int nIgnoreMaskLabel , const IIndexArr & views ) ;
bool FaceViewSelection3 ( unsigned minCommonCameras , float fOutlierThreshold , float fRatioDataSmoothness , int nIgnoreMaskLabel , const IIndexArr & views ) ;
bool FaceViewSelection3 ( unsigned minCommonCameras , float fOutlierThreshold , float fRatioDataSmoothness , int nIgnoreMaskLabel , const IIndexArr & views , bool bUseExistingUV ) ;
bool FaceViewSelection4 ( unsigned minCommonCameras , float fOutlierThreshold , float fRatioDataSmoothness , int nIgnoreMaskLabel , const IIndexArr & views , const Mesh : : FaceIdxArr * faceIndices = nullptr ) ;
bool FaceViewSelection4 ( unsigned minCommonCameras , float fOutlierThreshold , float fRatioDataSmoothness , int nIgnoreMaskLabel , const IIndexArr & views , const Mesh : : FaceIdxArr * faceIndices = nullptr ) ;
void CreateAdaptiveVirtualFaces ( FaceDataViewArr & facesDatas , FaceDataViewArr & virtualFacesDatas , VirtualFaceIdxsArr & virtualFaces , unsigned minCommonCameras ) ;
void CreateAdaptiveVirtualFaces ( FaceDataViewArr & facesDatas , FaceDataViewArr & virtualFacesDatas , VirtualFaceIdxsArr & virtualFaces , unsigned minCommonCameras ) ;
bool ShouldMergeVirtualFace ( const MeshTexture : : FaceDataViewArr & facesDatas , const Mesh : : FaceIdxArr & currentVirtualFace , FIndex candidateFace , unsigned minCommonCameras ) ;
bool ShouldMergeVirtualFace ( const MeshTexture : : FaceDataViewArr & facesDatas , const Mesh : : FaceIdxArr & currentVirtualFace , FIndex candidateFace , unsigned minCommonCameras ) ;
@ -474,9 +474,21 @@ public:
void GlobalSeamLeveling3 ( ) ;
void GlobalSeamLeveling3 ( ) ;
void LocalSeamLeveling ( ) ;
void LocalSeamLeveling ( ) ;
void LocalSeamLeveling3 ( ) ;
void LocalSeamLeveling3 ( ) ;
void GenerateTexture ( bool bGlobalSeamLeveling , bool bLocalSeamLeveling , unsigned nTextureSizeMultiple , unsigned nRectPackingHeuristic , Pixel8U colEmpty , float fSharpnessWeight , int maxTextureSize , const SEACAVE : : String & baseFileName , bool bOriginFaceview ) ;
void GenerateTexture2 ( bool bGlobalSeamLeveling , bool bLocalSeamLeveling , unsigned nTextureSizeMultiple , unsigned nRectPackingHeuristic , Pixel8U colEmpty , float fSharpnessWeight , int maxTextureSize , const SEACAVE : : String & baseFileName ) ;
void GlobalSeamLevelingExternalUV ( ) ;
void LocalSeamLevelingExternalUV ( ) ;
void GenerateTexture ( bool bGlobalSeamLeveling , bool bLocalSeamLeveling , unsigned nTextureSizeMultiple , unsigned nRectPackingHeuristic , Pixel8U colEmpty , float fSharpnessWeight , int maxTextureSize , const SEACAVE : : String & baseFileName , bool bOriginFaceview , Scene * pScene ) ;
void GenerateTexture2 ( bool bGlobalSeamLeveling , bool bLocalSeamLeveling , unsigned nTextureSizeMultiple , unsigned nRectPackingHeuristic , Pixel8U colEmpty , float fSharpnessWeight , int maxTextureSize , const SEACAVE : : String & baseFileName ) ;
bool TextureWithExistingUV ( const IIndexArr & views , int nIgnoreMaskLabel , float fOutlierThreshold , unsigned nTextureSizeMultiple , Pixel8U colEmpty , float fSharpnessWeight ) ;
Mesh : : Image8U3Arr GenerateTextureAtlasFromUV ( const LabelArr & faceLabels , const IIndexArr & views , unsigned nTextureSizeMultiple , Pixel8U colEmpty , float fSharpnessWeight ) ;
Point2f ProjectPointWithAutoCorrection ( const Camera & camera , const Vertex & worldPoint , const Image & sourceImage ) ;
Point2f ProjectPointRobust ( const Camera & camera , const Vertex & worldPoint , const Image & sourceImage , float searchRadius = 0.02f ) ;
bool ValidateProjection ( const Vertex & worldPoint , const Image & sourceImage , Point2f imgPoint , float maxReprojectionError = 1.5f ) ;
Pixel8U SampleImageBilinear ( const Image8U3 & image , const Point2f & point ) ;
void ProjectFaceToTexture ( FIndex faceID , IIndex viewID , const TexCoord * uv , Image8U3 & texture ) ;
bool PointInTriangle ( const Point2f & p , const Point2f & a , const Point2f & b , const Point2f & c , Point3f & bary ) ;
int ComputeOptimalTextureSize ( const Point2f & uvMin , const Point2f & uvMax , unsigned nTextureSizeMultiple ) ;
// Bruce
// Bruce
//*
//*
template < typename PIXEL >
template < typename PIXEL >
@ -764,8 +776,9 @@ void MeshTexture::ComputeFaceCurvatures() const {
// extract array of triangles incident to each vertex
// extract array of triangles incident to each vertex
// and check each vertex if it is at the boundary or not
// and check each vertex if it is at the boundary or not
void MeshTexture : : ListVertexFaces ( )
void MeshTexture : : ListVertexFaces ( bool bUseExistingUV )
{
{
// if (!bUseExistingUV)
scene . mesh . EmptyExtra ( ) ;
scene . mesh . EmptyExtra ( ) ;
scene . mesh . ListIncidenteFaces ( ) ;
scene . mesh . ListIncidenteFaces ( ) ;
scene . mesh . ListBoundaryVertices ( ) ;
scene . mesh . ListBoundaryVertices ( ) ;
@ -6067,10 +6080,10 @@ bool MeshTexture::ShouldMergeVirtualFace(
// return false;
// return false;
}
}
bool MeshTexture : : FaceViewSelection3 ( unsigned minCommonCameras , float fOutlierThreshold , float fRatioDataSmoothness , int nIgnoreMaskLabel , const IIndexArr & views )
bool MeshTexture : : FaceViewSelection3 ( unsigned minCommonCameras , float fOutlierThreshold , float fRatioDataSmoothness , int nIgnoreMaskLabel , const IIndexArr & views , bool bUseExistingUV )
{
{
// extract array of triangles incident to each vertex
// extract array of triangles incident to each vertex
ListVertexFaces ( ) ;
ListVertexFaces ( bUseExistingUV ) ;
// create texture patches
// create texture patches
{
{
@ -7156,6 +7169,7 @@ bool MeshTexture::FaceViewSelection3( unsigned minCommonCameras, float fOutlierT
mapIdxPatch . Insert ( numPatches ) ;
mapIdxPatch . Insert ( numPatches ) ;
}
}
}
}
return true ;
return true ;
}
}
@ -8330,8 +8344,16 @@ void MeshTexture::LocalSeamLeveling3()
}
}
}
}
void MeshTexture : : GenerateTexture ( bool bGlobalSeamLeveling , bool bLocalSeamLeveling , unsigned nTextureSizeMultiple , unsigned nRectPackingHeuristic , Pixel8U colEmpty , float fSharpnessWeight , int maxTextureSize , const SEACAVE : : String & basename , bool bOriginFaceview )
void MeshTexture : : GenerateTexture ( bool bGlobalSeamLeveling , bool bLocalSeamLeveling , unsigned nTextureSizeMultiple , unsigned nRectPackingHeuristic , Pixel8U colEmpty , float fSharpnessWeight , int maxTextureSize , const SEACAVE : : String & basename , bool bOriginFaceview , Scene * pScene )
{
{
bool bUseExternalUV = false ;
if ( ! pScene - > mesh . faceTexcoords . empty ( ) & & pScene - > mesh . faceTexcoords . size ( ) = = pScene - > mesh . faces . size ( ) * 3 ) {
bUseExternalUV = true ;
DEBUG_EXTRA ( " 使用外部UV数据,跳过自动UV生成流程 " ) ;
}
DEBUG_EXTRA ( " GenerateTexture bUseExternalUV=%b " , bUseExternalUV ) ;
// Bruce
// Bruce
// bGlobalSeamLeveling = false;
// bGlobalSeamLeveling = false;
// bLocalSeamLeveling = false;
// bLocalSeamLeveling = false;
@ -8340,11 +8362,19 @@ void MeshTexture::GenerateTexture(bool bGlobalSeamLeveling, bool bLocalSeamLevel
int border = 2 ;
int border = 2 ;
if ( ! bOriginFaceview )
if ( ! bOriginFaceview )
border = 4 ;
border = 4 ;
// ===== 修改:只在非外部UV模式下初始化faceTexcoords =====
if ( ! bUseExternalUV ) {
faceTexcoords . resize ( faces . size ( ) * 3 ) ;
faceTexcoords . resize ( faces . size ( ) * 3 ) ;
faceTexindices . resize ( faces . size ( ) ) ;
faceTexindices . resize ( faces . size ( ) ) ;
}
# ifdef TEXOPT_USE_OPENMP
# ifdef TEXOPT_USE_OPENMP
// LOG_OUT() << "def TEXOPT_USE_OPENMP" << std::endl;
// LOG_OUT() << "def TEXOPT_USE_OPENMP" << std::endl;
const unsigned numPatches ( texturePatches . size ( ) - 1 ) ;
const unsigned numPatches ( texturePatches . size ( ) - 1 ) ;
// ===== 修改:只在非外部UV模式下执行投影计算 =====
if ( ! bUseExternalUV ) {
# pragma omp parallel for schedule(dynamic)
# pragma omp parallel for schedule(dynamic)
for ( int_t idx = 0 ; idx < ( int_t ) numPatches ; + + idx ) {
for ( int_t idx = 0 ; idx < ( int_t ) numPatches ; + + idx ) {
TexturePatch & texturePatch = texturePatches [ ( uint32_t ) idx ] ;
TexturePatch & texturePatch = texturePatches [ ( uint32_t ) idx ] ;
@ -8361,6 +8391,31 @@ void MeshTexture::GenerateTexture(bool bGlobalSeamLeveling, bool bLocalSeamLevel
texcoords [ i ] = imageData . camera . ProjectPointP ( vertices [ face [ i ] ] ) ;
texcoords [ i ] = imageData . camera . ProjectPointP ( vertices [ face [ i ] ] ) ;
ASSERT ( imageData . image . isInsideWithBorder ( texcoords [ i ] , border ) ) ;
ASSERT ( imageData . image . isInsideWithBorder ( texcoords [ i ] , border ) ) ;
aabb . InsertFull ( texcoords [ i ] ) ;
aabb . InsertFull ( texcoords [ i ] ) ;
if ( false )
{
const Point2f & a = texcoords [ 0 ] ;
const Point2f & b = texcoords [ 1 ] ;
const Point2f & c = texcoords [ 2 ] ;
// 计算边向量
Point2f v0 = b - a ;
Point2f v1 = c - a ;
float denom = ( v0 . x * v0 . x + v0 . y * v0 . y ) * ( v1 . x * v1 . x + v1 . y * v1 . y ) -
std : : pow ( v0 . x * v1 . x + v0 . y * v1 . y , 2 ) ;
// 处理退化三角形情况(面积接近0)
const float epsilon = 1e-6 f ;
if ( std : : abs ( denom ) < epsilon )
{
// DEBUG_EXTRA("PointInTriangle - Degenerate triangle, denom=%.10f", denom);
}
else
{
DEBUG_EXTRA ( " PointInTriangle Yes idxFace=%d " , idxFace ) ;
}
}
}
}
}
}
// compute relative texture coordinates
// compute relative texture coordinates
@ -8415,9 +8470,41 @@ void MeshTexture::GenerateTexture(bool bGlobalSeamLeveling, bool bLocalSeamLevel
for ( const FIndex idxFace : texturePatch . faces ) {
for ( const FIndex idxFace : texturePatch . faces ) {
TexCoord * texcoords = faceTexcoords . data ( ) + idxFace * 3 ;
TexCoord * texcoords = faceTexcoords . data ( ) + idxFace * 3 ;
for ( int v = 0 ; v < 3 ; + + v )
for ( int v = 0 ; v < 3 ; + + v )
{
texcoords [ v ] - = offset ;
texcoords [ v ] - = offset ;
if ( false )
{
const Point2f & a = texcoords [ 0 ] ;
const Point2f & b = texcoords [ 1 ] ;
const Point2f & c = texcoords [ 2 ] ;
// 计算边向量
Point2f v0 = b - a ;
Point2f v1 = c - a ;
float denom = ( v0 . x * v0 . x + v0 . y * v0 . y ) * ( v1 . x * v1 . x + v1 . y * v1 . y ) -
std : : pow ( v0 . x * v1 . x + v0 . y * v1 . y , 2 ) ;
// 处理退化三角形情况(面积接近0)
const float epsilon = 1e-6 f ;
if ( std : : abs ( denom ) < epsilon )
{
// DEBUG_EXTRA("PointInTriangle - Degenerate triangle, denom=%.10f", denom);
}
else
{
// DEBUG_EXTRA("PointInTriangle Yes idxFace=%d", idxFace);
}
}
}
}
}
}
}
}
// ===== 修改:只在非外部UV模式下初始化最后一个patch =====
if ( ! bUseExternalUV )
{
{
// init last patch to point to a small uniform color patch
// init last patch to point to a small uniform color patch
TexturePatch & texturePatch = texturePatches . back ( ) ;
TexturePatch & texturePatch = texturePatches . back ( ) ;
@ -8442,7 +8529,12 @@ void MeshTexture::GenerateTexture(bool bGlobalSeamLeveling, bool bLocalSeamLevel
// perform global seam leveling
// perform global seam leveling
if ( bGlobalSeamLeveling ) {
if ( bGlobalSeamLeveling ) {
TD_TIMER_STARTD ( ) ;
TD_TIMER_STARTD ( ) ;
if ( bUseExternalUV ) {
// 外部UV数据可能需要更温和的接缝处理
GlobalSeamLevelingExternalUV ( ) ;
} else {
GlobalSeamLeveling3 ( ) ;
GlobalSeamLeveling3 ( ) ;
}
DEBUG_EXTRA ( " \t global seam leveling completed (%s) " , TD_TIMER_GET_FMT ( ) . c_str ( ) ) ;
DEBUG_EXTRA ( " \t global seam leveling completed (%s) " , TD_TIMER_GET_FMT ( ) . c_str ( ) ) ;
}
}
@ -8450,12 +8542,20 @@ void MeshTexture::GenerateTexture(bool bGlobalSeamLeveling, bool bLocalSeamLevel
if ( bLocalSeamLeveling ) {
if ( bLocalSeamLeveling ) {
TD_TIMER_STARTD ( ) ;
TD_TIMER_STARTD ( ) ;
// LocalSeamLeveling();
// LocalSeamLeveling();
if ( bUseExternalUV ) {
// 外部UV数据可能需要不同的局部接缝处理
LocalSeamLevelingExternalUV ( ) ;
} else {
LocalSeamLeveling3 ( ) ;
LocalSeamLeveling3 ( ) ;
}
DEBUG_EXTRA ( " \t local seam leveling completed (%s) " , TD_TIMER_GET_FMT ( ) . c_str ( ) ) ;
DEBUG_EXTRA ( " \t local seam leveling completed (%s) " , TD_TIMER_GET_FMT ( ) . c_str ( ) ) ;
}
}
}
}
DEBUG_EXTRA ( " seam (%s) " , TD_TIMER_GET_FMT ( ) . c_str ( ) ) ;
DEBUG_EXTRA ( " seam (%s) " , TD_TIMER_GET_FMT ( ) . c_str ( ) ) ;
// ===== 修改:纹理块合并逻辑调整 =====
// 外部UV数据可能需要跳过纹理块合并,因为UV已经固定
if ( ! bUseExternalUV ) {
// merge texture patches with overlapping rectangles
// merge texture patches with overlapping rectangles
for ( unsigned i = 0 ; i < texturePatches . size ( ) - 1 ; + + i ) {
for ( unsigned i = 0 ; i < texturePatches . size ( ) - 1 ; + + i ) {
TexturePatch & texturePatchBig = texturePatches [ i ] ;
TexturePatch & texturePatchBig = texturePatches [ i ] ;
@ -8480,6 +8580,7 @@ void MeshTexture::GenerateTexture(bool bGlobalSeamLeveling, bool bLocalSeamLevel
texturePatches . RemoveAtMove ( j - - ) ;
texturePatches . RemoveAtMove ( j - - ) ;
}
}
}
}
}
LOG_OUT ( ) < < " Second loop completed " < < std : : endl ;
LOG_OUT ( ) < < " Second loop completed " < < std : : endl ;
// create texture
// create texture
@ -8518,6 +8619,19 @@ void MeshTexture::GenerateTexture(bool bGlobalSeamLeveling, bool bLocalSeamLevel
typeHeuristic = 1 ;
typeHeuristic = 1 ;
}
}
int textureSize = 0 ;
int textureSize = 0 ;
if ( bUseExternalUV ) {
// 对于外部UV数据,直接使用现有的纹理坐标,跳过复杂的打包流程
DEBUG_EXTRA ( " 使用外部UV数据,简化纹理图集生成流程 " ) ;
// 创建单个纹理图集
textureSize = maxTextureSize > 0 ? maxTextureSize : 4096 ; // 默认大小
texturesDiffuse . emplace_back ( textureSize , textureSize ) . setTo ( cv : : Scalar ( colEmpty . b , colEmpty . g , colEmpty . r ) ) ;
// 直接使用现有的faceTexcoords和faceTexindices
// 不需要重新计算纹理坐标偏移
DEBUG_EXTRA ( " 外部UV纹理映射完成: 使用现有UV坐标 " ) ;
} else {
while ( ! unplacedRects . empty ( ) ) {
while ( ! unplacedRects . empty ( ) ) {
TD_TIMER_STARTD ( ) ;
TD_TIMER_STARTD ( ) ;
if ( textureSize = = 0 ) {
if ( textureSize = = 0 ) {
@ -8560,8 +8674,11 @@ void MeshTexture::GenerateTexture(bool bGlobalSeamLeveling, bool bLocalSeamLevel
}
}
}
}
}
}
}
LOG_OUT ( ) < < " Third loop completed " < < std : : endl ;
LOG_OUT ( ) < < " Third loop completed " < < std : : endl ;
Mesh : : FaceIdxArr emptyFaceIndexes ;
Mesh : : FaceIdxArr emptyFaceIndexes ;
if ( ! bUseExternalUV ) {
# ifdef TEXOPT_USE_OPENMP
# ifdef TEXOPT_USE_OPENMP
# pragma omp parallel for schedule(dynamic)
# pragma omp parallel for schedule(dynamic)
@ -8646,6 +8763,10 @@ void MeshTexture::GenerateTexture(bool bGlobalSeamLeveling, bool bLocalSeamLevel
}
}
}
}
}
}
} else {
// 外部UV数据:直接使用现有的纹理坐标,不需要重新计算
DEBUG_EXTRA ( " 跳过自动颜色采样,使用外部UV坐标 " ) ;
}
if ( texturesDiffuse . size ( ) = = 1 )
if ( texturesDiffuse . size ( ) = = 1 )
faceTexindices . Release ( ) ;
faceTexindices . Release ( ) ;
@ -8710,6 +8831,18 @@ void MeshTexture::GenerateTexture(bool bGlobalSeamLeveling, bool bLocalSeamLevel
}
}
}
}
void MeshTexture : : GlobalSeamLevelingExternalUV ( )
{
// 针对外部UV数据的全局接缝处理
// 实现更温和的接缝处理算法
}
void MeshTexture : : LocalSeamLevelingExternalUV ( )
{
// 针对外部UV数据的局部接缝处理
// 实现保留原始UV特征的接缝处理
}
// New
// New
void MeshTexture : : GlobalSeamLeveling ( )
void MeshTexture : : GlobalSeamLeveling ( )
{
{
@ -9400,6 +9533,601 @@ void MeshTexture::GenerateTexture2(bool bGlobalSeamLeveling, bool bLocalSeamLeve
}
}
}
}
# include <opencv2/imgcodecs.hpp>
// 保存生成的纹理图集
bool SaveGeneratedTextures ( const Mesh : : Image8U3Arr & generatedTextures , const std : : string & outputDir ) {
if ( generatedTextures . empty ( ) ) {
DEBUG_EXTRA ( " 错误: 没有纹理可保存 " ) ;
return false ;
}
// 确保输出目录存在
# ifdef _WIN32
_mkdir ( outputDir . c_str ( ) ) ;
# else
mkdir ( outputDir . c_str ( ) , 0755 ) ;
# endif
// 保存所有纹理
for ( size_t i = 0 ; i < generatedTextures . size ( ) ; + + i ) {
if ( generatedTextures [ i ] . empty ( ) ) {
DEBUG_EXTRA ( " 警告: 纹理 %zu 为空,跳过保存 " , i ) ;
continue ;
}
// 生成文件名
std : : string filename = outputDir + " /texture_ " + std : : to_string ( i ) + " .png " ;
// 使用OpenCV保存图像
if ( cv : : imwrite ( filename , generatedTextures [ i ] ) ) {
DEBUG_EXTRA ( " 成功保存纹理: %s (尺寸: %dx%d) " ,
filename . c_str ( ) ,
generatedTextures [ i ] . cols ,
generatedTextures [ i ] . rows ) ;
} else {
DEBUG_EXTRA ( " 错误: 无法保存纹理到 %s " , filename . c_str ( ) ) ;
return false ;
}
}
return true ;
}
bool MeshTexture : : TextureWithExistingUV ( const IIndexArr & views , int nIgnoreMaskLabel , float fOutlierThreshold , unsigned nTextureSizeMultiple , Pixel8U colEmpty , float fSharpnessWeight )
{
DEBUG_EXTRA ( " TextureWithExistingUV 1 " ) ;
TD_TIMER_START ( ) ;
// 1. 验证输入
if ( scene . mesh . faceTexcoords . empty ( ) ) {
VERBOSE ( " error: mesh does not contain UV coordinates " ) ;
return false ;
}
if ( scene . mesh . faceTexcoords . size ( ) ! = scene . mesh . faces . size ( ) * 3 ) {
VERBOSE ( " error: UV coordinates count does not match face count, %d, %d " , scene . mesh . faceTexcoords . size ( ) , scene . mesh . faces . size ( ) * 3 ) ;
return false ;
}
DEBUG_EXTRA ( " TextureWithExistingUV 2 " ) ;
// 2. 为每个面选择最佳视图
FaceDataViewArr facesDatas ;
if ( ! ListCameraFaces ( facesDatas , fOutlierThreshold , nIgnoreMaskLabel , views , false ) ) {
return false ;
}
DEBUG_EXTRA ( " TextureWithExistingUV 3 faceSize=%d " , scene . mesh . faces . size ( ) ) ;
// 3. 直接使用现有UV坐标,跳过视图选择优化
// 为每个面分配最佳视图
LabelArr faceLabels ( scene . mesh . faces . size ( ) ) ;
FOREACH ( idxFace , scene . mesh . faces ) {
const FaceDataArr & faceDatas = facesDatas [ idxFace ] ;
if ( faceDatas . empty ( ) ) {
// DEBUG_EXTRA("TextureWithExistingUV %d", idxFace);
faceLabels [ idxFace ] = 0 ; // 无视图可用
continue ;
}
// DEBUG_EXTRA("TextureWithExistingUV 4");
// 选择质量最高的视图
float bestQuality = - 1 ;
IIndex bestView = NO_ID ;
for ( const FaceData & data : faceDatas ) {
if ( data . quality > bestQuality & & ! data . bInvalidFacesRelative ) {
bestQuality = data . quality ;
bestView = data . idxView ;
}
}
faceLabels [ idxFace ] = ( bestView ! = NO_ID ) ? ( bestView + 1 ) : 0 ;
}
// 4. 生成纹理图集
Mesh : : Image8U3Arr generatedTextures = GenerateTextureAtlasFromUV ( faceLabels , views , nTextureSizeMultiple , colEmpty , fSharpnessWeight ) ;
if ( ! generatedTextures . empty ( ) ) {
scene . mesh . texturesDiffuse = std : : move ( generatedTextures ) ;
// 同时设置面的纹理索引
scene . mesh . faceTexindices . resize ( scene . mesh . faces . size ( ) ) ;
DEBUG_EXTRA ( " 成功生成 %zu 个纹理,已赋值给 mesh " , scene . mesh . texturesDiffuse . size ( ) ) ;
// 🆕 保存纹理到文件
std : : string outputDir = " texture_output " ;
if ( SaveGeneratedTextures ( scene . mesh . texturesDiffuse , outputDir ) ) {
DEBUG_EXTRA ( " 纹理已成功保存到目录: %s " , outputDir . c_str ( ) ) ;
}
return true ;
}
DEBUG_EXTRA ( " 纹理生成失败 " ) ;
return false ;
}
Point2f MeshTexture : : ProjectPointWithAutoCorrection ( const Camera & camera , const Vertex & worldPoint , const Image & sourceImage ) {
Point2f imgPoint = camera . ProjectPointP ( worldPoint ) ;
// 检查投影点是否在有效范围内
if ( ! sourceImage . image . isInside ( imgPoint ) ) {
// 尝试不同的偏移量来找到最佳投影点
std : : vector < Point2f > testOffsets = {
Point2f ( 0 , sourceImage . image . rows * 0.015f ) , // 当前使用的偏移
Point2f ( 0 , - sourceImage . image . rows * 0.015f ) , // 反向偏移
Point2f ( sourceImage . image . cols * 0.015f , 0 ) , // 水平偏移
Point2f ( 0 , 0 ) // 无偏移
} ;
for ( const auto & offset : testOffsets ) {
Point2f testPoint = imgPoint + offset ;
if ( sourceImage . image . isInside ( testPoint ) & & camera . IsInFront ( worldPoint ) ) {
return testPoint ;
}
}
}
return imgPoint ;
}
Point2f MeshTexture : : ProjectPointRobust ( const Camera & camera , const Vertex & worldPoint ,
const Image & sourceImage , float searchRadius ) {
Point2f imgPoint = camera . ProjectPointP ( worldPoint ) ;
// 如果投影点有效,直接返回
if ( sourceImage . image . isInside ( imgPoint ) & & camera . IsInFront ( worldPoint ) ) {
return imgPoint ;
}
// 在投影点周围搜索最佳匹配点
int searchSteps = 5 ;
float stepSize = searchRadius * sourceImage . image . rows / searchSteps ;
// 在y方向进行搜索(主要偏差方向)
for ( int dy = - searchSteps ; dy < = searchSteps ; + + dy ) {
Point2f testPoint = imgPoint + Point2f ( 0 , dy * stepSize ) ;
if ( sourceImage . image . isInside ( testPoint ) & & camera . IsInFront ( worldPoint ) ) {
// 可选:进一步验证这个点是否在面片边界内
return testPoint ;
}
}
// 如果在y方向没找到,尝试x方向
for ( int dx = - searchSteps ; dx < = searchSteps ; + + dx ) {
Point2f testPoint = imgPoint + Point2f ( dx * stepSize , 0 ) ;
if ( sourceImage . image . isInside ( testPoint ) & & camera . IsInFront ( worldPoint ) ) {
return testPoint ;
}
}
// 如果都没找到,返回原始投影点(后续会跳过)
return imgPoint ;
}
Mesh : : Image8U3Arr MeshTexture : : GenerateTextureAtlasFromUV ( const LabelArr & faceLabels , const IIndexArr & views ,
unsigned nTextureSizeMultiple , Pixel8U colEmpty , float fSharpnessWeight )
{
// 1. 分析整个模型的UV布局
AABB2f uvBounds ( true ) ;
FOREACH ( i , scene . mesh . faceTexcoords ) {
const TexCoord & uv = scene . mesh . faceTexcoords [ i ] ;
uvBounds . InsertFull ( uv ) ;
}
// 2. 根据UV范围确定纹理图集尺寸
const int textureSize = ComputeOptimalTextureSize ( uvBounds . ptMin , uvBounds . ptMax , nTextureSizeMultiple ) ;
// 3. 创建单个纹理图集
Mesh : : Image8U3Arr textures ;
Image8U3 & textureAtlas = textures . emplace_back ( textureSize , textureSize ) ;
textureAtlas . setTo ( cv : : Scalar ( colEmpty . b , colEmpty . g , colEmpty . r ) ) ;
DEBUG_EXTRA ( " 生成纹理图集: 尺寸=%dx%d, UV范围=[%.3f,%.3f]-[%.3f,%.3f] " ,
textureSize , textureSize ,
uvBounds . ptMin . x ( ) , uvBounds . ptMin . y ( ) , uvBounds . ptMax . x ( ) , uvBounds . ptMax . y ( ) ) ;
// 4. 为每个面片采样颜色并填充纹理图集
# ifdef _USE_OPENMP
# pragma omp parallel for schedule(dynamic)
for ( int_t idxFace = 0 ; idxFace < ( int_t ) scene . mesh . faces . size ( ) ; + + idxFace ) {
# else
FOREACH ( idxFace , scene . mesh . faces ) {
# endif
const FIndex faceID = ( FIndex ) idxFace ;
const Label label = faceLabels [ faceID ] ;
if ( label = = 0 ) continue ; // 跳过无视图的面片
const IIndex idxView = label - 1 ;
if ( idxView > = images . size ( ) ) continue ;
// 获取面的UV坐标和几何信息
const TexCoord * uvCoords = & scene . mesh . faceTexcoords [ faceID * 3 ] ;
const Face & face = scene . mesh . faces [ faceID ] ;
const Image & sourceImage = images [ idxView ] ;
// 计算面片在纹理图集中的边界框
AABB2f faceUVBounds ( true ) ;
for ( int i = 0 ; i < 3 ; + + i ) {
faceUVBounds . InsertFull ( uvCoords [ i ] ) ;
}
// 将UV坐标转换到纹理像素坐标
const int startX = std : : max ( 0 , ( int ) ( faceUVBounds . ptMin . x ( ) * textureSize ) ) ;
const int startY = std : : max ( 0 , ( int ) ( faceUVBounds . ptMin . y ( ) * textureSize ) ) ;
const int endX = std : : min ( textureSize - 1 , ( int ) ( faceUVBounds . ptMax . x ( ) * textureSize ) ) ;
const int endY = std : : min ( textureSize - 1 , ( int ) ( faceUVBounds . ptMax . y ( ) * textureSize ) ) ;
// 对面片覆盖的每个纹理像素进行采样
for ( int y = startY ; y < = endY ; + + y ) {
for ( int x = startX ; x < = endX ; + + x ) {
const Point2f texCoord ( ( float ) x / textureSize , ( float ) y / textureSize ) ;
// 检查点是否在三角形内
Point3f barycentric ;
if ( ! PointInTriangle ( texCoord , uvCoords [ 0 ] , uvCoords [ 1 ] , uvCoords [ 2 ] , barycentric ) ) {
continue ;
}
// 计算3D空间中的对应点
const Vertex worldPoint =
vertices [ face [ 0 ] ] * barycentric . x +
vertices [ face [ 1 ] ] * barycentric . y +
vertices [ face [ 2 ] ] * barycentric . z ;
// 将3D点投影到源图像
// Point2f imgPoint = sourceImage.camera.ProjectPointP(worldPoint);
// Point2f imgPoint = ProjectPointRobust(sourceImage.camera, worldPoint, sourceImage, 0.02f);
Point2f imgPoint = ProjectPointWithAutoCorrection ( sourceImage . camera , worldPoint , sourceImage ) ;
if ( ! ValidateProjection ( worldPoint , sourceImage , imgPoint ) )
{
continue ; // 跳过几何不一致的采样点
}
if ( imgPoint . x < - 100 | | imgPoint . x > sourceImage . image . cols + 100 | |
imgPoint . y < - 100 | | imgPoint . y > sourceImage . image . rows + 100 ) {
// 投影异常,记录日志用于调试
DEBUG_EXTRA ( " 异常投影: 图像点(%.1f,%.1f) 超出图像范围(%dx%d) " ,
imgPoint . x , imgPoint . y , sourceImage . image . cols , sourceImage . image . rows ) ;
}
// imgPoint.y += sourceImage.image.rows * 0.015f;
// 检查投影有效性
if ( ! sourceImage . image . isInside ( imgPoint ) | |
! sourceImage . camera . IsInFront ( worldPoint ) ) {
continue ;
}
// 从源图像采样颜色(使用双线性插值)
Pixel8U sampledColor = SampleImageBilinear ( sourceImage . image , imgPoint ) ;
// 将采样颜色写入纹理图集
# ifdef _USE_OPENMP
# pragma omp critical
# endif
{
textureAtlas ( y , x ) = sampledColor ;
}
}
}
}
// 5. 应用后处理
if ( fSharpnessWeight > 0 ) {
// ApplySharpening(textureAtlas, fSharpnessWeight);
}
// 6. 填充空白区域(使用邻近像素扩散)
// FillEmptyRegions(textureAtlas, colEmpty);
DEBUG_EXTRA ( " 纹理图集生成完成: %u个面片, 纹理尺寸%dx%d " ,
scene . mesh . faces . size ( ) , textureSize , textureSize ) ;
return textures ;
}
bool MeshTexture : : ValidateProjection ( const Vertex & worldPoint ,
const Image & sourceImage , Point2f imgPoint ,
float maxReprojectionError ) {
// 1. 前向投影:3D点 → 2D图像坐标
Point2f projectedPoint = sourceImage . camera . ProjectPointP ( worldPoint ) ;
// 2. 计算重投影误差
float reprojectionError = norm ( projectedPoint - imgPoint ) ;
// 3. 设置误差阈值
if ( reprojectionError > maxReprojectionError ) {
DEBUG_EXTRA ( " 重投影误差过大: %.3f像素,跳过该采样点 " , reprojectionError ) ;
return false ;
}
// 4. 视线方向一致性检查
if ( ! sourceImage . camera . IsInFront ( worldPoint ) ) {
DEBUG_EXTRA ( " 点位于相机后方,跳过 " ) ;
return false ;
}
return true ;
}
Pixel8U MeshTexture : : SampleImageBilinear ( const Image8U3 & image , const Point2f & point ) {
const int x1 = ( int ) point . x ;
const int y1 = ( int ) point . y ;
const int x2 = std : : min ( x1 + 1 , image . cols - 1 ) ;
const int y2 = std : : min ( y1 + 1 , image . rows - 1 ) ;
const float dx = point . x - x1 ;
const float dy = point . y - y1 ;
const Pixel8U & p11 = image ( y1 , x1 ) ;
const Pixel8U & p12 = image ( y1 , x2 ) ;
const Pixel8U & p21 = image ( y2 , x1 ) ;
const Pixel8U & p22 = image ( y2 , x2 ) ;
Pixel8U result ;
for ( int i = 0 ; i < 3 ; + + i ) {
result [ i ] = ( uint8_t ) (
p11 [ i ] * ( 1 - dx ) * ( 1 - dy ) +
p12 [ i ] * dx * ( 1 - dy ) +
p21 [ i ] * ( 1 - dx ) * dy +
p22 [ i ] * dx * dy
) ;
}
return result ;
}
void MeshTexture : : ProjectFaceToTexture ( FIndex faceID , IIndex viewID ,
const TexCoord * uv , Image8U3 & texture )
{
// DEBUG_EXTRA("ProjectFaceToTexture 1");
const Image & image = images [ viewID ] ;
const Face & face = scene . mesh . faces [ faceID ] ;
// 计算面的包围盒(在纹理空间中)
Point2f minUV ( FLT_MAX , FLT_MAX ) , maxUV ( FLT_MIN , FLT_MIN ) ;
for ( int i = 0 ; i < 3 ; + + i ) {
minUV . x = MIN ( minUV . x , uv [ i ] . x ) ;
minUV . y = MIN ( minUV . y , uv [ i ] . y ) ;
maxUV . x = MAX ( maxUV . x , uv [ i ] . x ) ;
maxUV . y = MAX ( maxUV . y , uv [ i ] . y ) ;
}
// 将UV坐标转换到纹理像素坐标
const int texWidth = texture . cols ;
const int texHeight = texture . rows ;
const int startX = MAX ( 0 , ( int ) ( minUV . x * texWidth ) ) ;
const int startY = MAX ( 0 , ( int ) ( minUV . y * texHeight ) ) ;
const int endX = MIN ( texWidth - 1 , ( int ) ( maxUV . x * texWidth ) ) ;
const int endY = MIN ( texHeight - 1 , ( int ) ( maxUV . y * texHeight ) ) ;
// 对纹理中的每个像素进行采样
for ( int y = startY ; y < = endY ; + + y ) {
for ( int x = startX ; x < = endX ; + + x ) {
// 将像素坐标转换回UV坐标
const Point2f texCoord ( ( float ) x / texWidth , ( float ) y / texHeight ) ;
// DEBUG_EXTRA("ProjectFaceToTexture1 %d", x);
// 检查点是否在三角形内[6,8](@ref)
Point3f bary ;
if ( ! PointInTriangle ( texCoord , uv [ 0 ] , uv [ 1 ] , uv [ 2 ] , bary ) ) {
continue ;
}
// DEBUG_EXTRA("ProjectFaceToTexture2 %d", x);
// 计算3D空间中的对应点
const Vertex worldPoint =
vertices [ face [ 0 ] ] * bary . x +
vertices [ face [ 1 ] ] * bary . y +
vertices [ face [ 2 ] ] * bary . z ;
// 将3D点投影到图像
Point2f imgPoint ;
// 确保 worldPoint 的类型与相机参数匹配
const TPoint3 < double > worldPointDouble (
static_cast < double > ( worldPoint . x ) ,
static_cast < double > ( worldPoint . y ) ,
static_cast < double > ( worldPoint . z )
) ;
imgPoint = image . camera . ProjectPoint ( worldPointDouble ) ;
// 添加有效性检查
if ( ! image . camera . IsInFront ( worldPoint ) ) {
continue ; // 点不在相机前方,跳过
}
// DEBUG_EXTRA("ProjectFaceToTexture3 %d", x);
// 检查投影点是否在图像范围内
if ( ! image . camera . IsInside ( imgPoint , Point2f ( image . width , image . height ) ) ) {
continue ; // 点不在图像内,跳过
}
// DEBUG_EXTRA("ProjectFaceToTexture4 %d", x);
// 检查投影点是否在图像范围内
// 从图像中采样颜色(使用双线性插值)
if ( image . image . isInside ( imgPoint ) ) {
// 获取图像中对应点的颜色[1,4](@ref)
const int imgX = ( int ) imgPoint . x ;
const int imgY = ( int ) imgPoint . y ;
// 边界检查
if ( imgX > = 0 & & imgX < image . image . cols - 1 & &
imgY > = 0 & & imgY < image . image . rows - 1 ) {
// 双线性插值参数
const float dx = imgPoint . x - imgX ;
const float dy = imgPoint . y - imgY ;
const float w1 = ( 1 - dx ) * ( 1 - dy ) ;
const float w2 = dx * ( 1 - dy ) ;
const float w3 = ( 1 - dx ) * dy ;
const float w4 = dx * dy ;
// 获取四个相邻像素的颜色
const Pixel8U & p1 = image . image ( imgY , imgX ) ;
const Pixel8U & p2 = image . image ( imgY , imgX + 1 ) ;
const Pixel8U & p3 = image . image ( imgY + 1 , imgX ) ;
const Pixel8U & p4 = image . image ( imgY + 1 , imgX + 1 ) ;
// 计算加权平均颜色
Pixel8U finalColor ;
finalColor . r = ( uint8_t ) ( p1 . r * w1 + p2 . r * w2 + p3 . r * w3 + p4 . r * w4 ) ;
finalColor . g = ( uint8_t ) ( p1 . g * w1 + p2 . g * w2 + p3 . g * w3 + p4 . g * w4 ) ;
finalColor . b = ( uint8_t ) ( p1 . b * w1 + p2 . b * w2 + p3 . b * w3 + p4 . b * w4 ) ;
// DEBUG_EXTRA("ProjectFaceToTexture5 finalColor=(%d,%d,%d)", finalColor.r, finalColor.g, finalColor.b);
// 将颜色赋给纹理像素[1](@ref)
texture ( y , x ) = finalColor ;
} else {
// 边界情况:使用最近邻插值
const int safeX = std : : min ( std : : max ( 0 , ( int ) imgPoint . x ) , image . image . cols - 1 ) ;
const int safeY = std : : min ( std : : max ( 0 , ( int ) imgPoint . y ) , image . image . rows - 1 ) ;
texture ( y , x ) = image . image ( safeY , safeX ) ;
// DEBUG_EXTRA("ProjectFaceToTexture6 %d", x);
}
}
}
}
}
# include <cmath>
/**
* @ brief 使 用 重 心 坐 标 法 判 断 点 是 否 在 三 角 形 内 , 并 计 算 重 心 坐 标
* @ param p 需 要 判 断 的 点 ( 纹 理 坐 标 空 间 中 的 点 )
* @ param a 三 角 形 的 第 一 个 顶 点
* @ param b 三 角 形 的 第 二 个 顶 点
* @ param c 三 角 形 的 第 三 个 顶 点
* @ param bary 输 出 的 重 心 坐 标 ( 1 - u - v , u , v )
* @ return bool 如 果 点 在 三 角 形 内 返 回 true , 否 则 返 回 false
*/
bool MeshTexture : : PointInTriangle ( const Point2f & p , const Point2f & a , const Point2f & b , const Point2f & c , Point3f & bary )
{
// 添加调试输出
// DEBUG_EXTRA("PointInTriangle - Input: p(%.6f,%.6f), a(%.6f,%.6f), b(%.6f,%.6f), c(%.6f,%.6f)",
// p.x, p.y, a.x, a.y, b.x, b.y, c.x, c.y);
// 检查输入有效性
if ( ! std : : isfinite ( p . x ) | | ! std : : isfinite ( p . y ) | |
! std : : isfinite ( a . x ) | | ! std : : isfinite ( a . y ) | |
! std : : isfinite ( b . x ) | | ! std : : isfinite ( b . y ) | |
! std : : isfinite ( c . x ) | | ! std : : isfinite ( c . y ) ) {
// DEBUG_EXTRA("PointInTriangle - Invalid input coordinates");
return false ;
}
// 计算边向量
Point2f v0 = b - a ;
Point2f v1 = c - a ;
Point2f v2 = p - a ;
// 计算必要的点积
float dot00 = v0 . x * v0 . x + v0 . y * v0 . y ;
float dot01 = v0 . x * v1 . x + v0 . y * v1 . y ;
float dot02 = v0 . x * v2 . x + v0 . y * v2 . y ;
float dot11 = v1 . x * v1 . x + v1 . y * v1 . y ;
float dot12 = v1 . x * v2 . x + v1 . y * v2 . y ;
// 计算分母(三角形平行四边形面积的两倍)
float denom = dot00 * dot11 - dot01 * dot01 ;
// 处理退化三角形情况(面积接近0)
const float epsilon = 1e-10 f ;
if ( std : : abs ( denom ) < epsilon ) {
// DEBUG_EXTRA("PointInTriangle - Degenerate triangle, denom=%.10f", denom);
// return false;
}
// 计算重心坐标参数
float invDenom = 1.0f / denom ;
float u = ( dot11 * dot02 - dot01 * dot12 ) * invDenom ;
float v = ( dot00 * dot12 - dot01 * dot02 ) * invDenom ;
// DEBUG_EXTRA("PointInTriangle - u=%.6f, v=%.6f, u+v=%.6f", u, v, u+v);
// 检查点是否在三角形内(使用更宽松的容差)
if ( u > = - epsilon & & v > = - epsilon & & ( u + v ) < = 1.0f + epsilon ) {
// 点在三角形内,计算完整的重心坐标
bary . x = 1.0f - u - v ;
bary . y = u ;
bary . z = v ;
// DEBUG_EXTRA("PointInTriangle - Point INSIDE triangle, bary(%.3f,%.3f,%.3f)", bary.x, bary.y, bary.z);
return true ;
}
// DEBUG_EXTRA("PointInTriangle - Point OUTSIDE triangle");
return false ;
}
int MeshTexture : : ComputeOptimalTextureSize ( const Point2f & uvMin , const Point2f & uvMax , unsigned nTextureSizeMultiple ) {
// 1. 计算UV坐标的实际覆盖范围
const float uvRangeX = uvMax . x - uvMin . x ;
const float uvRangeY = uvMax . y - uvMin . y ;
// 如果UV范围无效,返回默认尺寸
if ( uvRangeX < = 0.0f | | uvRangeY < = 0.0f ) {
return 1024 ; // 默认回退尺寸
}
// 2. 基于UV覆盖范围计算基础纹理尺寸
// 假设我们希望纹理密度为:每单位UV空间对应N个像素
const float pixelsPerUV = 256.0f ; // 可配置的密度系数
int baseSizeX = static_cast < int > ( uvRangeX * pixelsPerUV ) ;
int baseSizeY = static_cast < int > ( uvRangeY * pixelsPerUV ) ;
// 取较大者作为基础尺寸,以确保覆盖整个UV范围
int baseSize = std : : max ( baseSizeX , baseSizeY ) ;
DEBUG_EXTRA ( " %d, %d " , nTextureSizeMultiple , baseSize ) ;
// 3. 应用纹理尺寸倍数约束
baseSize = ( baseSize + nTextureSizeMultiple - 1 ) / nTextureSizeMultiple * nTextureSizeMultiple ;
// 4. 设备能力限制
int maxTextureSize = 4096 ; // 默认最大值
int minTextureSize = 64 ; // 默认最小值
// 此处可查询设备实际支持的最大纹理尺寸
// glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);
// 5. 质量等级调整(可根据OPT中的质量设置进行调整)
int qualityLevel = 1 ; // 默认中等质量
switch ( qualityLevel ) {
case 0 : // 低质量:缩小纹理尺寸
baseSize = baseSize / 2 ;
break ;
case 1 : // 中等质量:保持原计算尺寸
// baseSize 保持不变
break ;
case 2 : // 高质量:适度增大尺寸(如有足够内存)
baseSize = std : : min ( baseSize * 2 , maxTextureSize ) ;
break ;
}
DEBUG_EXTRA ( " (UV范围: [%.3f, %.3f]), %d, %d, %d " , uvRangeX , uvRangeY , nTextureSizeMultiple , baseSize , minTextureSize ) ;
// 6. 最终钳制到有效范围
baseSize = ( std : : max ) ( minTextureSize , ( std : : min ) ( baseSize , maxTextureSize ) ) ;
// 7. 确保尺寸为2的幂次(兼容性考虑,可选)
int finalSize = 1 ;
while ( finalSize < baseSize ) {
finalSize < < = 1 ;
if ( finalSize > = maxTextureSize ) {
finalSize = maxTextureSize ;
break ;
}
}
DEBUG_EXTRA ( " 计算出的最优纹理尺寸: %d (UV范围: [%.3f, %.3f]) " ,
finalSize , uvRangeX , uvRangeY ) ;
return finalSize ;
}
// 保存遮挡数据到文件
// 保存遮挡数据到文件
void Scene : : SaveVisibleFacesData ( std : : map < std : : string , std : : unordered_set < int > > & visible_faces_map ,
void Scene : : SaveVisibleFacesData ( std : : map < std : : string , std : : unordered_set < int > > & visible_faces_map ,
std : : unordered_set < int > & face_visible_relative ,
std : : unordered_set < int > & face_visible_relative ,
@ -9536,8 +10264,11 @@ bool Scene::LoadVisibleFacesData(std::map<std::string, std::unordered_set<int>>&
bool Scene : : TextureMesh ( unsigned nResolutionLevel , unsigned nMinResolution , unsigned minCommonCameras , float fOutlierThreshold , float fRatioDataSmoothness ,
bool Scene : : TextureMesh ( unsigned nResolutionLevel , unsigned nMinResolution , unsigned minCommonCameras , float fOutlierThreshold , float fRatioDataSmoothness ,
bool bGlobalSeamLeveling , bool bLocalSeamLeveling , unsigned nTextureSizeMultiple , unsigned nRectPackingHeuristic , Pixel8U colEmpty , float fSharpnessWeight ,
bool bGlobalSeamLeveling , bool bLocalSeamLeveling , unsigned nTextureSizeMultiple , unsigned nRectPackingHeuristic , Pixel8U colEmpty , float fSharpnessWeight ,
int nIgnoreMaskLabel , int maxTextureSize , const IIndexArr & views , const SEACAVE : : String & baseFileName , bool bOriginFaceview ,
int nIgnoreMaskLabel , int maxTextureSize , const IIndexArr & views , const SEACAVE : : String & baseFileName , bool bOriginFaceview ,
const std : : string & inputFileName , const std : : string & meshFileName )
const std : : string & inputFileName , const std : : string & meshFileName , bool bUseExistingUV , const std : : string & strUVMeshFileName )
{
{
nTextureSizeMultiple = 8192 ; // 8192 4096
// if (!bOriginFaceview && !bUseExistingUV)
if ( ! bOriginFaceview )
if ( ! bOriginFaceview )
{
{
// 确保网格拓扑结构已计算
// 确保网格拓扑结构已计算
@ -9647,7 +10378,7 @@ bool Scene::TextureMesh(unsigned nResolutionLevel, unsigned nMinResolution, unsi
// if (false)
// if (false)
{
{
TD_TIMER_STARTD ( ) ;
TD_TIMER_STARTD ( ) ;
if ( ! texture . FaceViewSelection3 ( minCommonCameras , fOutlierThreshold , fRatioDataSmoothness , nIgnoreMaskLabel , views ) )
if ( ! texture . FaceViewSelection3 ( minCommonCameras , fOutlierThreshold , fRatioDataSmoothness , nIgnoreMaskLabel , views , bUseExistingUV ) )
return false ;
return false ;
DEBUG_EXTRA ( " First pass (virtual faces) completed: %u faces (%s) " , mesh . faces . size ( ) , TD_TIMER_GET_FMT ( ) . c_str ( ) ) ;
DEBUG_EXTRA ( " First pass (virtual faces) completed: %u faces (%s) " , mesh . faces . size ( ) , TD_TIMER_GET_FMT ( ) . c_str ( ) ) ;
}
}
@ -9689,13 +10420,47 @@ bool Scene::TextureMesh(unsigned nResolutionLevel, unsigned nMinResolution, unsi
DEBUG_EXTRA ( " Assigning the best view to each face completed: %u faces (%s) " , mesh . faces . size ( ) , TD_TIMER_GET_FMT ( ) . c_str ( ) ) ;
DEBUG_EXTRA ( " Assigning the best view to each face completed: %u faces (%s) " , mesh . faces . size ( ) , TD_TIMER_GET_FMT ( ) . c_str ( ) ) ;
}
}
// mesh.CheckUVValid();
DEBUG_EXTRA ( " TextureMesh %b, %s " , bUseExistingUV , strUVMeshFileName . c_str ( ) ) ;
if ( bUseExistingUV & & ! strUVMeshFileName . empty ( ) ) {
VERBOSE ( " 1faceTexcoords.size=%d, faces.size=%d " , mesh . faceTexcoords . size ( ) , mesh . faces . size ( ) * 3 ) ;
// 使用预计算UV模式
if ( ! mesh . Load ( MAKE_PATH_SAFE ( strUVMeshFileName ) , true ) ) {
VERBOSE ( " error: cannot load mesh file with UV coordinates " ) ;
return false ; // 注意:在成员函数中,返回 false 表示失败
}
VERBOSE ( " 2faceTexcoords.size=%d, faces.size=%d " , mesh . faceTexcoords . size ( ) , mesh . faces . size ( ) * 3 ) ;
// mesh.CheckUVValid();
//*
// 确保网格包含UV坐标
if ( mesh . faceTexcoords . empty ( ) ) {
VERBOSE ( " error: the specified mesh does not contain UV coordinates " ) ;
return false ;
}
// 使用新的纹理生成方法
MeshTexture texture ( * this , nResolutionLevel , nMinResolution ) ;
if ( ! texture . TextureWithExistingUV ( views , nIgnoreMaskLabel , fOutlierThreshold , nTextureSizeMultiple , colEmpty , fSharpnessWeight ) ) {
return false ;
}
//*/
// return true;
}
// mesh.CheckUVValid();
// generate the texture image and atlas
// generate the texture image and atlas
{
{
TD_TIMER_STARTD ( ) ;
TD_TIMER_STARTD ( ) ;
texture . GenerateTexture ( bGlobalSeamLeveling , bLocalSeamLeveling , nTextureSizeMultiple , nRectPackingHeuristic , colEmpty , fSharpnessWeight , maxTextureSize , baseFileName , bOriginFaceview ) ;
texture . GenerateTexture ( bGlobalSeamLeveling , bLocalSeamLeveling , nTextureSizeMultiple , nRectPackingHeuristic , colEmpty , fSharpnessWeight , maxTextureSize , baseFileName , bOriginFaceview , this ) ;
DEBUG_EXTRA ( " Generating texture atlas and image completed: %u patches, %u image size, %u textures (%s) " , texture . texturePatches . size ( ) , mesh . texturesDiffuse [ 0 ] . width ( ) , mesh . texturesDiffuse . size ( ) , TD_TIMER_GET_FMT ( ) . c_str ( ) ) ;
DEBUG_EXTRA ( " Generating texture atlas and image completed: %u patches, %u image size, %u textures (%s) " , texture . texturePatches . size ( ) , mesh . texturesDiffuse [ 0 ] . width ( ) , mesh . texturesDiffuse . size ( ) , TD_TIMER_GET_FMT ( ) . c_str ( ) ) ;
}
}
// mesh.CheckUVValid();
return true ;
return true ;
} // TextureMesh
} // TextureMesh