Rust 3D空间分割库plane-split的使用,高效处理多边形平面分割与BSP树构建

Rust 3D空间分割库plane-split的使用,高效处理多边形平面分割与BSP树构建

plane-split是一个用于3D空间平面分割的Rust库,基于euclid几何库开发,主要用于WebRender项目。

安装

在项目中添加以下依赖到Cargo.toml:

plane-split = "0.18.0"

或者运行命令:

cargo add plane-split

基本使用示例

以下是使用plane-split库进行多边形分割的基本示例:

use euclid::{Point3D, Vector3D};
use plane_split::{Plane, Polygon};

fn main() {
    // 创建一个分割平面
    let plane = Plane::from_unnormalized(
        Vector3D::new(1.0, 0.0, 0.0), // 法线向量
        Point3D::new(0.0, 0.0, 0.0),  // 平面上的点
    ).unwrap();

    // 创建一个多边形
    let polygon = Polygon::from_points(
        vec![
            Point3D::new(-1.0, -1.0, 0.0),
            Point3D::new(1.0, -1.0, 0.0),
            Point3D::new(1.0, 1.0, 0.0),
            Point3D::new(-1.0, 1.0, 0.0),
        ],
        0, // 多边形ID
    ).unwrap();

    // 使用平面分割多边形
    let split_result = plane.split(&polygon);
    
    match split_result {
        Some((front, back)) => {
            println!("多边形被分割为两部分:");
            println!("- 平面正面部分: {:?}", front);
            println!("- 平面背面部分: {:?}", back);
        }
        None => {
            println!("多边形未被分割");
        }
    }
}

构建BSP树示例

以下是使用plane-split构建BSP树的完整示例:

use euclid::{Point3D, Vector3D};
use plane_split::{BspSplitter, Plane, Polygon};

fn main() {
    // 创建BSP分割器
    let mut splitter = BspSplitter::new();

    // 创建几个多边形
    let polygon1 = Polygon::from_points(
        vec![
            Point3D::new(0.0, 0.0, 0.0),
            Point3D::new(1.0, 0.0, 0.0),
            Point3D::new(1.0, 1.0, 0.0),
            Point3D::new(0.0, 1.0, 0.0),
        ],
        1, // 多边形ID
    ).unwrap();

    let polygon2 = Polygon::from_points(
        vec![
            Point3D::new(0.5, 0.5, 0.5),
            Point3D::new(1.5, 0.5, 0.5),
            Point3D::new(1.5, 1.5, 0.5),
            Point3D::new(0.5, 1.5, 0.5),
        ],
        2, // 多边形ID
    ).unwrap();

    // 添加多边形到BSP树
    splitter.add(polygon1);
    splitter.add(polygon2);

    // 构建BSP树并获取有序多边形列表
    let ordered = splitter.ordered();

    println!("BSP树排序后的多边形:");
    for poly in ordered {
        println!("- 多边形ID: {}, 顶点: {:?}", poly.anchor, poly.points);
    }
}

高级功能

plane-split还支持:

  • 多边形的剪切和合并
  • 平面与多边形的相交测试
  • 多边形到平面的投影
  • 自动生成分割平面

完整示例代码

以下是一个更完整的示例,展示如何使用plane-split进行复杂的3D空间分割:

use euclid::{Point3D, Vector3D, default::Point3D as DefaultPoint3D};
use plane_split::{BspSplitter, Plane, Polygon};

fn main() {
    // 创建多个多边形
    let polygons = vec![
        // 地面多边形
        Polygon::from_points(
            vec![
                Point3D::new(-5.0, -5.0, 0.0),
                Point3D::new(5.0, -5.0, 0.0),
                Point3D::new(5.0, 5.0, 0.0),
                Point3D::new(-5.0, 5.0, 0.0),
            ],
            0, // ID
        ).unwrap(),
        
        // 墙面多边形
        Polygon::from_points(
            vec![
                Point3D::new(-2.0, -5.0, 0.0),
                Point3D::new(-2.0, -5.0, 3.0),
                Point3D::new(-2.0, 5.0, 3.0),
                Point3D::new(-2.0, 5.0, 0.0),
            ],
            1, // ID
        ).unwrap(),
        
        // 倾斜多边形
        Polygon::from_points(
            vec![
                Point3D::new(1.0, -3.0, 1.0),
                Point3D::new(3.0, -3.0, 2.0),
                Point3D::new(3.0, 3.0, 2.0),
                Point3D::new(1.0, 3.0, 1.0),
            ],
            2, // ID
        ).unwrap(),
    ];

    // 创建BSP分割器
    let mut splitter = BspSplitter::new();

    // 添加所有多边形到BSP树
    for polygon in polygons {
        splitter.add(polygon);
    }

    // 获取排序后的多边形列表
    let ordered = splitter.ordered();

    // 打印结果
    println!("BSP树排序后的多边形(从远到近):");
    for (i, poly) in ordered.iter().enumerate() {
        println!("{}. 多边形ID: {}", i + 1, poly.anchor);
        for point in &poly.points {
            println!("   顶点: ({:.1}, {:.1}, {:.1})", 
                point.x, point.y, point.z);
        }
    }

    // 创建一个分割平面
    let split_plane = Plane::from_unnormalized(
        Vector3D::new(0.0, 1.0, 0.0), // Y轴法线
        Point3D::new(0.0, 0.0, 0.0),  // 原点
    ).unwrap();

    // 测试分割第一个多边形
    if let Some(poly) = ordered.first() {
        println!("\n测试分割第一个多边形:");
        match split_plane.split(poly) {
            Some((front, back)) => {
                println!("分割成功 - 前面部分有 {} 个顶点", front.points.len());
                println!("分割成功 - 后面部分有 {} 个顶点", back.points.len());
            }
            None => {
                println!("多边形与平面平行,无需分割");
            }
        }
    }
}

许可证

plane-split使用MPL-2.0许可证。


1 回复

Rust 3D空间分割库plane-split使用指南

完整示例demo

下面是一个完整的plane-split使用示例,展示了创建多边形、分割操作以及BSP树构建的完整流程:

use plane_split::{BspSplitter, Polygon, Splitter, Plane};
use nalgebra::{Point3, Vector3};

fn main() {
    // 设置精度容差
    plane_split::set_epsilon(1e-6);

    // 1. 创建多边形
    let polygon1 = Polygon::from_points(
        vec![
            Point3::new(0.0, 0.0, 0.0),
            Point3::new(2.0, 0.0, 0.0),
            Point3::new(2.0, 2.0, 0.0),
            Point3::new(0.0, 2.0, 0.0),
        ],
        Vector3::new(0.0, 0.0, 1.0), // 法线方向
    );

    let polygon2 = Polygon::from_points(
        vec![
            Point3::new(1.0, 1.0, 1.0),
            Point3::new(3.0, 1.0, 1.0),
            Point3::new(3.0, 3.0, 1.0),
            Point3::new(1.0, 3.0, 1.0),
        ],
        Vector3::new(0.0, 0.0, 1.0),
    );

    // 2. 多边形分割演示
    let split_plane = Plane::from_unnormalized(
        Vector3::new(0.0, 0.0, 1.0),
        Point3::new(1.5, 1.5, 0.0)
    ).unwrap();

    println!("分割多边形...");
    let (front, back) = polygon1.split(&split_plane);
    println!("分割结果 - 前面部分: {:?}, 后面部分: {:?}", front.is_some(), back.is_some());

    // 3. BSP树构建和排序
    println!("\n构建BSP树...");
    let mut splitter = BspSplitter::new();
    splitter.add(polygon1);
    splitter.add(polygon2);

    // 从不同视角获取排序结果
    println!("\n从(0,0,5)视角排序:");
    let camera_pos1 = Vector3::new(0.0, 0.0, 5.0);
    let sorted1 = splitter.sort(camera_pos1);
    println!("排序后多边形数量: {}", sorted1.len());

    println!("\n从(5,5,5)视角排序:");
    let camera_pos2 = Vector3::new(5.0, 5.0, 5.0);
    let sorted2 = splitter.sort(camera_pos2);
    println!("排序后多边形数量: {}", sorted2.len());
}

代码说明

  1. 精度设置:使用set_epsilon设置空间分割的精度容差值
  2. 多边形创建:创建两个四边形多边形,分别位于Z=0和Z=1平面
  3. 分割演示:使用一个平面分割第一个多边形,展示分割操作
  4. BSP树构建
    • 创建BspSplitter实例
    • 添加多边形到分割器中
  5. 视角排序
    • 从两个不同视角(0,0,5)和(5,5,5)获取排序后的多边形列表
    • 排序结果是从后到前的顺序,适合透明度渲染

运行结果预期

程序将输出:

  • 多边形分割的结果(前面和后面部分是否存在)
  • 从两个不同视角排序后的多边形数量

实际应用建议

  1. 对于游戏场景,可以预先构建所有静态物体的BSP树
  2. 动态物体可以每帧更新或使用单独的BSP树
  3. 考虑将结果用于透明度排序渲染或碰撞检测
  4. 对于复杂场景,可以分层级构建BSP树以提高效率

这个完整示例展示了plane-split库的核心功能,您可以根据实际需求扩展更多功能,如自定义分割策略、处理更复杂的多边形等。

回到顶部