save mesh info

This commit is contained in:
dqn 2025-09-09 18:57:37 +08:00
parent cd6038ea13
commit 691109e12a
9 changed files with 150 additions and 50 deletions

View File

@ -7,9 +7,10 @@ fn main() {
// .flag("-std=c++11") // .flag("-std=c++11")
.warnings(false) .warnings(false)
.include("./cpp_src/include") .include("./cpp_src/include")
.file("./cpp_src/tools.cpp")
.file("./cpp_src/db_ops.cpp")
.file("./cpp_src/fbx_parse.cpp") .file("./cpp_src/fbx_parse.cpp")
.file("./cpp_src/fbx_wrap.cpp") .file("./cpp_src/fbx_wrap.cpp")
.file("./cpp_src/db_ops.cpp")
.compile("fbx_parse"); .compile("fbx_parse");
// ------------- // -------------
println!("cargo:rustc-link-search=native=./cpp_src/lib"); println!("cargo:rustc-link-search=native=./cpp_src/lib");

View File

@ -1,7 +1,7 @@
#include <db_ops.h> #include <db_ops.h>
#include <string> #include <string>
#include <cstring> #include <cstring>
#include <tools.h>
using namespace std; using namespace std;
sqlite3 *create_db(const char *db_path, bool overwrite_file) sqlite3 *create_db(const char *db_path, bool overwrite_file)
@ -19,7 +19,7 @@ sqlite3 *create_db(const char *db_path, bool overwrite_file)
int result_code = sqlite3_open(db_path, &db); int result_code = sqlite3_open(db_path, &db);
if (result_code != SQLITE_OK) if (result_code != SQLITE_OK)
{ {
fprintf(stderr, "Failed to open DB: %s\n", sqlite3_errmsg(db)); fprintf(stderr, "Failed to open DB: %s[%d]\n", sqlite3_errmsg(db), result_code);
sqlite3_close(db); sqlite3_close(db);
return NULL; return NULL;
} }
@ -116,3 +116,38 @@ void create_tables(sqlite3 *db)
// 成功执行无需释放err_msgsqlite3_exec成功时err_msg为NULL // 成功执行无需释放err_msgsqlite3_exec成功时err_msg为NULL
} }
} }
// 函数定义
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)
{
if (!db || name.empty() || fbx_id.empty()) return -1;
sqlite3_stmt* stmt = nullptr;
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);
if (rc != SQLITE_OK) {
fprintf(stderr, "SQL prepare failed: %s\n", sqlite3_errmsg(db));
return rc;
}
sqlite3_bind_int64(stmt, 1, id);
sqlite3_bind_text(stmt, 2, name.c_str(), -1, SQLITE_STATIC);
sqlite3_bind_int(stmt, 3, vertex_count);
sqlite3_bind_int(stmt, 4, index_count);
sqlite3_bind_text(stmt, 5, fbx_id.c_str(), -1, SQLITE_STATIC);
rc = sqlite3_step(stmt);
if (rc != SQLITE_DONE && rc != SQLITE_CONSTRAINT) {
fprintf(stderr, "SQL step failed: %s\n", sqlite3_errmsg(db));
}
sqlite3_finalize(stmt);
return rc == SQLITE_DONE ? 0 : -1;
}

View File

@ -8,7 +8,7 @@ using namespace std;
extern "C" { extern "C" {
// 定义给Rust调用的接口函数 // 定义给Rust调用的接口函数
void fbx_parse(const FttContext* ctx) void fbx_parse(FttContext* ctx)
{ {
printf("%s\n", ctx->fbx_file); printf("%s\n", ctx->fbx_file);
FbxManager* lSdkManager = FbxManager::Create(); FbxManager* lSdkManager = FbxManager::Create();
@ -43,17 +43,21 @@ extern "C" {
void load_fbx_mesh_to_db( FttContext* ctx) void load_fbx_mesh_to_db( FttContext* ctx)
{ {
// get mutable data
auto temp = ctx_from_const(ctx);
FttContext* mut_ctx = &temp;
// 按fbx名称生成 ${ctx.out_dir}/sqlite3.db // 按fbx名称生成 ${ctx.out_dir}/sqlite3.db
// 初始化db赋值到ctx.db // 初始化db赋值到ctx.db
sqlite3* db = create_db((std::string(ctx->out_dir) + "/db.sqlite3").c_str(), true); sqlite3* db = create_db((std::string(ctx->out_dir) + "/db.sqlite3").c_str(), true);
printf("db---> %x\n", db); if (db == NULL) {
ctx->db = db; return;
}
mut_ctx->db = db;
// init db tables // init db tables
create_tables(ctx->db); create_tables(mut_ctx->db);
FbxNode* root = get_fbx_root_node(ctx->fbx_file); FbxNode* root = get_fbx_root_node(ctx->fbx_file);
each_node(ctx, root, 0); each_node(mut_ctx, root, 0);
} }
} }

View File

@ -1,29 +1,31 @@
#include "fbx_wrap.h" #include <fbx_wrap.h>
#include <stdio.h> #include <stdio.h>
#include <iostream> #include <iostream>
#include <db_ops.h>
#include <tools.h>
using namespace std; using namespace std;
int load_triangles(fbxsdk::FbxNodeAttribute* attr, std::vector<Triangle>& triangles) { int load_triangles(fbxsdk::FbxNodeAttribute* attr, std::vector<V3>& indices, std::vector<V3>& triangles) {
if (!attr || attr->GetAttributeType() != FbxNodeAttribute::eMesh) return false;
FbxMesh* mesh = static_cast<FbxMesh*>(attr); FbxMesh* mesh = static_cast<FbxMesh*>(attr);
// 顶点数据
// int ctrlPointCount = mesh->GetControlPointsCount();
// vertices.assign(mesh->GetControlPoints(), mesh->GetControlPoints() + ctrlPointCount);
// 三角化并提取三角形索引
FbxGeometryConverter converter(mesh->GetFbxManager());
if (!converter.Triangulate(mesh, true)) return false; // 强制三角化
int polyCount = mesh->GetPolygonCount(); int polyCount = mesh->GetPolygonCount();
triangles.reserve(polyCount);
for (int i = 0; i < polyCount; ++i) { for (int i = 0; i < polyCount; ++i) {
if (mesh->GetPolygonSize(i) != 3) continue; // 跳过非三角形(理论上不会存在) int vertexCount = mesh->GetPolygonSize(i);
int i0 = mesh->GetPolygonVertex(i, 0); std::vector<int> polyIndices;
int i1 = mesh->GetPolygonVertex(i, 1); for (int j = 0; j < vertexCount; ++j) {
int i2 = mesh->GetPolygonVertex(i, 2); polyIndices.push_back(mesh->GetPolygonVertex(i, j));
triangles.emplace_back(i0, i1, i2);
} }
return true; for (int j = 2; j < vertexCount; ++j) {
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;
} }
FbxNode* get_fbx_root_node(const char* fbx_path) FbxNode* get_fbx_root_node(const char* fbx_path)
@ -55,7 +57,7 @@ FbxNode* get_fbx_root_node(const char* fbx_path)
} }
void each_node(const FttContext* ctx, FbxNode* parent_node, int level) void each_node(FttContext* ctx, FbxNode* parent_node, int level)
{ {
// info // info
print_node_info(parent_node, level); print_node_info(parent_node, level);
@ -65,12 +67,20 @@ void each_node(const 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<Triangle> triangles; std::vector<V3> vertices;
int count = load_triangles(attr, triangles); std::vector<V3> triangles;
printf("triangles: %ld\n", triangles.size()); int count = load_triangles(attr, vertices, triangles);
uint id = attr->GetUniqueID();
printf("[%ld]triangles: %ld\n", id, triangles.size());
// 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,
id,
attr->GetName(),
vertices.size(), triangles.size(),
parent_node->GetNameOnly().Buffer());
} }
} }

View File

@ -1,6 +1,35 @@
#include <sqlite3.h> #include <tools.h>
using namespace std;
/**
* @brief SQLite数据库连接
* @param db_path
* @param overwrite_file true则删除已有文件后创建新数据库
* @return sqlite3句柄NULL
*/
sqlite3* create_db(const char* db_path, bool overwrite_file); sqlite3* create_db(const char* db_path, bool overwrite_file);
/**
* @brief
* @param db SQLite数据库句柄
* @note db参数有效且已成功打开
*/
void create_tables(sqlite3* db); void create_tables(sqlite3* db);
///////////////////////////
//////// 数据保存 /////////
///////////////////////////
/**
* @brief
* @param ctx FTT上下文句柄/
* @param db SQLite数据库连接
* @param name ()
* @param vertex_count
* @param index_count
* @param fbx_id FBX文件ID
* @return SQLITE_OKSQLite错误码(<0)
* @note 1. ctx/db非NULLname/fbx_id非空
* 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);

View File

@ -1,11 +1,8 @@
#include <fbxsdk.h>
#include <vector>
#include <tools.h> #include <tools.h>
#include <tuple>
using namespace std; using namespace std;
using Triangle = std::tuple<int, int, int>; using V3 = std::tuple<int, int, int>;
/** /**
* FBX节点树结构 * FBX节点树结构
@ -14,7 +11,7 @@ using Triangle = std::tuple<int, int, int>;
* @note 访parent_node的所有直接子节点和间接子节点 * @note 访parent_node的所有直接子节点和间接子节点
* @warning parent_node无效 * @warning parent_node无效
*/ */
void each_node(const FttContext* ctx, FbxNode* parent_node, int level); void each_node(FttContext* ctx, FbxNode* parent_node, int level);
/** /**
* FBX节点的基本信息 * FBX节点的基本信息
* @param node nullptr时输出警告日志 * @param node nullptr时输出警告日志
@ -32,11 +29,13 @@ void print_node_info(FbxNode* node, int level);
*/ */
FbxNode* get_fbx_root_node(const char* fbx_path); FbxNode* get_fbx_root_node(const char* fbx_path);
/** /**
* FBX属性提取三角形数据并填充到向量 * @brief FBX网格属性加载顶点数据和三角化索引
* @param attr FBX节点属性指针Mesh类型Mesh类型返回0 * @param[in] attr FBX节点属性FbxMesh类型
* @param triangles * @param[out] vertices Triangle存储3个FbxVector4顶点
* @return int -1attr为空或非Mesh类型 * @param[out] triangles Triangle存储3个顶点索引
* @note * @return bool truefalse
* @note
*/ */
int load_triangles(fbxsdk::FbxNodeAttribute* attr, std::vector<Triangle>& triangles); int load_triangles(fbxsdk::FbxNodeAttribute* attr, std::vector<V3>& indices, std::vector<V3>& triangles);

View File

@ -1,5 +1,14 @@
#ifndef _TOOLS_H_
#define _TOOLS_H_
#include <fbxsdk.h>
#include <tuple>
#include <vector>
#include <sqlite3.h> #include <sqlite3.h>
#include <string>
using namespace std;
typedef struct { typedef struct {
char* fbx_file; char* fbx_file;
@ -8,5 +17,7 @@ typedef struct {
sqlite3* db; sqlite3* db;
} FttContext; } FttContext;
FttContext ctx_from_const(const FttContext* ctx);
#endif
void create_tables(sqlite3* db);

11
cpp_src/tools.cpp Normal file
View File

@ -0,0 +1,11 @@
#include <tools.h>
FttContext ctx_from_const(const FttContext* ctx) {
FttContext mut_ctx;
mut_ctx.db = ctx->db;
mut_ctx.fbx_file = ctx->fbx_file;
mut_ctx.out_dir = ctx->out_dir;
return mut_ctx;
}

View File

@ -1,8 +1,8 @@
use std::{ffi::CString, os::raw::c_char}; use std::{ffi::CString, os::raw::c_char};
fn main() { fn main() {
convert_fbx_to_3dtiles("/root/data/绿科-三维视图-{三维}111.fbx", convert_fbx_to_3dtiles("/root/src/fbx_to_3dtiles/out/绿科-三维视图-{三维}111.fbx",
"/root/data/out/lk"); "/root/src/fbx_to_3dtiles/out/lk");
} }
#[repr(C)] #[repr(C)]