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!