Rust FBX文件解析库ufbx的使用,ufbx提供高性能FBX格式3D模型加载与处理功能

Rust FBX文件解析库ufbx的使用

ufbx是一个提供高性能FBX格式3D模型加载与处理功能的Rust库。

安装

在项目目录中运行以下Cargo命令:

cargo add ufbx

或者在你的Cargo.toml中添加:

ufbx = "0.9.0"

使用示例

下面是一个基本的FBX文件加载示例:

use ufbx;

fn main() {
    // 加载FBX文件
    let scene = ufbx::load_file("example.fbx", ufbx::LoadOpts::default())
        .expect("Failed to load FBX file");

    // 打印场景信息
    println!("Loaded FBX scene:");
    println!("- Meshes: {}", scene.meshes.len());
    println!("- Materials: {}", scene.materials.len());
    println!("- Lights: {}", scene.lights.len());
    println!("- Cameras: {}", scene.cameras.len());
    
    // 遍历所有网格
    for mesh in &scene.meshes {
        println!("Mesh '{}' has {} vertices", mesh.name, mesh.vertices.len());
        
        // 打印材质信息
        if let Some(material) = mesh.material {
            println!("  Material: '{}'", material.name);
        }
    }
}

完整示例

以下是一个更完整的示例,展示了如何加载FBX文件并提取网格数据:

use ufbx;

fn main() {
    // 加载选项可以自定义
    let opts = ufbx::LoadOpts {
        // 忽略动画数据
        ignore_animation: true,
        // 其他选项...
        ..Default::default()
    };

    // 加载FBX文件
    let scene = ufbx::load_file("model.fbx", opts)
        .expect("Failed to load FBX file");

    // 处理网格数据
    for mesh in &scene.meshes {
        println!("Processing mesh: {}", mesh.name);
        
        // 顶点数据
        let vertices = &mesh.vertices;
        println!("  Vertex count: {}", vertices.len());
        
        // 索引数据
        if let Some(indices) = &mesh.indices {
            println!("  Triangle count: {}", indices.len() / 3);
        }
        
        // 材质信息
        if let Some(material) = mesh.material {
            println!("  Material: {}", material.name);
            
            // 获取漫反射颜色
            if let Some(diffuse) = &material.diffuse_color {
                println!("    Diffuse color: {:?}", diffuse);
            }
        }
        
        // UV坐标
        if let Some(uvs) = &mesh.uvs {
            println!("  UV coordinates available");
        }
        
        // 法线
        if let Some(normals) = &mesh.normals {
            println!("  Normals available");
        }
    }
}

特性

ufbx提供以下主要功能:

  • 高性能的FBX文件解析
  • 完整的场景层次结构访问
  • 网格、材质、灯光、相机等数据提取
  • 动画数据处理
  • 自定义加载选项

完整示例demo

基于上述示例,下面是一个更完整的FBX文件处理demo:

use ufbx;

fn main() {
    // 设置加载选项
    let opts = ufbx::LoadOpts {
        ignore_animation: true,  // 忽略动画数据
        triangulate: true,       // 自动三角化网格
        normalize_normals: true, // 标准化法线
        ..Default::default()
    };

    // 加载FBX文件
    let scene = match ufbx::load_file("character.fbx", opts) {
        Ok(scene) => scene,
        Err(e) => {
            eprintln!("Error loading FBX file: {}", e);
            return;
        }
    };

    // 打印场景摘要信息
    print_scene_summary(&scene);
    
    // 处理网格数据
    process_meshes(&scene);
    
    // 处理材质数据
    process_materials(&scene);
}

fn print_scene_summary(scene: &ufbx::Scene) {
    println!("场景摘要:");
    println!("- 网格数量: {}", scene.meshes.len());
    println!("- 材质数量: {}", scene.materials.len());
    println!("- 灯光数量: {}", scene.lights.len());
    println!("- 相机数量: {}", scene.cameras.len());
    println!("- 根节点数量: {}", scene.root_nodes.len());
}

fn process_meshes(scene: &ufbx::Scene) {
    println!("\n处理网格数据:");
    
    for (i, mesh) in scene.meshes.iter().enumerate() {
        println!("\n网格 #{}: '{}'", i + 1, mesh.name);
        
        // 顶点数据
        println!("  顶点数: {}", mesh.vertices.len());
        
        // 索引数据
        if let Some(indices) = &mesh.indices {
            println!("  三角形数: {}", indices.len() / 3);
        }
        
        // UV坐标
        if let Some(uvs) = &mesh.uvs {
            println!("  UV层数: {}", uvs.len());
        }
        
        // 法线
        if let Some(normals) = &mesh.normals {
            println!("  法线数据可用");
        }
    }
}

fn process_materials(scene: &ufbx::Scene) {
    println!("\n处理材质数据:");
    
    for (i, material) in scene.materials.iter().enumerate() {
        println!("\n材质 #{}: '{}'", i + 1, material.name);
        
        // 漫反射颜色
        if let Some(diffuse) = &material.diffuse_color {
            println!("  漫反射颜色: {:?}", diffuse);
        }
        
        // 镜面反射颜色
        if let Some(specular) = &material.specular_color {
            println!("  镜面反射颜色: {:?}", specular);
        }
        
        // 透明度
        println!("  透明度: {}", material.transparency_factor);
    }
}

1 回复

Rust FBX文件解析库ufbx的使用指南

ufbx是一个高性能的FBX格式3D模型加载与处理库,专为Rust设计。它提供了快速、安全的FBX文件解析功能,适用于游戏开发、3D建模工具和其他需要处理FBX文件的应用程序。

主要特性

  • 高性能解析FBX文件
  • 内存安全的Rust实现
  • 支持ASCII和二进制FBX格式
  • 完整的场景图访问
  • 网格、材质、纹理、动画等数据提取
  • 轻量级设计

安装方法

在Cargo.toml中添加依赖:

[dependencies]
ufbx = "0.7"  # 请检查最新版本

基本使用方法

加载FBX文件

use ufbx;

fn main() -> Result<(), ufbx::Error> {
    // 加载FBX文件
    let scene = ufbx::load_file("model.fbx")?;
    
    // 打印场景基本信息
    println!("Loaded scene with {} meshes", scene.meshes.len());
    println!("Scene units: {} meters", scene.unit_meters);
    
    Ok(())
}

遍历场景节点

fn print_node_hierarchy(node: &ufbx::Node, depth: usize) {
    let indent = "  ".repeat(depth);
    println!("{}{}", indent, node.name);
    
    for child in &node.children {
        print_node_hierarchy(child, depth + 1);
    }
}

// 使用示例
let scene = ufbx::load_file("model.fbx")?;
print_node_hierarchy(&scene.root, 0);

提取网格数据

let scene = ufbx::load_file("model.fbx")?;

for mesh in &scene.meshes {
    println!("Mesh: {}", mesh.name);
    println!("  Vertex count: {}", mesh.vertices.len());
    
    // 访问顶点位置
    for vertex in &mesh.vertices {
        println!("    Vertex: {:?}", vertex);
    }
    
    // 访问面数据
    for face in &mesh.faces {
        println!("    Face vertex count: {}", face.num_indices);
    }
}

处理材质和纹理

let scene = ufbx::load_file("model.fbx")?;

for material in &scene.materials {
    println!("Material: {}", material.name);
    
    if let Some(diffuse) &material.diffuse_color {
        println!("  Diffuse color: {:?}", diffuse.value);
    }
    
    if let Some(texture) = material.diffuse_texture.as_ref() {
        println!("  Diffuse texture: {}", texture.texture.name);
        println!("  Texture file: {:?}", texture.texture.file_name);
    }
}

处理动画数据

let scene = ufbx::load_file("animated_model.fbx")?;

for anim_stack in &scene.anim_stacks {
    println!("Animation stack: {}", anim_stack.name);
    
    for layer in &anim_stack.layers {
        println!("  Layer: {}", layer.name);
        
        for anim in &layer.anims {
            println!("    Anim: {}", anim.node.name);
            println!("    Keyframes: {}", anim.curves.len());
        }
    }
}

高级用法

自定义加载选项

let opts = ufbx::LoadOpts {
    target_axes: ufbx::CoordinateAxes {
        front: ufbx::Axis::PositiveZ,
        up: ufbx::Axis::PositiveY,
        right: ufbx::Axis::PositiveX,
        unit_meters: 1.0,
    },
    ..Default::default()
};

let scene = ufbx::load_file_with_opts("model.fbx", opts)?;

内存中加载FBX数据

let data = std::fs::read("model.fbx")?;
let scene = ufbx::load_from_memory(&data, ufbx::LoadOpts::default())?;

性能提示

  1. 对于大型FBX文件,考虑在后台线程加载
  2. 如果只需要部分数据,可以检查加载选项以跳过不需要的部分
  3. 加载后可以释放不再需要的原始数据

错误处理

match ufbx::load_file("model.fbx") {
    Ok(scene) => {
        // 处理场景
    },
    Err(ufbx::Error::Io(e)) => {
        eprintln!("IO error: {}", e);
    },
    Err(ufbx::Error::Data(e)) => {
        eprintln!("FBX data error: {}", e);
    },
    Err(e) => {
        eprintln!("Unknown error: {}", e);
    }
}

完整示例代码

下面是一个完整的示例,展示如何加载FBX文件并提取各种数据:

use ufbx;

fn main() -> Result<(), ufbx::Error> {
    // 1. 加载FBX文件
    let scene = ufbx::load_file("model.fbx")?;
    
    // 2. 打印场景基本信息
    println!("场景单位: {} 米", scene.unit_meters);
    println!("网格数量: {}", scene.meshes.len());
    println!("材质数量: {}", scene.materials.len());
    println!("动画堆栈数量: {}", scene.anim_stacks.len());
    
    // 3. 遍历节点层次结构
    fn print_nodes(node: &ufbx::Node, depth: usize) {
        let indent = "  ".repeat(depth);
        println!("{}- {}", indent, node.name);
        
        for child in &node.children {
            print_nodes(child, depth + 1);
        }
    }
    
    println!("\n场景节点层次:");
    print_nodes(&scene.root, 0);
    
    // 4. 处理网格数据
    println!("\n网格信息:");
    for mesh in &scene.meshes {
        println!("网格名称: {}", mesh.name);
        println!("  顶点数: {}", mesh.vertices.len());
        println!("  面数: {}", mesh.faces.len());
        
        // 打印前10个顶点位置
        println!("  前10个顶点:");
        for vertex in mesh.vertices.iter().take(10) {
            println!("    {:?}", vertex);
        }
    }
    
    // 5. 处理材质数据
    println!("\n材质信息:");
    for material in &scene.materials {
        println!("材质名称: {}", material.name);
        
        if let Some(diffuse) = &material.diffuse_color {
            println!("  漫反射颜色: {:?}", diffuse.value);
        }
        
        if let Some(texture) = material.diffuse_texture.as_ref() {
            println!("  漫反射纹理: {}", texture.texture.name);
            println!("  纹理文件: {:?}", texture.texture.file_name);
        }
    }
    
    // 6. 处理动画数据(如果有)
    if !scene.anim_stacks.is_empty() {
        println!("\n动画信息:");
        for anim_stack in &scene.anim_stacks {
            println!("动画堆栈: {}", anim_stack.name);
            
            for layer in &anim_stack.layers {
                println!("  图层: {}", layer.name);
                
                for anim in &layer.anims {
                    println!("    节点 {} 的关键帧数: {}", 
                        anim.node.name, anim.curves.len());
                }
            }
        }
    }
    
    Ok(())
}

这个完整示例展示了如何使用ufbx库加载FBX文件并提取各种数据,包括场景信息、节点层次结构、网格数据、材质信息和动画数据。您可以根据需要修改或扩展此示例来满足特定的应用需求。

回到顶部