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
50 changes: 49 additions & 1 deletion src/cli/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
#include "mymesh.h"
#include "obj_loader.h"
#include <cstdio>
#include <cmath>
#include <map>
#include <vector>

// --- 主程序 ---
void LogStatus(MyMesh &m, const char *stage) { printf("[%s] V:%d F:%d\n", stage, m.VN(), m.FN()); }
Expand Down Expand Up @@ -125,6 +128,17 @@ int main(int argc, char **argv) {
vcgData.wedge_tangents = wtangents.data();
vcgData.wedge_binormal_signs = wb_signs.data();

// Save original face centroids + matId for post-simplification recovery
struct OrigFaceInfo { float cx, cy, cz; int matId; };
std::vector<OrigFaceInfo> origFaces(vcgData.num_faces);
for (int i = 0; i < vcgData.num_faces; ++i) {
int i0 = idx[i*3+0], i1 = idx[i*3+1], i2 = idx[i*3+2];
origFaces[i].cx = (pos[i0*3+0]+pos[i1*3+0]+pos[i2*3+0]) / 3.0f;
origFaces[i].cy = (pos[i0*3+1]+pos[i1*3+1]+pos[i2*3+1]) / 3.0f;
origFaces[i].cz = (pos[i0*3+2]+pos[i1*3+2]+pos[i2*3+2]) / 3.0f;
origFaces[i].matId = mat_id[i];
}

printf("Calling CreateMesh...\n");
// ======= C API 调用 =======
VCGMeshHandle handle = VCG_CreateMesh();
Expand All @@ -142,7 +156,41 @@ 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. Recovering material IDs...\n");
printf(" Result: V=%d F=%d\n", vcgData.num_vertices, vcgData.num_faces);

// Recover matId by nearest-centroid matching
for (int i = 0; i < vcgData.num_faces; ++i) {
int i0 = vcgData.indices[i*3+0];
int i1 = vcgData.indices[i*3+1];
int i2 = vcgData.indices[i*3+2];
float cx = (vcgData.positions[i0*3+0]+vcgData.positions[i1*3+0]+vcgData.positions[i2*3+0]) / 3.0f;
float cy = (vcgData.positions[i0*3+1]+vcgData.positions[i1*3+1]+vcgData.positions[i2*3+1]) / 3.0f;
float cz = (vcgData.positions[i0*3+2]+vcgData.positions[i1*3+2]+vcgData.positions[i2*3+2]) / 3.0f;

float bestDist = 1e30f;
int bestMat = 0;
for (int j = 0; j < (int)origFaces.size(); ++j) {
float dx = cx - origFaces[j].cx;
float dy = cy - origFaces[j].cy;
float dz = cz - origFaces[j].cz;
float d = dx*dx + dy*dy + dz*dz;
if (d < bestDist) {
bestDist = d;
bestMat = origFaces[j].matId;
if (d == 0.0f) break;
}
}
vcgData.material_ids[i] = bestMat;
}

{
std::map<int, int> matCount;
for (int i = 0; i < vcgData.num_faces; ++i)
matCount[vcgData.material_ids[i]]++;
for (auto &p : matCount)
printf(" matId=%d count=%d\n", p.first, p.second);
}
fflush(stdout);
// ======= 更新 MyMesh =======
m.Clear();
Expand Down