手动UV分支

This commit is contained in:
hesuicong committed 2025-12-31 09:51:38 +08:00
1 parent 5e1623e303
commit 7fd81ffbea
7 files changed
+1192 -242

No files matched your search

+128 -1
View File
@@ -48,6 +48,7 @@ ObjModel::MaterialLib::MaterialLib()
bool ObjModel::MaterialLib::Save(const String& prefix, bool texLossless) const
{
DEBUG_EXTRA("MaterialLib::Save %s", prefix.c_str());
std::ofstream out((prefix+".mtl").c_str());
if (!out.good())
return false;
@@ -130,7 +131,7 @@ bool ObjModel::MaterialLib::Load(const String& fileName)
// S T R U C T S ///////////////////////////////////////////////////
bool ObjModel::Save(const String& fileName, unsigned precision, bool texLossless) const
bool ObjModel::Save(const String& fileName, unsigned precision, bool texLossless, bool bUseExistingUV) const
{
if (vertices.empty())
return false;
@@ -140,6 +141,9 @@ bool ObjModel::Save(const String& fileName, unsigned precision, bool texLossless
if (!material_lib.Save(prefix, texLossless))
return false;
if (bUseExistingUV)
return true;
std::ofstream out((prefix + ".obj").c_str());
if (!out.good())
return false;
@@ -269,6 +273,129 @@ bool ObjModel::Load(const String& fileName)
return !vertices.empty();
}
bool ObjModel::LoadUV(const String& fileName, SEACAVE::cList<TexCoord,const TexCoord&,0,8192,uint32_t> &faceTexcoords, bool bLoadUV)
{
DEBUG_EXTRA("LoadUV bLoadUV=%b", bLoadUV);
ASSERT(vertices.empty() && groups.empty() && material_lib.materials.empty());
std::ifstream fin(fileName.c_str());
String line, keyword;
std::istringstream in;
while (fin.good()) {
std::getline(fin, line);
if (line.empty() || line[0u] == '#')
continue;
in.str(line);
in >> keyword;
if (keyword == "v") {
Vertex v;
in >> v[0] >> v[1] >> v[2];
if (in.fail())
{
DEBUG_EXTRA("1");
return false;
}
vertices.push_back(v);
// DEBUG_EXTRA("10, %d", vertices.size());
} else if (keyword == "vt") {
TexCoord vt;
in >> vt[0] >> vt[1];
if (in.fail())
{
DEBUG_EXTRA("2");
return false;
}
texcoords.push_back(vt);
} else if (keyword == "vn") {
Normal vn;
in >> vn[0] >> vn[1] >> vn[2];
if (in.fail())
{
DEBUG_EXTRA("3");
return false;
}
normals.push_back(vn);
} else if (keyword == "f") {
Face f;
memset(&f, 0xFF, sizeof(Face));
for (size_t k = 0; k < 3; ++k) {
in >> keyword;
// 更健壮的解析方法,处理各种索引格式
std::vector<String> parts;
size_t start = 0, end = 0;
// 按'/'分割字符串
while ((end = keyword.find('/', start)) != String::npos) {
parts.push_back(keyword.substr(start, end - start));
start = end + 1;
}
parts.push_back(keyword.substr(start));
// 根据分割后的部分数量处理不同情况
if (parts.size() >= 1 && !parts[0].empty()) {
f.vertices[k] = std::stoi(parts[0]) - OBJ_INDEX_OFFSET;
}
if (parts.size() >= 2 && !parts[1].empty()) {
f.texcoords[k] = std::stoi(parts[1]) - OBJ_INDEX_OFFSET;
}
if (parts.size() >= 3 && !parts[2].empty()) {
f.normals[k] = std::stoi(parts[2]) - OBJ_INDEX_OFFSET;
}
}
if (in.fail())
{
DEBUG_EXTRA("4");
return false;
}
if (bLoadUV)
{
for (int i = 0; i < 3; ++i) {
if (f.texcoords[i] != NO_ID && f.texcoords[i] < texcoords.size()) {
faceTexcoords.push_back(texcoords[f.texcoords[i]]);
} else {
// 索引无效(例如面定义中未提供vt索引或索引越界),使用默认值
faceTexcoords.push_back(Point2f(0.0f, 0.0f)); // 默认UV
DEBUG_EXTRA("Invalid texcoords %d", f.texcoords[i])
}
}
// DEBUG_EXTRA("faceTexcoords push_back [(%f,%f),(%f,%f),(%f,%f)]", texcoords[f.texcoords[0]].x, texcoords[f.texcoords[0]].y,
// texcoords[f.texcoords[1]].x, texcoords[f.texcoords[1]].y, texcoords[f.texcoords[2]].x, texcoords[f.texcoords[2]].y);
}
if (groups.empty())
AddGroup("");
groups.back().faces.push_back(f);
// } else if (keyword == "mtllib") {
// in >> keyword;
// if (!material_lib.Load(keyword))
// DEBUG_EXTRA("3");
// return false;
} else if (keyword == "usemtl") {
Group group;
in >> group.material_name;
if (in.fail())
{
DEBUG_EXTRA("5");
return false;
}
groups.push_back(group);
}
in.clear();
}
DEBUG_EXTRA("6, vertices.size=%d, faceTexcoords.size=%d", vertices.size(), faceTexcoords.size());
return !vertices.empty();
}
ObjModel::Group& ObjModel::AddGroup(const String& material_name)
{
+2 -1
View File
@@ -93,9 +93,10 @@ public:
ObjModel() {}
// Saves the obj model to an .obj file, its material lib and the materials with the given file name
bool Save(const String& fileName, unsigned precision=6, bool texLossless=false) const;
bool Save(const String& fileName, unsigned precision=6, bool texLossless=false, bool bUseExistingUV=false) const;
// Loads the obj model from an .obj file, its material lib and the materials with the given file name
bool Load(const String& fileName);
bool LoadUV(const String& fileName, SEACAVE::cList<TexCoord,const TexCoord&,0,8192,uint32_t> &faceTexcoords, bool bLoadUV = false);
// Creates a new group with the given material name
Group& AddGroup(const String& material_name);
+62 -12
View File
@@ -1191,15 +1191,14 @@ namespace BasicPLY {
} // namespace MeshInternal
// import the mesh from the given file
bool Mesh::Load(const String& fileName)
bool Mesh::Load(const String& fileName, bool bLoadUV)
{
TD_TIMER_STARTD();
const String ext(Util::getFileExt(fileName).ToLower());
bool ret;
if (ext == _T(".obj"))
ret = LoadOBJ(fileName);
else
if (ext == _T(".gltf") || ext == _T(".glb"))
ret = LoadOBJ(fileName, bLoadUV);
else if (ext == _T(".gltf") || ext == _T(".glb"))
ret = LoadGLTF(fileName, ext == _T(".glb"));
else
ret = LoadPLY(fileName);
@@ -1208,6 +1207,43 @@ bool Mesh::Load(const String& fileName)
DEBUG_EXTRA("Mesh loaded: %u vertices, %u faces (%s)", vertices.size(), faces.size(), TD_TIMER_GET_FMT().c_str());
return true;
}
void Mesh::CheckUVValid()
{
for (int_t idxFace = 0; idxFace < (int_t)faces.size(); ++idxFace)
{
FOREACH(idxFace, faces)
{
const FIndex faceID = (FIndex)idxFace;
const TexCoord* uv = &faceTexcoords[faceID * 3];
const Point2f& a = uv[0];
const Point2f& b = uv[1];
const Point2f& c = uv[2];
// DEBUG_EXTRA("a=(%f,%f),b=(%f,%f),c=(%f,%f)", a.x, a.y, b.x, b.y, c.x, c.y);
// 计算边向量
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-10f;
if (std::abs(denom) < epsilon)
{
// DEBUG_EXTRA("PointInTriangle - Degenerate triangle, denom=%.10f", denom);
}
else
{
DEBUG_EXTRA("PointInTriangle Yes idxFace=%d", idxFace);
}
}
}
}
// import the mesh as a PLY file
bool Mesh::LoadPLY(const String& fileName)
{
@@ -1302,16 +1338,28 @@ bool Mesh::LoadPLY(const String& fileName)
return true;
}
// import the mesh as a OBJ file
bool Mesh::LoadOBJ(const String& fileName)
bool Mesh::LoadOBJ(const String& fileName, bool bLoadUV)
{
ASSERT(!fileName.empty());
Release();
// open and parse OBJ file
ObjModel model;
if (!model.Load(fileName)) {
DEBUG_EXTRA("error: invalid OBJ file");
return false;
if (bLoadUV)
{
if (!model.LoadUV(fileName, faceTexcoords, true)) {
DEBUG_EXTRA("error: LoadUV invalid OBJ file %s", fileName.c_str());
return false;
}
}
else
{
if (!model.LoadUV(fileName, faceTexcoords)) {
// if (!model.Load(fileName)) {
DEBUG_EXTRA("error: Load invalid OBJ file %s", fileName.c_str());
return false;
}
}
if (model.get_vertices().empty() || model.get_groups().empty()) {
@@ -1340,11 +1388,13 @@ bool Mesh::LoadOBJ(const String& fileName)
for (const ObjModel::Face& f: group.faces) {
ASSERT(f.vertices[0] != NO_ID);
faces.emplace_back(f.vertices[0], f.vertices[1], f.vertices[2]);
/*
if (f.texcoords[0] != NO_ID) {
for (int i=0; i<3; ++i)
faceTexcoords.emplace_back(model.get_texcoords()[f.texcoords[i]]);
faceTexindices.emplace_back((TexIndex)groupIdx);
}
*/
if (f.normals[0] != NO_ID) {
Normal& n = faceNormals.emplace_back(Normal::ZERO);
for (int i=0; i<3; ++i)
@@ -1445,13 +1495,13 @@ bool Mesh::LoadGLTF(const String& fileName, bool bBinary)
/*----------------------------------------------------------------*/
// export the mesh to the given file
bool Mesh::Save(const String& fileName, const cList<String>& comments, bool bBinary) const
bool Mesh::Save(const String& fileName, const cList<String>& comments, bool bBinary, bool bUseExistingUV) const
{
TD_TIMER_STARTD();
const String ext(Util::getFileExt(fileName).ToLower());
bool ret;
if (ext == _T(".obj"))
ret = SaveOBJ(fileName);
ret = SaveOBJ(fileName, bUseExistingUV);
else
if (ext == _T(".gltf") || ext == _T(".glb"))
ret = SaveGLTF(fileName, ext == _T(".glb"));
@@ -1538,7 +1588,7 @@ bool Mesh::SavePLY(const String& fileName, const cList<String>& comments, bool b
return true;
}
// export the mesh as a OBJ file
bool Mesh::SaveOBJ(const String& fileName) const
bool Mesh::SaveOBJ(const String& fileName, bool bUseExistingUV) const
{
ASSERT(!fileName.empty());
Util::ensureFolder(fileName);
@@ -1597,7 +1647,7 @@ bool Mesh::SaveOBJ(const String& fileName) const
pMaterial->diffuse_map = texturesDiffuse[idxTexture];
}
return model.Save(fileName, 6U, true);
return model.Save(fileName, 6U, true, bUseExistingUV);
}
// export the mesh as a GLTF file
template <typename T>
+6 -4
View File
@@ -262,8 +262,8 @@ public:
bool TransferTexture(Mesh& mesh, const FaceIdxArr& faceSubsetIndices={}, unsigned borderSize=3, unsigned textureSize=4096);
// file IO
bool Load(const String& fileName);
bool Save(const String& fileName, const cList<String>& comments=cList<String>(), bool bBinary=true) const;
bool Load(const String& fileName, bool bLoadUV=false);
bool Save(const String& fileName, const cList<String>& comments=cList<String>(), bool bBinary=true, bool bUseExistingUV=false) const;
bool Save(const FacesChunkArr&, const String& fileName, const cList<String>& comments=cList<String>(), bool bBinary=true) const;
static bool Save(const VertexArr& vertices, const String& fileName, bool bBinary=true);
@@ -271,13 +271,15 @@ public:
static inline VIndex GetVertex(const Face& f, VIndex v) { const uint32_t idx(FindVertex(f, v)); ASSERT(idx != NO_ID); return f[idx]; }
static inline VIndex& GetVertex(Face& f, VIndex v) { const uint32_t idx(FindVertex(f, v)); ASSERT(idx != NO_ID); return f[idx]; }
void CheckUVValid();
protected:
bool LoadPLY(const String& fileName);
bool LoadOBJ(const String& fileName);
bool LoadOBJ(const String& fileName, bool bLoadUV);
bool LoadGLTF(const String& fileName, bool bBinary=true);
bool SavePLY(const String& fileName, const cList<String>& comments=cList<String>(), bool bBinary=true, bool bTexLossless=true) const;
bool SaveOBJ(const String& fileName) const;
bool SaveOBJ(const String& fileName, bool bUseExistingUV) const;
bool SaveGLTF(const String& fileName, bool bBinary=true) const;
#ifdef _USE_CUDA
+1 -1
View File
@@ -169,7 +169,7 @@ public:
bool TextureMesh(unsigned nResolutionLevel, unsigned nMinResolution, unsigned minCommonCameras=0, float fOutlierThreshold=0.f, float fRatioDataSmoothness=0.3f,
bool bGlobalSeamLeveling=true, bool bLocalSeamLeveling=true, unsigned nTextureSizeMultiple=0, unsigned nRectPackingHeuristic=3, Pixel8U colEmpty=Pixel8U(255,127,39),
float fSharpnessWeight=0.5f, int ignoreMaskLabel=-1, int maxTextureSize=0, const IIndexArr& views=IIndexArr(), const SEACAVE::String& basename = "", bool bOriginFaceview = false,
const std::string& inputFileName = "", const std::string& meshFileName = "");
const std::string& inputFileName = "", const std::string& meshFileName = "", bool bUseExistingUV = false, const std::string& strUVMeshFileName = "");
std::string runPython(const std::string& command);
bool is_face_visible(const std::string& image_name, int face_index);
+986 -221
View File
File diff suppressed because it is too large. Load diff