Hi! I'm making an implementation of a ray tracer, but I'm getting stuck on this one portion, the Ray
struct. The errors I'm getting are this:
Hidden for space
error[E0277]: cannot multiply `Vec3<f64>` by `<f64 as Sub<T>>::Output`
--> src/types/ray.rs:23:60
|
23 | ...64>::new(1.0, 1.0, 1.0) * (1.0 - t.into()) + Vec3::<f64>::new(0.5, 0.7, 1.0) * t;
| ^ no implementation for `Vec3<f64> * <f64 as Sub<T>>::Output`
|
= help: the trait `Mul<<f64 as Sub<T>>::Output>` is not implemented for `Vec3<f64>`
= help: the following other types implement trait `Mul<Rhs>`:
<Vec3<f64> as Mul<i8>>
<Vec3<f64> as Mul<i16>>
<Vec3<f64> as Mul<i32>>
<Vec3<f64> as Mul<i64>>
<Vec3<f64> as Mul<i128>>
<Vec3<f64> as Mul<u8>>
<Vec3<f64> as Mul<u16>>
<Vec3<f64> as Mul<u32>>
and 16 others
error[E0308]: mismatched types
--> src/types/ray.rs:28:27
|
28 | let oc: Vec3<T> = self.origin - center;
| ------- ^^^^^^^^^^^^^^^^^^^^ expected `Vec3<T>`, found associated type
| |
| expected due to this
|
= note: expected struct `Vec3<T>`
found associated type `<Vec3<T> as Sub>::Output`
= help: consider constraining the associated type `<Vec3<T> as Sub>::Output` to `Vec3<T>`
= note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
error[E0308]: mismatched types
--> src/types/ray.rs:31:22
|
31 | let c: f64 = oc.dot(&oc) - radius * radius;
| --- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `f64`, found associated type
| |
| expected due to this
|
= note: expected type `f64`
found associated type `<f64 as Sub<T>>::Output`
= help: consider constraining the associated type `<f64 as Sub<T>>::Output` to `f64`
= note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
error[E0277]: cannot multiply `{integer}` by `f64`
--> src/types/ray.rs:32:43
|
32 | let discriminant: f64 = b * b - 4 * a * c;
| ^ no implementation for `{integer} * f64`
|
= help: the trait `Mul<f64>` is not implemented for `{integer}`
= help: the following other types implement trait `Mul<Rhs>`:
<isize as Mul>
<isize as Mul<&isize>>
<i8 as Mul>
<i8 as Mul<&i8>>
<i16 as Mul>
<i16 as Mul<&i16>>
<i32 as Mul>
<i32 as Mul<&i32>>
and 49 others
error[E0308]: mismatched types
--> src/types/ray.rs:32:33
|
32 | let discriminant: f64 = b * b - 4 * a * c;
| --- ^^^^^^^^^^^^^^^^^ expected `f64`, found associated type
| |
| expected due to this
|
= note: expected type `f64`
found associated type `<f64 as Sub<T>>::Output`
= help: consider constraining the associated type `<f64 as Sub<T>>::Output` to `f64`
= note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
Some errors have detailed explanations: E0277, E0308.
For more information about an error, try `rustc --explain E0277`.
Here's the ray.rs file:
Hidden for space
use std::ops::{Add, Div, Mul, Sub};
use super::Vec3;
#[derive(Debug, PartialEq, Eq, Copy, Clone, Default)]
pub struct Ray<T> {
pub origin: Vec3<T>,
pub direction: Vec3<T>
}
impl<T: Mul<Output = T> + Add<Output = T> + From<f64> + Into<f64> + Copy + Sub<Output = T>> Ray<T>
where Vec3<T>: Div<f64, Output = Vec3<T>> + Mul + Sub, f64: Sub<T> {
pub fn new(origin: Vec3<T>, direction: Vec3<T>) -> Self {
Self {
origin,
direction
}
}
pub fn to_color(&self) -> Vec3<f64> {
let unit_direction: Vec3<T> = self.direction.unit_vector();
let t: f64 = ((unit_direction.y + 1.0.into()) * 0.5.into()).into();
let g: Vec3<f64> = Vec3::<f64>::new(1.0, 1.0, 1.0) * (1.0 - t) + Vec3::<f64>::new(0.5, 0.7, 1.0) * t;
g
}
pub fn hit_sphere(&self, center: Vec3<T>, radius: T) -> bool {
let oc: Vec3<T> = self.origin - center;
let a: f64 = self.direction.dot(&self.direction);
let b: f64 = 2.0 * oc.dot(&self.direction);
let c = oc.dot(&oc) - radius * radius;
let discriminant = b * b - 4 * a * c;
discriminant > 0
}
}
And the vec.rs file:
Hidden for space
use std::{
fmt::Display,
ops::{
Add, AddAssign, Div, DivAssign, Index, IndexMut, Mul, MulAssign, Neg, Not, Sub, SubAssign,
},
};
#[derive(Eq, PartialEq, Debug, Copy, Clone, Default)]
pub struct Vec3<T> {
pub x: T,
pub y: T,
pub z: T,
}
macro_rules! impl_ops_vec3 {
($t: ty => $($u: ty),* $(,)?) => {
$(
// Operations on Vec3s
impl Add<Vec3<$u>> for Vec3<$t> {
type Output = Vec3<$t>;
fn add(self, rhs: Vec3<$u>) -> Self::Output {
Vec3 {
x: self.x + rhs.x as $t,
y: self.y + rhs.y as $t,
z: self.z + rhs.z as $t,
}
}
}
impl AddAssign<Vec3<$u>> for Vec3<$t> {
fn add_assign(&mut self, rhs: Vec3<$u>) {
self.x += rhs.x as $t;
self.y += rhs.y as $t;
self.z += rhs.z as $t;
}
}
impl Sub<Vec3<$u>> for Vec3<$t> {
type Output = Vec3<$t>;
fn sub(self, rhs: Vec3<$u>) -> Self::Output {
Vec3 {
x: self.x - rhs.x as $t,
y: self.y - rhs.y as $t,
z: self.z - rhs.z as $t,
}
}
}
impl SubAssign<Vec3<$u>> for Vec3<$t> {
fn sub_assign(&mut self, rhs: Vec3<$u>) {
self.x -= rhs.x as $t;
self.y -= rhs.y as $t;
self.z -= rhs.z as $t;
}
}
impl Mul<Vec3<$u>> for Vec3<$t> {
type Output = Vec3<$t>;
fn mul(self, rhs: Vec3<$u>) -> Self::Output {
Vec3 {
x: self.x * rhs.x as $t,
y: self.y * rhs.y as $t,
z: self.z * rhs.z as $t,
}
}
}
impl MulAssign<Vec3<$u>> for Vec3<$t> {
fn mul_assign(&mut self, rhs: Vec3<$u>) {
self.x *= rhs.x as $t;
self.y *= rhs.y as $t;
self.z *= rhs.z as $t;
}
}
impl Div<Vec3<$u>> for Vec3<$t> {
type Output = Vec3<$t>;
fn div(self, rhs: Vec3<$u>) -> Self::Output {
Vec3 {
x: self.x / rhs.x as $t,
y: self.y / rhs.y as $t,
z: self.z / rhs.z as $t,
}
}
}
impl DivAssign<Vec3<$u>> for Vec3<$t> {
fn div_assign(&mut self, rhs: Vec3<$u>) {
self.x /= rhs.x as $t;
self.y /= rhs.y as $t;
self.z /= rhs.z as $t;
}
}
// Operations on primatives
impl Mul<$u> for Vec3<$t> {
type Output = Vec3<$t>;
fn mul(self, rhs: $u) -> Self::Output {
Vec3 {
x: self.x * rhs as $t,
y: self.y * rhs as $t,
z: self.z * rhs as $t,
}
}
}
impl MulAssign<$u> for Vec3<$t> {
fn mul_assign(&mut self, rhs: $u) {
self.x *= rhs as $t;
self.y *= rhs as $t;
self.z *= rhs as $t;
}
}
impl Div<$u> for Vec3<$t> {
type Output = Vec3<$t>;
fn div(self, rhs: $u) -> Self::Output {
Vec3 {
x: self.x / rhs as $t,
y: self.y / rhs as $t,
z: self.z / rhs as $t,
}
}
}
impl DivAssign<$u> for Vec3<$t> {
fn div_assign(&mut self, rhs: $u) {
let k = 1.0 / rhs as i32 as f64; // Forgive me lord, for I have sinned.
self.x *= k as $t;
self.y *= k as $t;
self.z *= k as $t;
}
}
)*
}
}
// Implement operators for integer types
impl_ops_vec3!(i8 => f32, f64, i8, i16, i32, i64, i128, u8, u16, u32, u64, u128, bool);
impl_ops_vec3!(i16 => f32, f64, i8, i16, i32, i64, i128, u8, u16, u32, u64, u128, bool);
impl_ops_vec3!(i32 => f32, f64, i8, i16, i32, i64, i128, u8, u16, u32, u64, u128, bool);
impl_ops_vec3!(i64 => f32, f64, i8, i16, i32, i64, i128, u8, u16, u32, u64, u128, bool);
impl_ops_vec3!(i128 => f32, f64, i8, i16, i32, i64, i128, u8, u16, u32, u64, u128, bool);
// Implement operators for float types
impl_ops_vec3!(f32 => f32, f64, i8, i16, i32, i64, i128, u8, u16, u32, u64, u128);
impl_ops_vec3!(f64 => f32, f64, i8, i16, i32, i64, i128, u8, u16, u32, u64, u128);
// Implement operators for unsigned types
impl_ops_vec3!(u8 => f32, f64, i8, i16, i32, i64, i128, u8, u16, u32, u64, u128, bool);
impl_ops_vec3!(u16 => f32, f64, i8, i16, i32, i64, i128, u8, u16, u32, u64, u128, bool);
impl_ops_vec3!(u32 => f32, f64, i8, i16, i32, i64, i128, u8, u16, u32, u64, u128, bool);
impl_ops_vec3!(u64 => f32, f64, i8, i16, i32, i64, i128, u8, u16, u32, u64, u128, bool);
impl_ops_vec3!(u128 => f32, f64, i8, i16, i32, i64, i128, u8, u16, u32, u64, u128, bool);
// Universal operators
impl<T: Neg> Neg for Vec3<T> {
type Output = Vec3<<T as Neg>::Output>;
fn neg(self) -> Self::Output {
Vec3 {
x: -self.x,
y: -self.y,
z: -self.z,
}
}
}
impl<T: Not> Not for Vec3<T> {
type Output = Vec3<<T as Not>::Output>;
fn not(self) -> Self::Output {
Vec3 {
x: !self.x,
y: !self.y,
z: !self.z,
}
}
}
impl<T> Index<i32> for Vec3<T> {
type Output = T;
fn index(&self, i: i32) -> &Self::Output {
match i {
-1 => &self.z,
0 => &self.x,
1 => &self.y,
2 => &self.z,
_ => panic!("len was 2, but index was {}", i),
}
}
}
impl<T> IndexMut<i32> for Vec3<T> {
fn index_mut(&mut self, i: i32) -> &mut Self::Output {
match i {
-1 => &mut self.z,
0 => &mut self.x,
1 => &mut self.y,
2 => &mut self.z,
_ => panic!("len was 2, but index was {}", i),
}
}
}
impl<T: Display> Display for Vec3<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "({}, {}, {})", self.x, self.y, self.z)
}
}
impl<T: Mul<Output = T> + Add<Output = T> + Into<f64> + Copy + Sub<Output = T>> Vec3<T>
where Vec3<T>: Div<f64, Output = Vec3<T>> {
pub fn new(x: T, y: T, z: T) -> Self {
Vec3 { x, y, z }
}
pub fn length(&self) -> f64 {
(self.x * self.x + self.y * self.y + self.z * self.z)
.into()
.sqrt()
}
pub fn square_length(&self) -> f64 {
(self.x * self.x + self.y * self.y + self.z * self.z).into()
}
pub fn dot(&self, other: &Vec3<T>) -> f64 {
(self.x * other.x + self.y * other.y + self.z * other.z).into()
}
pub fn cross(&self, other: &Vec3<T>) -> Self {
Self {
x: self.y * other.z - self.z * other.y,
y: self.x * other.z - self.z * other.x,
z: self.x * other.y - self.y * other.x,
}
}
pub fn unit_vector(self) -> Self {
self / self.length()
}
}
What am I doing wrong? It doesn't seem like I've specified any of these types anywhere. How do I further constrain the types? The docs page doesn't seem to have anything. Any help is appreciated, thanks!