在“ Ray Tracer挑战”之后,我一直在Rust中编写Ray Caster,并且一直很难弄清楚在Rust中实现多态性的正确方法。我的首要任务是可以在多线程程序中使用该对象,这似乎是主要问题。
我有两种情况,但我只关注一种:形状。有多种形状(坚持使用able
后缀,我最初将其称为特征Intersectable
)。这是一个有效的特征对象实现,但不适用于多线程:
#[derive(Debug)]
pub struct Shape {
pub parent: Option<Arc<Shape>>,
pub transform: Matrix4,
pub material: Material,
pub intersectable: Box<Intersectable>,
}
pub trait Intersectable: Debug + IntersectableClone {
fn local_intersect(&self, ray: &Ray, object: Arc<Shape>) -> Vec<Intersection>;
}
pub trait IntersectableClone {
fn clone_box(&self) -> Box<Intersectable>;
}
impl<T> IntersectableClone for T
where
T: 'static + Intersectable + Clone,
{
fn clone_box(&self) -> Box<Intersectable> {
Box::new(self.clone())
}
}
impl Clone for Box<Intersectable> {
fn clone(&self) -> Box<Intersectable> {
self.clone_box()
}
}
#[derive(Clone, Debug)]
pub struct Sphere {}
impl Intersectable for Sphere {
fn local_intersect(&self, ray: &Ray, object: Arc<Shape>) -> Vec<Intersection> {
...sphere specific code
}
}
#[derive(Clone, Debug)]
pub struct Plane {}
impl Intersectable for Plane {
fn local_intersect(&self, ray: &Ray, object: Arc<Shape>) -> Vec<Intersection> {
...plane specific code
}
}
作为纯结构,没有官方的多态性,我写了一种静态调度,看起来像这样:
#[derive(Debug, Clone)]
pub enum IntersectableType {
Sphere,
Plane,
}
#[derive(Debug, Clone)]
pub struct Intersectable {
intersectable_type: IntersectableType,
}
impl Intersectable {
pub fn local_intersect(&self, ray: &Ray, object: Arc<Shape>) -> Vec<Intersection> {
match self.intersectable_type {
IntersectableType::Sphere => self.local_intersect_sphere(ray, object),
IntersectableType::Plane => self.local_intersect_plane(ray, object),
_ => Vec::new(),
}
}
fn local_intersect_sphere(&self, ray: &Ray, object: Arc<Shape>) -> Vec<Intersection> {
...sphere specific code
}
fn local_intersect_plane(&self, ray: &Ray, object: Arc<Shape>) -> Vec<Intersection> {
...plane specific implementation
}
}
这很好用,但感觉很不生锈。我在使用其他实现时遇到了一些问题:
-使用Box<Intersectable>
(当它是Trait而不是结构时)很难克隆(我复制了How to clone a struct storing a boxed trait object?,但不喜欢使用'static,因为这使得并发成为不可能)。
-使用Arc<Intersectable>
似乎和Box
存在相同的问题,尽管也许有办法使之工作。
在Rust中有没有一种方法可以让我利用并发性,而不必像这样编写手动静态分派?
答案 0 :(得分:0)
我也在做“光线追踪挑战”,虽然比你落后一点。我没有考虑并发性。我现在尝试遵循 A-Frame ECS 的想法:
pub trait Primitive {}
pub struct Shape<T: Primitive> {
pub transformation: M4x4,
pub material: Material,
pub primitive: T,
}
pub struct Sphere;
impl Primitive for Sphere {}