Compare commits
No commits in common. "93b4efead168679ac9cb7b6c249310a4a1ef4c9d" and "cfe1fa46e049354d833beedf15f9085fb56a5df6" have entirely different histories.
93b4efead1
...
cfe1fa46e0
|
@ -28,30 +28,9 @@ 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,
|
||||||
|
@ -77,6 +56,11 @@ 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
|
||||||
);
|
);
|
||||||
)";
|
)";
|
||||||
|
@ -141,7 +125,6 @@ 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)
|
||||||
|
@ -151,7 +134,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, pid, name, vertex_count, index_count, fbx_id) VALUES (?, ?, ?, ?, ?, ?);";
|
const char *sql = "INSERT OR IGNORE INTO meshes (id, 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)
|
||||||
{
|
{
|
||||||
|
@ -160,11 +143,10 @@ int save_mesh_to_table(FttContext *ctx,
|
||||||
}
|
}
|
||||||
|
|
||||||
sqlite3_bind_int64(stmt, 1, id);
|
sqlite3_bind_int64(stmt, 1, id);
|
||||||
sqlite3_bind_int64(stmt, 2, pid);
|
sqlite3_bind_text(stmt, 2, name.c_str(), -1, SQLITE_STATIC);
|
||||||
sqlite3_bind_text(stmt, 3, name.c_str(), -1, SQLITE_STATIC);
|
sqlite3_bind_int(stmt, 3, vertex_count);
|
||||||
sqlite3_bind_int(stmt, 4, vertex_count);
|
sqlite3_bind_int(stmt, 4, index_count);
|
||||||
sqlite3_bind_int(stmt, 5, index_count);
|
sqlite3_bind_text(stmt, 5, fbx_id.c_str(), -1, SQLITE_STATIC);
|
||||||
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)
|
||||||
|
@ -211,43 +193,37 @@ 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<unsigned int> indices) {
|
int save_mesh_indices(FttContext* ctx, uint mesh_id, std::vector<V3> indices) {
|
||||||
if (!ctx->db) return -1;
|
if (!ctx->db) return -1;
|
||||||
printf("save indices: %d\n", indices.size());
|
|
||||||
for (int i = 0; i < indices.size(); i++)
|
sqlite3_stmt *stmt = nullptr;
|
||||||
{
|
const char *sql = "INSERT OR IGNORE INTO indices (mesh_id, index_id, position_x, position_y, position_z) VALUES (?, ?, ?, ?, ?);";
|
||||||
printf("%d ", indices[i]);
|
int rc = sqlite3_prepare_v2(ctx->db, sql, -1, &stmt, nullptr);
|
||||||
|
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); // 开启事务
|
||||||
|
|
||||||
// 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 (?, ?, ?, ?, ?);";
|
sqlite3_reset(stmt); // 重置语句
|
||||||
// int rc = sqlite3_prepare_v2(ctx->db, sql, -1, &stmt, nullptr);
|
sqlite3_bind_int64(stmt, 1, mesh_id);
|
||||||
// if (rc != SQLITE_OK) {
|
sqlite3_bind_int64(stmt, 2, i); // vert_id使用索引
|
||||||
// fprintf(stderr, "SQL prepare failed: %s\n", sqlite3_errmsg(ctx->db));
|
sqlite3_bind_double(stmt, 3, std::get<0>(indices[i])); // 修正为double类型绑定
|
||||||
// return rc;
|
sqlite3_bind_double(stmt, 4, std::get<1>(indices[i]));
|
||||||
// }
|
sqlite3_bind_double(stmt, 5, std::get<2>(indices[i]));
|
||||||
|
|
||||||
// sqlite3_exec(ctx->db, "BEGIN TRANSACTION;", nullptr, nullptr, nullptr); // 开启事务
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// for (int i = 0; i < indices.size(); i++) {
|
sqlite3_exec(ctx->db, "COMMIT;", nullptr, nullptr, nullptr); // 提交事务
|
||||||
// sqlite3_reset(stmt); // 重置语句
|
sqlite3_finalize(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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,32 +6,32 @@
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
int load_triangles(fbxsdk::FbxNodeAttribute *attr, std::vector<unsigned int> indices, std::vector<V3> &vertices)
|
int load_triangles(fbxsdk::FbxNodeAttribute *attr, std::vector<V3> &indices, std::vector<V3> &triangles)
|
||||||
{
|
{
|
||||||
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();
|
||||||
unsigned int index_p = 0;
|
for (int i = 0; i < polyCount; ++i)
|
||||||
FbxVector4* control_points = mesh->GetControlPoints();
|
|
||||||
for (int p = 0; p < mesh->GetPolygonCount(); p++)
|
|
||||||
{
|
{
|
||||||
if (mesh->GetPolygonSize(p) != 3) {
|
int vertexCount = mesh->GetPolygonSize(i);
|
||||||
// 不是三角形
|
std::vector<int> polyIndices;
|
||||||
return index_p;
|
for (int j = 0; j < vertexCount; ++j)
|
||||||
}
|
|
||||||
for (int p_vertex = 0; p_vertex < mesh->GetPolygonSize(p); p_vertex++)
|
|
||||||
{
|
{
|
||||||
int vertex_indexed = mesh->GetPolygonVertex(p, p_vertex);
|
polyIndices.push_back(mesh->GetPolygonVertex(i, j));
|
||||||
FbxVector4 control_point = control_points[vertex_indexed];
|
}
|
||||||
V3 v = V3(control_point.mData[0], control_point.mData[1], control_point.mData[2]);
|
for (int j = 2; j < vertexCount; ++j)
|
||||||
vertices.push_back(v);
|
{
|
||||||
indices.push_back(index_p++);
|
indices.push_back({polyIndices[0], polyIndices[j - 1], polyIndices[j]});
|
||||||
|
for (int k : {0, j - 1, j})
|
||||||
|
{
|
||||||
|
FbxVector4 pos = mesh->GetControlPointAt(polyIndices[k]);
|
||||||
|
triangles.push_back({(float)pos[0], (float)pos[1], (float)pos[2]});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
return index_p;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FbxNode *get_fbx_root_node(const char *fbx_path)
|
FbxNode *get_fbx_root_node(const char *fbx_path)
|
||||||
|
@ -81,28 +81,23 @@ 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, indices, vertices);
|
int count = load_triangles(attr, vertices, triangles);
|
||||||
|
|
||||||
uint id = attr->GetUniqueID();
|
uint id = attr->GetUniqueID();
|
||||||
uint pid = parent_node->GetUniqueID();
|
printf("[%d]triangles: %ld\n", id, triangles.size());
|
||||||
|
|
||||||
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(), indices.size(),
|
vertices.size(), triangles.size(),
|
||||||
parent_node->GetNameOnly().Buffer());
|
parent_node->GetNameOnly().Buffer());
|
||||||
|
|
||||||
save_mesh_vertices(ctx, id, vertices);
|
save_mesh_vertices(ctx, id, triangles);
|
||||||
save_mesh_indices(ctx, id, indices);
|
save_mesh_indices(ctx, id, vertices);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -117,35 +112,14 @@ 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("|");
|
||||||
printf("--> ");
|
for (int i = 0; i < level; i++)
|
||||||
|
{
|
||||||
// 基础信息:ID/父ID/名称
|
printf("-");
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
if (prop_count > 0) printf("\n");
|
printf("> ");
|
||||||
|
printf("[%lld]: %s\n", node->GetUniqueID(), node->GetNameOnly().Buffer());
|
||||||
}
|
}
|
|
@ -32,7 +32,7 @@ void create_tables(sqlite3* db);
|
||||||
* @note 1. 参数需确保有效:ctx/db非NULL,name/fbx_id非空
|
* @note 1. 参数需确保有效:ctx/db非NULL,name/fbx_id非空
|
||||||
* 2. 内部自动处理事务,重复name会触发唯一键冲突
|
* 2. 内部自动处理事务,重复name会触发唯一键冲突
|
||||||
*/
|
*/
|
||||||
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_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_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<unsigned int> indices);
|
int save_mesh_indices(FttContext* ctx, uint mesh_id, std::vector<V3> indices);
|
|
@ -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 成功返回true,失败返回false
|
* @return bool 成功返回true,失败返回false
|
||||||
* @note 内部会强制三角化网格,非三角形多边形将被忽略
|
* @note 内部会强制三角化网格,非三角形多边形将被忽略
|
||||||
*/
|
*/
|
||||||
int load_triangles(fbxsdk::FbxNodeAttribute* attr, std::vector<unsigned int> indices, std::vector<V3> &vertices);
|
int load_triangles(fbxsdk::FbxNodeAttribute* attr, std::vector<V3>& indices, std::vector<V3>& triangles);
|
||||||
|
|
|
@ -17,7 +17,7 @@ typedef struct {
|
||||||
sqlite3* db;
|
sqlite3* db;
|
||||||
} FttContext;
|
} FttContext;
|
||||||
|
|
||||||
using V3 = std::tuple<double, double, double>;
|
using V3 = std::tuple<int, int, int>;
|
||||||
|
|
||||||
FttContext ctx_from_const(const FttContext* ctx);
|
FttContext ctx_from_const(const FttContext* ctx);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue