Ray Tracer Refraction on glass surfaces not working - rust

I'm working through Ray Tracing in One Weekend (The rust version) here:
https://misterdanb.github.io/raytracinginrust/
But after adding Dielectrics (Glass), something is way off with my refraction on glass spheres. I've done troubleshooting, but the math looks correct in reference to both the Rust version and the C++ version this was based on. The expected image is this:
But my code is generating this:
My github link is: https://github.com/jsjutzi/rust-ray-tracer
The only code I've added for refraction and glass materials respectively is:
pub fn refract(self, n: Vec3, etai_over_etat: f64) -> Vec3 {
let cos_theta = (-1.0 * self).dot(n).min(1.0);
let r_out_perp = etai_over_etat * (self + cos_theta * n);
let r_out_parallel = -(1.0 - r_out_perp.length().powi(2)).abs().sqrt() * n;
r_out_perp + r_out_parallel
}
And:
pub struct Dielectric {
ir: f64,
}
impl Dielectric {
pub fn new(index_of_refraction: f64) -> Dielectric {
Dielectric {
ir: index_of_refraction,
}
}
impl Scatter for Dielectric {
fn scatter(&self, r_in: &Ray, rec: &HitRecord) -> Option<(Color, Ray)> {
let refraction_ratio = if rec.front_face {
1.0 / self.ir
} else {
self.ir
};
let unit_direction = r_in.direction();
let refracted = unit_direction.refract(rec.normal, refraction_ratio);
let scattered = Ray::new(rec.p, refracted);
Some((Color::new(1.0, 1.0, 1.0), scattered))
}
I'm not even sure if the issue is refraction itself, or if I screwed something else up earlier in my build and it's just now surfacing because of refraction/glass surfaces being added. I've backtracked several chapters and haven't found anything obvious that I missed earlier on, and I also read up on Snell's Law a bit and don't seen an obvious math error either.
Anyone have any tips on where I went wrong?

So I missed adding the normalized method long ago and wrongly assumed that it was a deprecated method or something and just proceeded without it since it never impacted anything. I've had other typos and things I had to work around from the tutorial and thought that was just another one of them.
Adding that method to the Vec3 type like so:
pub fn normalized(self) -> Vec3 {
self / self.length()
}
Solved the issue for me. Works like a charm now.

Related

Write a function in Rust that returns a random normal deviate with specified mean and standard deviation

I am experimenting with Rust and I am wondering how to write a simple function that returns a normal random deviate. I know generally how to do this, so my question is really more about global state and the way in which the rand_distr crate works. I'd like to be able to write something like:
fn main() {
let x: f64 = rnorm(-2.0, 3.0); // returns a normal deviate with the given mean and standard deviation
println!("{}", x);
}
This type of function is a very common pattern in simulation modeling as it is typically the case that one needs to generate many deviates, each with different parameters. Can a Rust expert fill in the definition of rnorm here?
This appears to work but raises some additional questions.
use rand::*; // hard to figure out what is best here
use rand_distr::*;
fn rnorm(mu: f64, sigma: f64) -> f64 {
let dst = Normal::new(mu, sigma).unwrap();
return dst.sample(&mut thread_rng());
}
fn main() {
let x: f64 = rnorm(-2.0, 3.0);
println!("{}", x);
}
So will this build and teardown the normal struct each call?

How can I make struct variables inaccessible to change from default value when using default initialization? [duplicate]

I'm getting an error when I have this sort of setup:
default_test.rs:
mod default_mod;
use default_mod::Point;
fn main() {
let _p1 = Point::new();
let _p2: Point = Point {
z: 1,
..Default::default()
};
}
default_mod.rs:
pub struct Point {
x: i32,
y: i32,
pub z: i32,
}
impl Point {
pub fn new() -> Self {
Point { x: 0, y: 0, z: 0 }
}
}
impl Default for Point {
fn default() -> Self {
Point { x: 0, y: 0, z: 0 }
}
}
which gives the compiler error:
default_test.rs:9:7
|
9 | ..Default::default()
| ^^^^^^^^^^^^^^^^^^ field `x` is private
error[E0451]: field `y` of struct `default_mod::Point` is private
Short version - I have a struct with both public and private fields. I would like to initialise this struct with default values, but sometimes override them.
I can't seem to fix this error, nor seen anything on the internet or the docs that even mentions errors like this.
It surprises me, because I'd think a common use-case would be to initialise a struct, and that some members of the struct would be private so you can hide implementation details behind and interface.
In my case the private field is a Vec as I have some logic that needs to go into adding or removing things from the vector, so I want to make it private to prevent anyone messing up the data structure.
What are my options here?
It surprises me, because I'd think a common use-case would be to initialise a struct, and that some members of the struct would be private so you can hide implementation details behind and interface.
The problem is that the struct update syntax doesn't do what you think it does. For example, the book shows the following code:
let user2 = User {
email: String::from("another#example.com"),
username: String::from("anotherusername567"),
..user1
};
The ..user1 syntax fills in the User fields we haven't explicitly specified, such as active: user1.active, signin_count: user1.signin_count. .. may be followed by an arbitrary expression which returns the structure, which is where Default::default() comes into play, and means the same as User::default() because a User is expected. However, the desugaring remains unchanged and boils down to assigning individual fields, in neither case granting special access to private fields.
To get back to your example, this code:
let p = Point {
z: 1,
..Default::default()
};
is syntactic sugar for:
let p = {
let _tmp = Point::default();
Point {
x: _tmp.x,
y: _tmp.y,
z: 1,
}
};
and not for the expected:
// NOT what happens
let p = {
let _tmp = Point::default();
p.z = 1;
_tmp
};
What are my options here?
The most idiomatic option is to provide a builder for Point. That is also somewhat bulky1, so if you're looking for a simple solution, you could also use Point::default() and set the z attribute manually. The struct update syntax is incompatible with structs with private fields and just not useful for your type.
1
Though there are crates like derive_builder, typed-builder and builder-pattern that take some of the drudgery away.
What are my options here?
A new() with parameters or a builder.
..struct is just a convenient way of doing functional updates, it doesn't bypass ACLs. Here since your struct has private fields, users can not manipulate it as a "bare" struct, they have to treat it as a largely opaque type.

Breadth-first traversal of binary tree in Rust

I'm new to Rust but coming from C++ I find the gymnastics of the type system a bit ... troubling. I use problems from LeetCode to teach myself Rust. Take the following definition of a binary tree:
pub struct TreeNode {
pub val: i32,
pub left: Option<Rc<RefCell<TreeNode>>>,
pub right: Option<Rc<RefCell<TreeNode>>>,
}
Okay, this is a bit ugly already, but I sort of understand the reasons (although it's unclear to me why we can't have a single type that combines the functionality of Option, Rc, and RefCell when these seem to occur together quite often).
Anyhow, here's the BFS algorithm I implemented (it doesn't do anything interesting, the point is the general layout):
use std::collections::VecDeque;
fn bfs(root: Option<Rc<RefCell<TreeNode>>>) {
let mut queue = VecDeque::new();
queue.push_back((root, 0));
while queue.len() > 0 {
// 'pos' measures how far out to the left or right the given node is.
let (node, pos) = queue.pop_front().unwrap();
if node.is_none() { continue; }
let subtree = node.unwrap();
queue.push_back((subtree.borrow().left.clone(), pos - 1));
queue.push_back((subtree.borrow().right.clone(), pos + 1));
}
}
My question is: is this really how these things are done in Rust? Isn't there a more idiosyncratic (more concise) way of doing this? I mean, the code uses one of each unwrap(), borrow(), and clone() to get at the left and right tree pointers. This feels a bit cumbersome, to say the least. It might be how things are done in Rust in general, but I'm curious if it's the norm or if it's the exception?
The unwrap()s here are indeed non-idiomatic and can be replaced. The first unwrap() can be replaced with while let, and the second with if let:
while let Some((node, pos)) = queue.pop_front() {
// 'pos' measures how far out to the left or right the given node is.
if let Some(subtree) = node {
queue.push_back((subtree.borrow().left.clone(), pos - 1));
queue.push_back((subtree.borrow().right.clone(), pos + 1));
}
}
Having to wrap the whole loop body with if let is unfortunate. The experimental feature let_else will solve that (stabilized in Rust 1.65.0):
#![feature(let_else)]
while let Some((node, pos)) = queue.pop_front() {
// 'pos' measures how far out to the left or right the given node is.
let Some(subtree) = node else {
continue;
};
queue.push_back((subtree.borrow().left.clone(), pos - 1));
queue.push_back((subtree.borrow().right.clone(), pos + 1));
}
But the borrow() and clone() are because you try to bypass the ownership rules with Rc<RefCell>. This is somewhat considered an antipattern: if you think you need to use that, think again. There may be much more Rusty way of doing things. Sometimes it is simple, sometimes requires a redesign of your data structure (for example, with graphs that are commonly represented with indices in Rust).
A simpler tree will also have a simpler search function:
pub struct TreeNode {
pub val: i32,
pub left: Option<Box<TreeNode>>,
pub right: Option<Box<TreeNode>>,
}
fn bfs(root: Option<&TreeNode>) {
let mut queue = VecDeque::new();
queue.push_back((root, 0));
while let Some((node, pos)) = queue.pop_front() {
// 'pos' measures how far out to the left or right the given node is.
let Some(subtree) = node else {
continue;
};
queue.push_back((subtree.left.as_deref(), pos - 1));
queue.push_back((subtree.right.as_deref(), pos + 1));
}
}

How is count_ones implemented in Rust?

I tried looking for how Rust implements count_ones(). I'm curious because it seems to vastly outperform my own naive implementation (no kidding), and I would really like to see why it is so performant. My guess is that Rust is using some asm to do the work. For completeness, here was my attempt:
/*
* my attempt to implement count_ones for i32 types
* but this is much slower than the default
* implementation.
*/
fn count_ones(num: i32) -> u32 {
let mut ans: u32 = 0;
let mut _num = num;
while _num > 0 {
if _num & 0x1 == 0x1 {
ans += 1;
}
_num >>= 1;
}
ans
}
I found this on the rust repo, but I can't make sense of it (still new to Rust!) (reproduced below).
#[inline]
fn count_ones(self) -> u32 {
unsafe { $ctpop(self as $ActualT) as u32 }
}
Let's follow the code step-by-step.
First, looking at the snippet you've posted - it contains several macro variables (identifiers with a dollar sign prepended), so it is assumed that this code is, in fact, a part of macro definition. Scrolling up, we get the following:
macro_rules! uint_impl {
($T:ty = $ActualT:ty, $BITS:expr,
$ctpop:path,
$ctlz:path,
$cttz:path,
$bswap:path,
$add_with_overflow:path,
$sub_with_overflow:path,
$mul_with_overflow:path) => {
#[stable(feature = "rust1", since = "1.0.0")]
#[allow(deprecated)]
impl Int for $T {
// skipped
}
}
}
Now, to see that are the variable values here, we should find where this macro is invoked. In general, this might be hard, due to the macro scoping rules, but here we'll just search the same file, and here it is:
uint_impl! { u8 = u8, 8,
intrinsics::ctpop8,
intrinsics::ctlz8,
intrinsics::cttz8,
bswap8,
intrinsics::u8_add_with_overflow,
intrinsics::u8_sub_with_overflow,
intrinsics::u8_mul_with_overflow }
(and multiple another invocations). Comparing this with the macro definition, we see that the function we're looking for will be expanded to the following:
#[inline]
fn count_ones(self) -> u32 {
unsafe { intrinsics::ctpop8(self as u8) as u32 }
}
And, finally, intrinsics::ctpop8 is, as Stargateur mentioned in comment, an LLVM intrinsic, i.e. this call is directly converted into LLVM instruction.
However, there's a little better way to find out what is what.
Let's now look for the function we're interested in in the std documentation. Searching for count_ones brings together a bunch of functions, for each primitive number type independently; we'll take a look on the implementation for u8. Clicking the src link on the function brings us to the code:
doc_comment! {
concat!("Returns the number of ones in the binary representation of `self`.
# Examples
Basic usage:
```
", $Feature, "let n = 0b01001100", stringify!($SelfT), ";
assert_eq!(n.count_ones(), 3);", $EndFeature, "
```"),
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_stable(feature = "const_math", since = "1.32.0")]
#[inline]
pub const fn count_ones(self) -> u32 {
intrinsics::ctpop(self as $ActualT) as u32
}
}
...which just directly calls the intrinsics::ctpop function we've found before.
Now you might wonder, why these two searches yielded different pieces of code. Reason is simple: the commit you're referring to is from the fairly old version of rustc - pre-1.0, if I understand correctly; at that time, numerical operations were implemented as part of Num trait, not directly on primitive types. If you check out the implementation for version 1.44.1, which is the current one at the time of writing, you'll see the same code I've quoted above from the docs.

Why are booleans copyable even though the documentation doesn't indicate that?

I am trying to understand the ownership and borrowing concept. At first I thought it was pretty simple once you understood it. But...
fn main() {
let a = 5;
let _y = double(a);
println!("{}", a);
}
fn double(x: i32) -> i32 {
x * 2
}
At first I would have expected this to not compile, because a would have been moved to _y.
I was a bit confused, but I found out that I would have been right except that i32 is an exception to the rule because it implements the copy trait.
I looked at the Copy trait and as I understand it, they list all types that implement this trait at the bottom.
So the bool type is not present and so I assumed it's default behaviour was to be "moved". But...
fn main() {
let a = true;
let _y = change_truth(a);
println!("{}", a);
}
fn change_truth(x: bool) -> bool {
!x
}
Doesn't fail either.
Now I am quite confused. I found the Clone trait that seems to be closely related to the copy trait. But unless I missed it, they don't really mention it in the learning doc.
Can someone give me some more info ?
Update:
I have filed an issue on the Rust repository.
I have also made a pull request with some change proposals.
Your understanding is pretty spot-on, this seems to be an issue with the docs. The documentation doesn't show Copy instances for any of the primitives types, even though they are definitely Copy. As an example to show that the compiler considers bool to be Copy, the following compiles just fine:
fn takes_copyable<T: Copy>(foo: T) {}
fn main() {
takes_copyable(true);
}

Resources