diff --git a/CMakeLists.txt b/CMakeLists.txt index 5d098c7..a9186f1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -26,9 +26,10 @@ target_compile_options(VCGCoreStatic PRIVATE $<$:/utf-8>) add_executable(vcg-simplifier ${CLI_SOURCES}) -target_link_libraries(vcg-simplifier PRIVATE VCGCoreStatic) +target_link_libraries(vcg-simplifier PRIVATE VCGCoreStatic VCGSimplifier) target_include_directories(vcg-simplifier PRIVATE ${SRC_DIR}/cli/Public) target_include_directories(vcg-simplifier PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include) +target_include_directories(vcg-simplifier PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) target_include_directories(vcg-simplifier PRIVATE ${TINYGLTF_INCLUDE_DIRS}) target_compile_definitions(vcg-simplifier PRIVATE _CRT_SECURE_NO_WARNINGS) target_compile_options(vcg-simplifier PRIVATE $<$:/utf-8>) diff --git a/src/cli/glb_loader.cpp b/src/cli/glb_loader.cpp index 2576459..137561f 100644 --- a/src/cli/glb_loader.cpp +++ b/src/cli/glb_loader.cpp @@ -229,18 +229,11 @@ bool SaveGLB(MyMesh &m, const tinygltf::Model &originalModel, const std::string outModel.asset = originalModel.asset; outModel.asset.generator = "VCG-Simplifier"; - // 【关键修复】处理图片和纹理引用 outModel.materials = originalModel.materials; outModel.textures = originalModel.textures; outModel.samplers = originalModel.samplers; outModel.images = originalModel.images; - // 清除 BufferView 索引,强制 TinyGLTF 重新打包图片数据 - for (auto &img : outModel.images) { - img.bufferView = -1; - img.uri = ""; - } - // 2. 准备几何数据容器 std::vector rawPos; std::vector rawNor; @@ -350,7 +343,7 @@ bool SaveGLB(MyMesh &m, const tinygltf::Model &originalModel, const std::string allIndices.insert(allIndices.end(), pair.second.begin(), pair.second.end()); } - // 3. 构建二进制 Buffer + // 3. 构建二进制 Buffer (几何 + 原始图片数据) tinygltf::Buffer buffer; size_t lenPos = rawPos.size() * sizeof(float); @@ -365,23 +358,46 @@ bool SaveGLB(MyMesh &m, const tinygltf::Model &originalModel, const std::string size_t offsetCol = offsetUV + lenUV; size_t offsetInd = offsetCol + lenCol; - size_t totalSize = offsetInd + lenInd; - - // 【关键修复】Buffer 总长度必须是 4 的倍数 (Padding) - size_t padding = 0; - if (totalSize % 4 != 0) { - padding = 4 - (totalSize % 4); + size_t geoEnd = offsetInd + lenInd; + if (geoEnd % 4 != 0) geoEnd += 4 - (geoEnd % 4); + + // Collect raw image bytes from original buffer + struct ImgEntry { size_t srcOffset; size_t length; std::string mimeType; }; + std::vector imgEntries; + size_t imgTotalSize = 0; + for (const auto &img : originalModel.images) { + if (img.bufferView >= 0 && !originalModel.buffers.empty()) { + const auto &bv = originalModel.bufferViews[img.bufferView]; + size_t aligned = bv.byteLength; + if (aligned % 4 != 0) aligned += 4 - (aligned % 4); + imgEntries.push_back({bv.byteOffset, bv.byteLength, img.mimeType}); + imgTotalSize += aligned; + } else { + imgEntries.push_back({0, 0, ""}); + } } - buffer.data.resize(totalSize + padding); + buffer.data.resize(geoEnd + imgTotalSize, 0); - // 写入数据 std::memcpy(buffer.data.data() + offsetPos, rawPos.data(), lenPos); std::memcpy(buffer.data.data() + offsetNor, rawNor.data(), lenNor); std::memcpy(buffer.data.data() + offsetUV, rawUV.data(), lenUV); std::memcpy(buffer.data.data() + offsetCol, rawColorUB.data(), lenCol); std::memcpy(buffer.data.data() + offsetInd, allIndices.data(), lenInd); + // Copy image data and update image references + size_t imgWriteOffset = geoEnd; + const auto &srcBuf = originalModel.buffers[0].data; + for (size_t i = 0; i < imgEntries.size(); ++i) { + if (imgEntries[i].length == 0) continue; + std::memcpy(buffer.data.data() + imgWriteOffset, + srcBuf.data() + imgEntries[i].srcOffset, + imgEntries[i].length); + imgWriteOffset += imgEntries[i].length; + if (imgWriteOffset % 4 != 0) + imgWriteOffset += 4 - (imgWriteOffset % 4); + } + outModel.buffers.push_back(buffer); int bufferId = 0; @@ -402,6 +418,25 @@ bool SaveGLB(MyMesh &m, const tinygltf::Model &originalModel, const std::string int bvCol = addBufferView(offsetCol, lenCol, TINYGLTF_TARGET_ARRAY_BUFFER); int bvInd = addBufferView(offsetInd, lenInd, TINYGLTF_TARGET_ELEMENT_ARRAY_BUFFER); + // Image bufferViews — keep images in BIN chunk + size_t imgBvOffset = geoEnd; + for (size_t i = 0; i < imgEntries.size(); ++i) { + if (imgEntries[i].length == 0) continue; + tinygltf::BufferView bv; + bv.buffer = bufferId; + bv.byteOffset = imgBvOffset; + bv.byteLength = imgEntries[i].length; + bv.target = 0; + int bvIdx = (int)outModel.bufferViews.size(); + outModel.bufferViews.push_back(bv); + outModel.images[i].bufferView = bvIdx; + outModel.images[i].mimeType = imgEntries[i].mimeType; + outModel.images[i].uri = ""; + imgBvOffset += imgEntries[i].length; + if (imgBvOffset % 4 != 0) + imgBvOffset += 4 - (imgBvOffset % 4); + } + // 5. 创建 Accessors // 【关键修复】参数 typeEnum 改为 int,并接收 Min/Max auto addAccessor = [&](int bv, int count, int compType, int typeEnum, diff --git a/src/cli/main.cpp b/src/cli/main.cpp index d8ce309..78ecce4 100644 --- a/src/cli/main.cpp +++ b/src/cli/main.cpp @@ -142,7 +142,7 @@ int main(int argc, char **argv) { printf("Calling GetMeshData...\n"); fflush(stdout); VCG_GetMeshData(handle, &vcgData); - printf("API done. Unpacking data...\n"); + printf("API done. V=%d F=%d\n", vcgData.num_vertices, vcgData.num_faces); fflush(stdout); // ======= 更新 MyMesh ======= m.Clear(); diff --git a/src/core/simplifier.cpp b/src/core/simplifier.cpp index 0920148..5b05876 100644 --- a/src/core/simplifier.cpp +++ b/src/core/simplifier.cpp @@ -45,6 +45,16 @@ Simplifier::Result Simplifier::SimplifyDetailed(MyMesh &m, const Params ¶ms) } } + // Save face centroids + matId before simplification for recovery + struct FaceCentroidMatId { float cx, cy, cz; int matId; }; + std::vector origFaceMats; + origFaceMats.reserve(m.fn); + for (const auto &f : m.face) { + if (f.IsD()) continue; + auto c = vcg::Barycenter(f); + origFaceMats.push_back({c.X(), c.Y(), c.Z(), f.matId}); + } + Clean(m); result.postCleanVertices = m.vn; result.postCleanFaces = m.fn; @@ -172,6 +182,26 @@ Simplifier::Result Simplifier::SimplifyDetailed(MyMesh &m, const Params ¶ms) vcg::tri::UpdateBounding::Box(m); core::detail::UpdateWedgeNormalsFromFace(m); + // Recover matId by nearest-centroid matching + for (auto &f : m.face) { + if (f.IsD()) continue; + auto c = vcg::Barycenter(f); + float bestDist = std::numeric_limits::max(); + int bestMat = 0; + for (const auto &orig : origFaceMats) { + float dx = c.X() - orig.cx; + float dy = c.Y() - orig.cy; + float dz = c.Z() - orig.cz; + float d = dx*dx + dy*dy + dz*dz; + if (d < bestDist) { + bestDist = d; + bestMat = orig.matId; + if (d == 0.0f) break; + } + } + f.matId = bestMat; + } + result.outputVertices = m.vn; result.outputFaces = m.fn; result.maxError = core::detail::ComputeApproxVertexHausdorff(m, originalPoints);