Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,10 @@ target_compile_options(VCGCoreStatic PRIVATE $<$<CXX_COMPILER_ID:MSVC>:/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 $<$<CXX_COMPILER_ID:MSVC>:/utf-8>)
Expand Down
67 changes: 51 additions & 16 deletions src/cli/glb_loader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<float> rawPos;
std::vector<float> rawNor;
Expand Down Expand Up @@ -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);
Expand All @@ -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<ImgEntry> 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;

Expand All @@ -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,
Expand Down
2 changes: 1 addition & 1 deletion src/cli/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
30 changes: 30 additions & 0 deletions src/core/simplifier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,16 @@ Simplifier::Result Simplifier::SimplifyDetailed(MyMesh &m, const Params &params)
}
}

// Save face centroids + matId before simplification for recovery
struct FaceCentroidMatId { float cx, cy, cz; int matId; };
std::vector<FaceCentroidMatId> 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;
Expand Down Expand Up @@ -172,6 +182,26 @@ Simplifier::Result Simplifier::SimplifyDetailed(MyMesh &m, const Params &params)
vcg::tri::UpdateBounding<MyMesh>::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<float>::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);
Expand Down