Как я могу превратить Ve c трейт-объектов в древовидную структуру? - PullRequest
0 голосов
/ 11 июля 2020

Я пытаюсь реализовать алгоритм BVH в моем трассировщике лучей Rust, но у меня проблемы с временем жизни и владением. У меня есть черта Hittable, которую реализует множество разных вещей - Sphere, Triangle, Mesh, и c. Итак, у меня есть Vec<Box<dyn Hittable>>, который я хочу превратить в дерево этой структуры:

pub struct BvhNode {
    bounding_box: BoundingBox,
    left: Box<dyn Hittable>,
    right: Box<dyn Hittable>,
}

Итак, у меня есть рекурсивный алгоритм, который почти работает, если бы не пожизненные вопросы. Моя функция выглядит так:

    pub fn new(objects: Vec<Box<dyn Hittable>>, start: usize, end: usize, t0: f64, t1: f64) -> Self {
        let r = util::rand();
        let comp = if r < 1. / 3. {
            util::box_x_compare
        } else if r < 2. / 3. {
            util::box_y_compare
        } else {
            util::box_z_compare
        }; // which axis to compare along (random for now)
        let num_obj = end - start;
        let mut left: Box<dyn Hittable>;
        let mut right: Box<dyn Hittable>;
        if num_obj == 1 {
            left = objects[start];
            right = objects[start];
        } else if num_obj == 2 {
            if comp(&&objects[start], &&objects[start + 1]) != Ordering::Greater {
                left = objects[start];
                right = objects[start + 1];
            } else {
                left = objects[start + 1];
                right = objects[start];
            }
        } else {
            let mut slice: Vec<&Box<dyn Hittable>> = Vec::new();
            for i in start..end { // make a copy to sort
                slice.push(&objects[i]);
            }
            slice.sort_by(comp);
            let mid = start + num_obj / 2;
            let l = BvhNode::new(objects, start, mid, t0, t1);
            let r = BvhNode::new(objects, mid, end, t0, t1);
            left = Box::new(l.clone());
            right = Box::new(r.clone());
        }

        let left_box = left.get_bounding_box(t0, t1);
        let right_box = right.get_bounding_box(t0, t1);
        
        if left_box.is_none() || right_box.is_none() {
            println!("Error: No bounding box in Bvh Node");
            panic!();
        }

        Self { left, right, bounding_box: BoundingBox::new(Point3::origin(), Point3::origin()) }
    }

Во-первых, я столкнулся с некоторыми проблемами при попытке «выйти из ve c», чего я не могу сделать, поэтому я попытался реализовать Clone на все типы, реализующие Hittable. Это работает почти для всех из них, но моя Triangle struct

pub struct Triangle <'b> {
    mat: &'b Box<dyn Material>,
    bounding_box: Option<BoundingBox>,
    p: Vec<Point3<f64>>,
    n: Vec<Vector3<f64>>,
    uv: Vec<Vector2<f64>>,
}

содержит ссылку на материал связанного с ней меня sh, который не нравится клону. Я мог бы сделать клон самого Материала, но он потенциально может быть очень большим, и я не хочу иметь тысячи его копий для каждого треугольника в me sh.

Я чувствую, что должен быть лучший способ спроектировать мою систему, например, избавиться от ссылок в Triangle, чтобы ее можно было легко скопировать. Как только эта структура будет создана, мне больше не понадобится Vec, поэтому возможность move объектов извлекать из нее внутри копирования их также будет работать, но я не вижу способа сделать это. .

Если поможет, полный файл находится на GitHub здесь

1 Ответ

0 голосов
/ 11 июля 2020

Мне удалось решить эту проблему, изменив objects Ve c на &mut Vec<Box<dyn Hittable>>, а затем используя objects.remove() вместо индексации. Мне пришлось немного изменить алгоритм, чтобы он работал по-новому, но он должен работать.

...