手动UV分支
This commit is contained in:
1 parent
5e1623e303
commit
7fd81ffbea
7 files changed
+1192
-242
No files matched your search
+128
-1
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
File diff suppressed because it is too large.
Load diff
Reference in new issue
Block a user