Compare commits

...

2 Commits

Author SHA1 Message Date
dqn 93b4efead1 nodes 2025-09-15 18:11:17 +08:00
dqn a0ca1bffc3 pid 2025-09-15 10:33:59 +08:00
5 changed files with 122 additions and 72 deletions

View File

@ -28,9 +28,30 @@ sqlite3 *create_db(const char *db_path, bool overwrite_file)
void create_tables(sqlite3 *db) void create_tables(sqlite3 *db)
{ {
const char *sql_nodes = R"
CREATE TABLE IF NOT EXISTS nodes (
id INTEGER PRIMARY KEY,
unique_id INTEGER NOT NULL UNIQUE,
parent_id INTEGER,
name TEXT NOT NULL,
lcl_translation_x REAL,
lcl_translation_y REAL,
lcl_translation_z REAL,
lcl_rotation_x REAL,
lcl_rotation_y REAL,
lcl_rotation_z REAL,
lcl_scaling_x REAL,
lcl_scaling_y REAL,
lcl_scaling_z REAL,
properties TEXT,
FOREIGN KEY (parent_id) REFERENCES fbx_nodes(unique_id)
);
";
const char *sql_meshes = R"( const char *sql_meshes = R"(
CREATE TABLE IF NOT EXISTS meshes ( CREATE TABLE IF NOT EXISTS meshes (
id INTEGER PRIMARY KEY AUTOINCREMENT, id INTEGER PRIMARY KEY AUTOINCREMENT,
pid INTEGER,
name TEXT NOT NULL, name TEXT NOT NULL,
vertex_count INTEGER NOT NULL, vertex_count INTEGER NOT NULL,
index_count INTEGER NOT NULL, index_count INTEGER NOT NULL,
@ -56,11 +77,6 @@ void create_tables(sqlite3 *db)
position_x REAL NOT NULL, position_x REAL NOT NULL,
position_y REAL NOT NULL, position_y REAL NOT NULL,
position_z REAL NOT NULL, position_z REAL NOT NULL,
normal_x REAL,
normal_y REAL,
normal_z REAL,
uv_u REAL,
uv_v REAL,
FOREIGN KEY(mesh_id) REFERENCES meshes(id) ON DELETE CASCADE FOREIGN KEY(mesh_id) REFERENCES meshes(id) ON DELETE CASCADE
); );
)"; )";
@ -125,6 +141,7 @@ void create_tables(sqlite3 *db)
int save_mesh_to_table(FttContext *ctx, int save_mesh_to_table(FttContext *ctx,
sqlite3 *db, sqlite3 *db,
uint id, uint id,
uint pid,
const std::string &name, const std::string &name,
int vertex_count, int index_count, int vertex_count, int index_count,
const std::string &fbx_id) const std::string &fbx_id)
@ -134,7 +151,7 @@ int save_mesh_to_table(FttContext *ctx,
return -1; return -1;
sqlite3_stmt *stmt = nullptr; sqlite3_stmt *stmt = nullptr;
const char *sql = "INSERT OR IGNORE INTO meshes (id, name, vertex_count, index_count, fbx_id) VALUES (?, ?, ?, ?, ?);"; const char *sql = "INSERT OR IGNORE INTO meshes (id, pid, name, vertex_count, index_count, fbx_id) VALUES (?, ?, ?, ?, ?, ?);";
int rc = sqlite3_prepare_v2(db, sql, -1, &stmt, nullptr); int rc = sqlite3_prepare_v2(db, sql, -1, &stmt, nullptr);
if (rc != SQLITE_OK) if (rc != SQLITE_OK)
{ {
@ -143,10 +160,11 @@ int save_mesh_to_table(FttContext *ctx,
} }
sqlite3_bind_int64(stmt, 1, id); sqlite3_bind_int64(stmt, 1, id);
sqlite3_bind_text(stmt, 2, name.c_str(), -1, SQLITE_STATIC); sqlite3_bind_int64(stmt, 2, pid);
sqlite3_bind_int(stmt, 3, vertex_count); sqlite3_bind_text(stmt, 3, name.c_str(), -1, SQLITE_STATIC);
sqlite3_bind_int(stmt, 4, index_count); sqlite3_bind_int(stmt, 4, vertex_count);
sqlite3_bind_text(stmt, 5, fbx_id.c_str(), -1, SQLITE_STATIC); sqlite3_bind_int(stmt, 5, index_count);
sqlite3_bind_text(stmt, 6, fbx_id.c_str(), -1, SQLITE_STATIC);
rc = sqlite3_step(stmt); rc = sqlite3_step(stmt);
if (rc != SQLITE_DONE && rc != SQLITE_CONSTRAINT) if (rc != SQLITE_DONE && rc != SQLITE_CONSTRAINT)
@ -193,37 +211,43 @@ int save_mesh_vertices(FttContext *ctx, uint mesh_id, std::vector<V3> vertices)
return 0; return 0;
} }
int save_mesh_indices(FttContext* ctx, uint mesh_id, std::vector<V3> indices) { int save_mesh_indices(FttContext* ctx, uint mesh_id, std::vector<unsigned int> indices) {
if (!ctx->db) return -1; if (!ctx->db) return -1;
printf("save indices: %d\n", indices.size());
sqlite3_stmt *stmt = nullptr; for (int i = 0; i < indices.size(); i++)
const char *sql = "INSERT OR IGNORE INTO indices (mesh_id, index_id, position_x, position_y, position_z) VALUES (?, ?, ?, ?, ?);"; {
int rc = sqlite3_prepare_v2(ctx->db, sql, -1, &stmt, nullptr); printf("%d ", indices[i]);
if (rc != SQLITE_OK) {
fprintf(stderr, "SQL prepare failed: %s\n", sqlite3_errmsg(ctx->db));
return rc;
} }
sqlite3_exec(ctx->db, "BEGIN TRANSACTION;", nullptr, nullptr, nullptr); // 开启事务
for (int i = 0; i < indices.size(); i++) { // sqlite3_stmt *stmt = nullptr;
sqlite3_reset(stmt); // 重置语句 // const char *sql = "INSERT OR IGNORE INTO indices (mesh_id, index_id, position_x, position_y, position_z) VALUES (?, ?, ?, ?, ?);";
sqlite3_bind_int64(stmt, 1, mesh_id); // int rc = sqlite3_prepare_v2(ctx->db, sql, -1, &stmt, nullptr);
sqlite3_bind_int64(stmt, 2, i); // vert_id使用索引 // if (rc != SQLITE_OK) {
sqlite3_bind_double(stmt, 3, std::get<0>(indices[i])); // 修正为double类型绑定 // fprintf(stderr, "SQL prepare failed: %s\n", sqlite3_errmsg(ctx->db));
sqlite3_bind_double(stmt, 4, std::get<1>(indices[i])); // return rc;
sqlite3_bind_double(stmt, 5, std::get<2>(indices[i])); // }
rc = sqlite3_step(stmt); // sqlite3_exec(ctx->db, "BEGIN TRANSACTION;", nullptr, nullptr, nullptr); // 开启事务
if (rc != SQLITE_DONE && rc != SQLITE_CONSTRAINT) {
fprintf(stderr, "SQL step failed at vertex %d: %s\n", i, sqlite3_errmsg(ctx->db));
sqlite3_exec(ctx->db, "ROLLBACK;", nullptr, nullptr, nullptr);
sqlite3_finalize(stmt);
return rc;
}
}
sqlite3_exec(ctx->db, "COMMIT;", nullptr, nullptr, nullptr); // 提交事务 // for (int i = 0; i < indices.size(); i++) {
sqlite3_finalize(stmt); // sqlite3_reset(stmt); // 重置语句
// sqlite3_bind_int64(stmt, 1, mesh_id);
// sqlite3_bind_int64(stmt, 2, i); // vert_id使用索引
// sqlite3_bind_double(stmt, 3, std::get<0>(indices[i])); // 修正为double类型绑定
// sqlite3_bind_double(stmt, 4, std::get<1>(indices[i]));
// sqlite3_bind_double(stmt, 5, std::get<2>(indices[i]));
// rc = sqlite3_step(stmt);
// if (rc != SQLITE_DONE && rc != SQLITE_CONSTRAINT) {
// fprintf(stderr, "SQL step failed at vertex %d: %s\n", i, sqlite3_errmsg(ctx->db));
// sqlite3_exec(ctx->db, "ROLLBACK;", nullptr, nullptr, nullptr);
// sqlite3_finalize(stmt);
// return rc;
// }
// }
// sqlite3_exec(ctx->db, "COMMIT;", nullptr, nullptr, nullptr); // 提交事务
// sqlite3_finalize(stmt);
return 0; return 0;
} }

View File

@ -6,32 +6,32 @@
using namespace std; using namespace std;
int load_triangles(fbxsdk::FbxNodeAttribute *attr, std::vector<V3> &indices, std::vector<V3> &triangles) int load_triangles(fbxsdk::FbxNodeAttribute *attr, std::vector<unsigned int> indices, std::vector<V3> &vertices)
{ {
if (!attr || attr->GetAttributeType() != FbxNodeAttribute::eMesh) if (!attr || attr->GetAttributeType() != FbxNodeAttribute::eMesh)
return false; return false;
FbxMesh *mesh = static_cast<FbxMesh *>(attr); FbxMesh *mesh = static_cast<FbxMesh *>(attr);
int polyCount = mesh->GetPolygonCount();
for (int i = 0; i < polyCount; ++i) unsigned int index_p = 0;
FbxVector4* control_points = mesh->GetControlPoints();
for (int p = 0; p < mesh->GetPolygonCount(); p++)
{ {
int vertexCount = mesh->GetPolygonSize(i); if (mesh->GetPolygonSize(p) != 3) {
std::vector<int> polyIndices; // 不是三角形
for (int j = 0; j < vertexCount; ++j) return index_p;
{
polyIndices.push_back(mesh->GetPolygonVertex(i, j));
} }
for (int j = 2; j < vertexCount; ++j) for (int p_vertex = 0; p_vertex < mesh->GetPolygonSize(p); p_vertex++)
{ {
indices.push_back({polyIndices[0], polyIndices[j - 1], polyIndices[j]}); int vertex_indexed = mesh->GetPolygonVertex(p, p_vertex);
for (int k : {0, j - 1, j}) FbxVector4 control_point = control_points[vertex_indexed];
{ V3 v = V3(control_point.mData[0], control_point.mData[1], control_point.mData[2]);
FbxVector4 pos = mesh->GetControlPointAt(polyIndices[k]); vertices.push_back(v);
triangles.push_back({(float)pos[0], (float)pos[1], (float)pos[2]}); indices.push_back(index_p++);
}
} }
} }
return 0;
return index_p;
} }
FbxNode *get_fbx_root_node(const char *fbx_path) FbxNode *get_fbx_root_node(const char *fbx_path)
@ -81,23 +81,28 @@ void each_node(FttContext *ctx, FbxNode *parent_node, int level)
FbxNodeAttribute *attr = parent_node->GetNodeAttributeByIndex(i); FbxNodeAttribute *attr = parent_node->GetNodeAttributeByIndex(i);
if (attr && attr->GetAttributeType() == FbxNodeAttribute::eMesh) if (attr && attr->GetAttributeType() == FbxNodeAttribute::eMesh)
{ {
std::vector<unsigned int> indices;
std::vector<V3> vertices; std::vector<V3> vertices;
std::vector<V3> triangles;
int count = load_triangles(attr, vertices, triangles); int count = load_triangles(attr, indices, vertices);
uint id = attr->GetUniqueID(); uint id = attr->GetUniqueID();
printf("[%d]triangles: %ld\n", id, triangles.size()); uint pid = parent_node->GetUniqueID();
printf("[%d]vertices: %ld\n", count);
// save data to database // save data to database
sqlite3 *db = ctx->db; sqlite3 *db = ctx->db;
// todo save mesh into db // todo save mesh into db
save_mesh_to_table(ctx, ctx->db, save_mesh_to_table(ctx, ctx->db,
id, id,
pid,
attr->GetName(), attr->GetName(),
vertices.size(), triangles.size(), vertices.size(), indices.size(),
parent_node->GetNameOnly().Buffer()); parent_node->GetNameOnly().Buffer());
save_mesh_vertices(ctx, id, triangles); save_mesh_vertices(ctx, id, vertices);
save_mesh_indices(ctx, id, vertices); save_mesh_indices(ctx, id, indices);
} }
} }
@ -112,14 +117,35 @@ void each_node(FttContext *ctx, FbxNode *parent_node, int level)
} }
} }
void print_node_info(FbxNode *node, int level) void print_node_info(FbxNode* node, int level) {
{ // 层级前缀
// 打印一下节点信息 for (int i = 0; i < level; i++) printf("--");
printf("|"); printf("|");
for (int i = 0; i < level; i++) printf("--> ");
{
printf("-"); // 基础信息ID/父ID/名称
FbxNode* parent = node->GetParent();
printf("[ID:%lld/PID:%lld] Name: %s\n",
node->GetUniqueID(),
parent ? parent->GetUniqueID() : 0,
node->GetNameOnly().Buffer());
// 变换矩阵:平移/旋转/缩放
FbxDouble3 t = node->LclTranslation.Get();
FbxDouble3 r = node->LclRotation.Get();
FbxDouble3 s = node->LclScaling.Get();
printf(" Transform: T(%.2f,%.2f,%.2f) R(%.2f,%.2f,%.2f) S(%.2f,%.2f,%.2f)\n",
t[0], t[1], t[2], r[0], r[1], r[2], s[0], s[1], s[2]);
// 属性列表前5个非默认属性
FbxProperty p = node->GetFirstProperty();
int prop_count = 0;
printf(" Properties: ");
while (p.IsValid() && prop_count < 5) {
printf("%s[%.2f] ", p.GetName().Buffer(), p.Get<double>());
prop_count++;
p = node->GetNextProperty(p);
} }
printf("> "); if (prop_count > 0) printf("\n");
printf("[%lld]: %s\n", node->GetUniqueID(), node->GetNameOnly().Buffer());
} }

View File

@ -32,7 +32,7 @@ void create_tables(sqlite3* db);
* @note 1. ctx/db非NULLname/fbx_id非空 * @note 1. ctx/db非NULLname/fbx_id非空
* 2. name会触发唯一键冲突 * 2. name会触发唯一键冲突
*/ */
int save_mesh_to_table(FttContext* ctx, sqlite3 *db, uint id, const std::string &name, int vertex_count, int index_count, const std::string &fbx_id); int save_mesh_to_table(FttContext* ctx, sqlite3 *db, uint id, uint pid, const std::string &name, int vertex_count, int index_count, const std::string &fbx_id);
int save_mesh_vertices(FttContext* ctx, uint mesh_id, std::vector<V3> vertices); int save_mesh_vertices(FttContext* ctx, uint mesh_id, std::vector<V3> vertices);
int save_mesh_indices(FttContext* ctx, uint mesh_id, std::vector<V3> indices); int save_mesh_indices(FttContext* ctx, uint mesh_id, std::vector<unsigned int> indices);

View File

@ -32,9 +32,9 @@ FbxNode* get_fbx_root_node(const char* fbx_path);
/** /**
* @brief FBX网格属性加载顶点数据和三角化索引 * @brief FBX网格属性加载顶点数据和三角化索引
* @param[in] attr FBX节点属性FbxMesh类型 * @param[in] attr FBX节点属性FbxMesh类型
* @param[out] indices Triangle存储3个顶点索引
* @param[out] vertices Triangle存储3个FbxVector4顶点 * @param[out] vertices Triangle存储3个FbxVector4顶点
* @param[out] triangles Triangle存储3个顶点索引
* @return bool truefalse * @return bool truefalse
* @note * @note
*/ */
int load_triangles(fbxsdk::FbxNodeAttribute* attr, std::vector<V3>& indices, std::vector<V3>& triangles); int load_triangles(fbxsdk::FbxNodeAttribute* attr, std::vector<unsigned int> indices, std::vector<V3> &vertices);

View File

@ -17,7 +17,7 @@ typedef struct {
sqlite3* db; sqlite3* db;
} FttContext; } FttContext;
using V3 = std::tuple<int, int, int>; using V3 = std::tuple<double, double, double>;
FttContext ctx_from_const(const FttContext* ctx); FttContext ctx_from_const(const FttContext* ctx);