Overflow evaluating the requirement `glass::builtins::materials::Lambertian: glass::builtins::materials::Material<glass::builtins::materials::Lambertian>`

Hi! I'm making a ray tracer, and am stuck on materials. I have the classes (Lambertian and Metal) but for some reason I'm getting this error:

error[E0275]: overflow evaluating the requirement `glass::builtins::materials::Lambertian: glass::builtins::materials::Material<glass::builtins::materials::Lambertian>`
  --> src/main.rs:35:18
   |
35 |           Box::new(Sphere::new(
   |  __________________^
36 | |             Point3::new(0.0, -100.5, -1.0),
37 | |             100.0,
38 | |             Lambertian::new(Color::new(0.8, 0.8, 0.0)),
39 | |         )),
   | |_________^
   |
   = note: required for `glass::builtins::materials::Lambertian` to implement `glass::builtins::materials::Material<glass::builtins::materials::Lambertian>`
note: required by a bound in `glass::types::obj::Sphere::<T>::new`
  --> /project/workspace/src/types/obj.rs:53:15
   |
53 |     T: Copy + Material<T>,
   |               ^^^^^^^^^^^ required by this bound in `Sphere::<T>::new`
54 | {
55 |     pub fn new(center: Vec3, radius: f64, mat: T) -> Self {
   |            --- required by a bound in this associated function

For more information about this error, try `rustc --explain E0275`.

Here's my main.rs file:

use std::{
    error::Error,
    fs::File,
    io::{stdout, Write},
};

use crate::{
    builtins::materials::Material,
    types::{Color, Point3, Ray, Vec3},
    utils::{random, write_color},
};

use super::cast::Hittable;

pub struct CameraConfig {
    pub display_width: i32,
    pub display_height: i32,
    pub focal_length: f64,
    pub viewport_height: f64,
    pub samples_per_pixel: i32,
    pub max_depth: i32,
}

// TODO: implement wasm canvas
pub struct Camera {
    display_width: i32,
    display_height: i32,

    focal_length: f64,
    viewport_height: f64,
    viewport_width: f64,
    pub camera_center: Vec3,

    viewport_u: Vec3,
    viewport_v: Vec3,

    pixel_delta_u: Vec3,
    pixel_delta_v: Vec3,

    viewport_upper_left: Vec3,
    pixel00_loc: Vec3,

    pub samples_per_pixel: i32,
    pixel_samples_scale: f64,
    pub max_depth: i32,
}

impl Camera {
    pub fn render<T, M>(&self, world: T) -> Result<(), Box<dyn Error>>
    where
        T: Hittable<M>,
        M: Copy + Material<M> + Default,
    {
        let mut w = stdout();
        let mut file: File = File::create("out.ppm").unwrap();

        //println!("P3\n{} {}\n255", display_width, display_height);
        let _ = file
            .write(format!("P3\n{} {}\n255\n", self.display_width, self.display_height).as_bytes());

        for j in 0..self.display_height {
            w.write_all(format!("\rScanlines remaining: {}", self.display_height - j).as_bytes())?;
            w.flush()?;
            for i in 0..self.display_width {
                let mut pixel_color: Color = Color::new(0.0, 0.0, 0.0);
                for _sample in 0..self.samples_per_pixel {
                    let r: Ray = self.get_ray(i, j);
                    pixel_color += r.to_color(self.max_depth, &world);
                }
                write_color(&mut file, pixel_color * self.pixel_samples_scale)?;
            }
        }
        w.write_all(b"\rDone.                          \n")?;
        w.flush()?;
        Ok(())
    }

    fn get_ray(&self, i: i32, j: i32) -> Ray {
        let offset = Camera::sample_square();
        let pixel_sample = self.pixel00_loc
            + (self.pixel_delta_u * (i as f64 + offset.x))
            + (self.pixel_delta_v * (j as f64 + offset.y));

        let ray_origin = self.camera_center;
        let ray_direction = pixel_sample - ray_origin;

        Ray::new(ray_origin, ray_direction)
    }

    fn sample_square() -> Vec3 {
        Vec3::new(random() - 0.5, random() - 0.5, 0.0)
    }

    pub fn reinit(&mut self, value: CameraConfig) {
        self.display_width = value.display_width;
        self.display_height = value.display_height;
        self.focal_length = value.focal_length;
        self.viewport_height = value.viewport_height;
        self.viewport_width =
            value.viewport_height * (value.display_width as f64 / value.display_height as f64);
        self.camera_center = Point3::new(0.0, 0.0, 0.0);
        self.viewport_u = Vec3::new(self.viewport_width, 0.0, 0.0);
        self.viewport_v = Vec3::new(0.0, -self.viewport_height, 0.0);
        self.pixel_delta_u = self.viewport_u / self.display_width as f64;
        self.pixel_delta_v = self.viewport_v / self.display_height as f64;
        self.viewport_upper_left = self.camera_center
            - Vec3::new(0.0, 0.0, self.focal_length)
            - self.viewport_u / 2.0
            - self.viewport_v / 2.0;
        self.pixel00_loc =
            self.viewport_upper_left + (self.pixel_delta_u + self.pixel_delta_v) * 0.5;

        self.samples_per_pixel = value.samples_per_pixel;
        self.pixel_samples_scale = 1.0 / self.samples_per_pixel as f64;
        self.max_depth = value.max_depth;
    }
}

impl From<CameraConfig> for Camera {
    fn from(value: CameraConfig) -> Self {
        let display_width = value.display_width;
        let display_height = value.display_height;
        let focal_length = value.focal_length;
        let viewport_height = value.viewport_height;
        let viewport_width =
            value.viewport_height * (value.display_width as f64 / value.display_height as f64);
        let camera_center = Point3::new(0.0, 0.0, 0.0);
        let viewport_u = Vec3::new(viewport_width, 0.0, 0.0);
        let viewport_v = Vec3::new(0.0, -viewport_height, 0.0);
        let pixel_delta_u = viewport_u / display_width as f64;
        let pixel_delta_v = viewport_v / display_height as f64;
        let viewport_upper_left =
            camera_center - Vec3::new(0.0, 0.0, focal_length) - viewport_u / 2.0 - viewport_v / 2.0;
        let pixel00_loc = viewport_upper_left + (pixel_delta_u + pixel_delta_v) * 0.5;
        let samples_per_pixel = value.samples_per_pixel;
        let pixel_samples_scale = 1.0 / samples_per_pixel as f64;
        let max_depth = value.max_depth;

        Self {
            display_width,
            display_height,
            focal_length,
            viewport_height,
            viewport_width,
            camera_center,
            viewport_u,
            viewport_v,
            pixel_delta_u,
            pixel_delta_v,
            viewport_upper_left,
            pixel00_loc,
            samples_per_pixel,
            pixel_samples_scale,
            max_depth,
        }
    }
}

And my cast.rs file:

use crate::{
    builtins::materials::Material,
    types::{Interval, Ray, Vec3},
};

#[derive(Default, Clone, Copy, Debug)]
pub struct HitRecord<T>
where
    T: Copy + Material<T>,
{
    pub t: f64,
    pub p: Vec3,
    pub mat: T,
    pub normal: Vec3,
    pub front_face: bool,
}

impl<T> HitRecord<T>
where
    T: Copy + Material<T>,
{
    pub fn set_face_normal(&mut self, r: Ray, outward_normal: Vec3) {
        self.front_face = r.direction.dot(outward_normal) < 0.0;
        self.normal = if self.front_face {
            outward_normal
        } else {
            -outward_normal
        };
    }
}

pub trait Hittable<T> {
    fn hit(&self, _r: Ray, _ray_t: Interval, _rec: &mut HitRecord<T>) -> bool
    where
        T: Copy + Material<T>,
    {
        false
    }
}

impl<T> Hittable<T> for Vec<Box<dyn Hittable<T>>>
where
    T: Copy + Material<T> + Default,
{
    fn hit(&self, r: Ray, ray_t: Interval, rec: &mut HitRecord<T>) -> bool {
        let mut temp_rec: HitRecord<T> = HitRecord::default();
        let mut hit: bool = false;
        let mut _closest: f64 = ray_t.max;
        for i in self {
            if i.hit(r, ray_t, &mut temp_rec) {
                hit = true;
                _closest = temp_rec.t;
                *rec = temp_rec;
            }
        }
        hit
    }
}

And my material.rs:

use crate::{
    checks::cast::HitRecord,
    types::{Color, Ray, Vec3},
};

pub trait Material<T>
where
    T: Copy + Material<T>,
{
    fn scatter(
        &self,
        _r_in: Ray,
        _rec: &HitRecord<T>,
        _attenuation: &mut Color,
        _scattered: &mut Ray,
    ) -> bool {
        false
    }
}

#[derive(Clone, Copy, Default)]
pub struct Lambertian {
    pub albedo: Color,
}

impl<T> Material<T> for Lambertian
where
    T: Copy + Material<T>,
{
    fn scatter(
        &self,
        _r_in: Ray,
        rec: &HitRecord<T>,
        attenuation: &mut Color,
        scattered: &mut Ray,
    ) -> bool {
        let mut scatter_direction = rec.normal + Vec3::random_unit_vector();

        if scatter_direction.near_zero() {
            scatter_direction = rec.normal;
        }

        *scattered = Ray::new(rec.p, scatter_direction);
        *attenuation = self.albedo;
        true
    }
}

impl Lambertian {
    pub fn new(albedo: Color) -> Self {
        Self { albedo }
    }
}

#[derive(Clone, Copy, Default)]
pub struct Metal {
    pub albedo: Color,
}

impl<T> Material<T> for Metal
where
    T: Copy + Material<T>,
{
    fn scatter(
        &self,
        r_in: Ray,
        rec: &HitRecord<T>,
        attenuation: &mut Color,
        scattered: &mut Ray,
    ) -> bool {
        let reflected = r_in.direction.reflect(rec.normal);
        *scattered = Ray::new(rec.p, reflected);
        *attenuation = self.albedo;
        true
    }
}

impl Metal {
    pub fn new(albedo: Color) -> Self {
        Self { albedo }
    }
}

I can provide any other files as needed, but what seems to be wrong? Lambertian implements Material, so it should work, right? Any help is appreciated, thanks!

It looks like your trait Material has an extra type parameter <T> it does not need. Remove it and write your bounds as just T: Material and your implementations as impl Material for Lambertian.

Sorry for the late response! I need the type parameter for the HitRecord struct in cast.rs, so I can specify that an item needs to implement Material.

EDIT: Code is unneeded; already specified.

Yes, HitRecord as written has and needs a type parameter. But Material does not.

I actually did just find out how many redundant and unnecessary type parameters I had! I also wrote an enum which included all of the materials that I implemented Material on (an earlier error message told me to) and it works! Thanks for the help, though, you were right!

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.