Draw first image
This commit is contained in:
parent
4c872f9f91
commit
62b9fdcb56
19 changed files with 1566 additions and 76 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -1 +1,2 @@
|
|||
.target
|
||||
**.exr
|
||||
|
|
|
|||
1072
Cargo.lock
generated
1072
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
|
|
@ -1,4 +1,4 @@
|
|||
[workspace]
|
||||
|
||||
members = [ "ray-tracing-core"]
|
||||
members = [ "ray-tracing-core", "ray-tracing-image", "ray-tracing-scene"]
|
||||
resolver = "2"
|
||||
|
|
|
|||
|
|
@ -4,3 +4,4 @@ version = "0.1.0"
|
|||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
rand = "0.8.5"
|
||||
|
|
|
|||
74
ray-tracing-core/src/camera.rs
Normal file
74
ray-tracing-core/src/camera.rs
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
use crate::prelude::*;
|
||||
use rand::Rng;
|
||||
|
||||
pub trait Camera<R: Rng> {
|
||||
fn forward(&self, x: u32, y: u32, rng: &mut R) -> Ray;
|
||||
fn width(&self) -> u32;
|
||||
fn height(&self) -> u32;
|
||||
}
|
||||
|
||||
pub struct BasicCamera {
|
||||
width: u32,
|
||||
height: u32,
|
||||
pos: Pos3,
|
||||
dir: Dir3,
|
||||
h: Dir3,
|
||||
v: Dir3,
|
||||
}
|
||||
|
||||
impl BasicCamera {
|
||||
pub fn new(
|
||||
width: u32,
|
||||
height: u32,
|
||||
pos: Pos3,
|
||||
dir: Dir3,
|
||||
up: Dir3,
|
||||
horizontal_fov: Float,
|
||||
) -> Self {
|
||||
assert!(horizontal_fov < FloatConsts::PI);
|
||||
let dir = dir.normalize();
|
||||
let up = up.normalize();
|
||||
let l = Float::sin(0.5 * horizontal_fov);
|
||||
let h = l * Dir3::cross(dir, up);
|
||||
let v = l * ((height as Float) / (width as Float)) * Dir3::cross(dir, h.normalize());
|
||||
Self {
|
||||
width,
|
||||
height,
|
||||
pos,
|
||||
dir,
|
||||
h,
|
||||
v,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_look_at(
|
||||
width: u32,
|
||||
height: u32,
|
||||
pos: Pos3,
|
||||
look_at: Pos3,
|
||||
up: Dir3,
|
||||
horizontal_fov: Float,
|
||||
) -> Self {
|
||||
Self::new(width, height, pos, look_at - pos, up, horizontal_fov)
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: Rng> Camera<R> for BasicCamera {
|
||||
fn forward(&self, x: u32, y: u32, rng: &mut R) -> Ray {
|
||||
// normalize x and y to -0.5 to 0.5
|
||||
let x = ((x as Float + rng.gen::<Float>()) / (self.width as Float)) - 0.5;
|
||||
let y = ((y as Float + rng.gen::<Float>()) / (self.height as Float)) - 0.5;
|
||||
|
||||
let dir = self.dir + x * self.h + y * self.v;
|
||||
|
||||
Ray::new(self.pos, dir.normalize(), 0.0)
|
||||
}
|
||||
|
||||
fn width(&self) -> u32 {
|
||||
self.width
|
||||
}
|
||||
|
||||
fn height(&self) -> u32 {
|
||||
self.height
|
||||
}
|
||||
}
|
||||
67
ray-tracing-core/src/color.rs
Normal file
67
ray-tracing-core/src/color.rs
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
use crate::prelude::*;
|
||||
use std::ops::{Add, AddAssign, Div};
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct Color {
|
||||
r: Float,
|
||||
g: Float,
|
||||
b: Float,
|
||||
}
|
||||
|
||||
impl Color {
|
||||
pub fn new(r: Float, g: Float, b: Float) -> Self {
|
||||
Self { r, g, b }
|
||||
}
|
||||
|
||||
pub fn r(self) -> Float {
|
||||
self.r
|
||||
}
|
||||
|
||||
pub fn g(self) -> Float {
|
||||
self.g
|
||||
}
|
||||
|
||||
pub fn b(self) -> Float {
|
||||
self.b
|
||||
}
|
||||
|
||||
pub fn gray(x: Float) -> Self {
|
||||
Self::new(x, x, x)
|
||||
}
|
||||
|
||||
pub fn black() -> Self {
|
||||
Self::gray(0.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl Add for Color {
|
||||
type Output = Color;
|
||||
|
||||
fn add(self, rhs: Self) -> Self::Output {
|
||||
Self {
|
||||
r: self.r + rhs.r,
|
||||
g: self.g + rhs.g,
|
||||
b: self.b + rhs.b,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AddAssign for Color {
|
||||
fn add_assign(&mut self, rhs: Self) {
|
||||
self.r += rhs.r;
|
||||
self.g += rhs.g;
|
||||
self.b += rhs.b;
|
||||
}
|
||||
}
|
||||
|
||||
impl Div<Float> for Color {
|
||||
type Output = Color;
|
||||
|
||||
fn div(self, rhs: Float) -> Self::Output {
|
||||
Self {
|
||||
r: self.r / rhs,
|
||||
g: self.g / rhs,
|
||||
b: self.b / rhs,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +1,16 @@
|
|||
pub mod camera;
|
||||
pub mod color;
|
||||
pub mod material;
|
||||
pub mod math;
|
||||
pub mod ray;
|
||||
pub mod renderer;
|
||||
pub mod scene;
|
||||
|
||||
pub mod prelude {
|
||||
pub type Float = f64;
|
||||
pub type Float = f32;
|
||||
pub use crate::color::Color;
|
||||
pub use crate::material::Material;
|
||||
pub use crate::math::{Dir3, Pos3};
|
||||
pub use crate::math::*;
|
||||
pub use crate::ray::Ray;
|
||||
pub use std::f32::consts as FloatConsts;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1 +1,15 @@
|
|||
pub trait Material {}
|
||||
use crate::prelude::*;
|
||||
use rand::Rng;
|
||||
|
||||
/// All calculations for the material are done a tangent space of the intersection.
|
||||
pub trait Material<R: Rng> {
|
||||
fn eval(&self, w_in: Dir3, w_out: Dir3, rng: &mut R) -> Color;
|
||||
}
|
||||
|
||||
pub struct DefaultMaterial {}
|
||||
|
||||
impl<R: Rng> Material<R> for DefaultMaterial {
|
||||
fn eval(&self, _w_in: Dir3, _w_out: Dir3, rng: &mut R) -> Color {
|
||||
Color::black()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,54 +1,26 @@
|
|||
use crate::prelude::*;
|
||||
use std::ops::{Add, Div, Mul, Neg, Sub};
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct Pos3 {
|
||||
x: Float,
|
||||
y: Float,
|
||||
z: Float,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct Dir3 {
|
||||
x: Float,
|
||||
y: Float,
|
||||
z: Float,
|
||||
}
|
||||
|
||||
impl Pos3 {
|
||||
pub fn new(x: Float, y: Float, z: Float) -> Self {
|
||||
Self { x, y, z }
|
||||
}
|
||||
|
||||
pub fn x(self) -> Float {
|
||||
self.x
|
||||
}
|
||||
pub fn y(self) -> Float {
|
||||
self.y
|
||||
}
|
||||
pub fn z(self) -> Float {
|
||||
self.z
|
||||
}
|
||||
|
||||
pub fn zero() -> Self {
|
||||
Self {
|
||||
x: 0.0,
|
||||
y: 0.0,
|
||||
z: 0.0,
|
||||
}
|
||||
}
|
||||
pub(crate) x: Float,
|
||||
pub(crate) y: Float,
|
||||
pub(crate) z: Float,
|
||||
}
|
||||
|
||||
impl Dir3 {
|
||||
pub fn new(x: Float, y: Float, z: Float) -> Self {
|
||||
Self { x, y, z }
|
||||
}
|
||||
|
||||
pub fn x(self) -> Float {
|
||||
self.x
|
||||
}
|
||||
|
||||
pub fn y(self) -> Float {
|
||||
self.y
|
||||
}
|
||||
|
||||
pub fn z(self) -> Float {
|
||||
self.z
|
||||
}
|
||||
|
|
@ -61,23 +33,32 @@ impl Dir3 {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn up() -> Self {
|
||||
Self::new(0.0, 1.0, 0.0)
|
||||
}
|
||||
|
||||
pub fn normalize(self) -> Self {
|
||||
self / self.length()
|
||||
}
|
||||
pub fn length(self) -> Float {
|
||||
Float::sqrt(self.x * self.x + self.y * self.y + self.z * self.z)
|
||||
|
||||
pub fn length_squared(self) -> Float {
|
||||
self.x * self.x + self.y * self.y + self.z * self.z
|
||||
}
|
||||
}
|
||||
|
||||
impl Sub for Pos3 {
|
||||
type Output = Dir3;
|
||||
pub fn length(self) -> Float {
|
||||
Float::sqrt(self.length_squared())
|
||||
}
|
||||
|
||||
fn sub(self, rhs: Self) -> Self::Output {
|
||||
Dir3 {
|
||||
x: self.x - rhs.x,
|
||||
y: self.y - rhs.y,
|
||||
z: self.z - rhs.z,
|
||||
}
|
||||
pub fn dot(self, rhs: Self) -> Float {
|
||||
self.x * rhs.x + self.y * rhs.y + self.z * rhs.z
|
||||
}
|
||||
|
||||
pub fn cross(self, rhs: Self) -> Self {
|
||||
Self::new(
|
||||
self.y * rhs.z - self.z * rhs.y,
|
||||
self.z * rhs.x - self.x * rhs.z,
|
||||
self.x * rhs.y - self.y * rhs.x,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -93,23 +74,11 @@ impl Add for Dir3 {
|
|||
}
|
||||
}
|
||||
|
||||
impl Add<Pos3> for Dir3 {
|
||||
type Output = Pos3;
|
||||
impl Add<pos3::Pos3> for Dir3 {
|
||||
type Output = pos3::Pos3;
|
||||
|
||||
fn add(self, rhs: Pos3) -> Self::Output {
|
||||
Pos3 {
|
||||
x: self.x + rhs.x,
|
||||
y: self.y + rhs.y,
|
||||
z: self.z + rhs.z,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<Dir3> for Pos3 {
|
||||
type Output = Pos3;
|
||||
|
||||
fn add(self, rhs: Dir3) -> Self::Output {
|
||||
Pos3 {
|
||||
fn add(self, rhs: pos3::Pos3) -> Self::Output {
|
||||
pos3::Pos3 {
|
||||
x: self.x + rhs.x,
|
||||
y: self.y + rhs.y,
|
||||
z: self.z + rhs.z,
|
||||
|
|
@ -141,6 +110,18 @@ impl Mul<Float> for Dir3 {
|
|||
}
|
||||
}
|
||||
|
||||
impl Mul<Dir3> for Float {
|
||||
type Output = Dir3;
|
||||
|
||||
fn mul(self, rhs: Dir3) -> Self::Output {
|
||||
Dir3 {
|
||||
x: self * rhs.x,
|
||||
y: self * rhs.y,
|
||||
z: self * rhs.z,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Div<Float> for Dir3 {
|
||||
type Output = Dir3;
|
||||
|
||||
5
ray-tracing-core/src/math/mod.rs
Normal file
5
ray-tracing-core/src/math/mod.rs
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
pub mod dir3;
|
||||
pub mod pos3;
|
||||
|
||||
pub use dir3::Dir3;
|
||||
pub use pos3::Pos3;
|
||||
57
ray-tracing-core/src/math/pos3.rs
Normal file
57
ray-tracing-core/src/math/pos3.rs
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
use crate::prelude::*;
|
||||
use std::ops::{Add, Sub};
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct Pos3 {
|
||||
pub(crate) x: Float,
|
||||
pub(crate) y: Float,
|
||||
pub(crate) z: Float,
|
||||
}
|
||||
|
||||
impl Pos3 {
|
||||
pub fn new(x: Float, y: Float, z: Float) -> Self {
|
||||
Self { x, y, z }
|
||||
}
|
||||
|
||||
pub fn x(self) -> Float {
|
||||
self.x
|
||||
}
|
||||
pub fn y(self) -> Float {
|
||||
self.y
|
||||
}
|
||||
pub fn z(self) -> Float {
|
||||
self.z
|
||||
}
|
||||
|
||||
pub fn zero() -> Self {
|
||||
Self {
|
||||
x: 0.0,
|
||||
y: 0.0,
|
||||
z: 0.0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Sub for pos3::Pos3 {
|
||||
type Output = Dir3;
|
||||
|
||||
fn sub(self, rhs: Self) -> Self::Output {
|
||||
Dir3 {
|
||||
x: self.x - rhs.x,
|
||||
y: self.y - rhs.y,
|
||||
z: self.z - rhs.z,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<Dir3> for pos3::Pos3 {
|
||||
type Output = pos3::Pos3;
|
||||
|
||||
fn add(self, rhs: Dir3) -> Self::Output {
|
||||
pos3::Pos3 {
|
||||
x: self.x + rhs.x,
|
||||
y: self.y + rhs.y,
|
||||
z: self.z + rhs.z,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2,7 +2,25 @@ use crate::prelude::*;
|
|||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct Ray {
|
||||
pub start: Pos3,
|
||||
pub dir: Dir3,
|
||||
pub time: Float,
|
||||
start: Pos3,
|
||||
dir: Dir3,
|
||||
time: Float,
|
||||
}
|
||||
|
||||
impl Ray {
|
||||
pub fn new(start: Pos3, dir: Dir3, time: Float) -> Self {
|
||||
Self { start, dir, time }
|
||||
}
|
||||
|
||||
pub fn start(self) -> Pos3 {
|
||||
self.start
|
||||
}
|
||||
|
||||
pub fn dir(self) -> Dir3 {
|
||||
self.dir
|
||||
}
|
||||
|
||||
pub fn time(self) -> Float {
|
||||
self.time
|
||||
}
|
||||
}
|
||||
|
|
|
|||
63
ray-tracing-core/src/renderer.rs
Normal file
63
ray-tracing-core/src/renderer.rs
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
use std::marker::PhantomData;
|
||||
|
||||
use crate::{camera::Camera, prelude::*, scene::Scene};
|
||||
use rand::Rng;
|
||||
|
||||
pub trait ClassicalRenderer<R: Rng> {
|
||||
fn render_pixel(&self, x: u32, y: u32, rng: &mut R) -> Color;
|
||||
fn width(&self) -> u32;
|
||||
fn height(&self) -> u32;
|
||||
}
|
||||
|
||||
pub struct DepthRenderer<S, C, R>
|
||||
where
|
||||
S: Scene<R>,
|
||||
C: Camera<R>,
|
||||
R: Rng,
|
||||
{
|
||||
scene: S,
|
||||
camera: C,
|
||||
rng: PhantomData<R>,
|
||||
}
|
||||
|
||||
impl<S, C, R> DepthRenderer<S, C, R>
|
||||
where
|
||||
S: Scene<R>,
|
||||
C: Camera<R>,
|
||||
R: Rng,
|
||||
{
|
||||
pub fn new(scene: S, camera: C) -> Self {
|
||||
Self {
|
||||
scene,
|
||||
camera,
|
||||
rng: PhantomData {},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<S, C, R> ClassicalRenderer<R> for DepthRenderer<S, C, R>
|
||||
where
|
||||
S: Scene<R>,
|
||||
C: Camera<R>,
|
||||
R: Rng,
|
||||
{
|
||||
fn render_pixel(&self, x: u32, y: u32, rng: &mut R) -> Color {
|
||||
let r = self.camera.forward(x, y, rng);
|
||||
|
||||
if let Some(i) = self.scene.intersect(r, 0.0, Float::INFINITY) {
|
||||
// Color::gray(1.0 / i.t())
|
||||
let c = 0.5 * (i.normal() + Dir3::new(1.0, 1.0, 1.0));
|
||||
Color::new(c.x, c.y, c.z)
|
||||
} else {
|
||||
Color::black()
|
||||
}
|
||||
}
|
||||
|
||||
fn width(&self) -> u32 {
|
||||
self.camera.width()
|
||||
}
|
||||
|
||||
fn height(&self) -> u32 {
|
||||
self.camera.height()
|
||||
}
|
||||
}
|
||||
|
|
@ -1,24 +1,34 @@
|
|||
use crate::prelude::*;
|
||||
use rand::Rng;
|
||||
|
||||
pub trait Scene {
|
||||
fn intersect(&self, ray: Ray, min: Float, max: Float) -> Option<Intersection<'_>>;
|
||||
pub trait Scene<R: Rng> {
|
||||
fn intersect(&self, ray: Ray, min: Float, max: Float) -> Option<Intersection<'_, R>>;
|
||||
}
|
||||
|
||||
pub struct Intersection<'sc> {
|
||||
pub struct Intersection<'sc, R: Rng> {
|
||||
t: Float,
|
||||
material: &'sc dyn Material,
|
||||
normal: Dir3,
|
||||
material: &'sc dyn Material<R>,
|
||||
}
|
||||
|
||||
impl<'sc> Intersection<'sc> {
|
||||
pub fn new(t: Float, material: &'sc dyn Material) -> Self {
|
||||
Self { t, material }
|
||||
impl<'sc, R: Rng> Intersection<'sc, R> {
|
||||
pub fn new(t: Float, normal: Dir3, material: &'sc dyn Material<R>) -> Self {
|
||||
Self {
|
||||
t,
|
||||
normal,
|
||||
material,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn t(&self) -> Float {
|
||||
self.t
|
||||
}
|
||||
|
||||
pub fn material(&self) -> &'sc dyn Material {
|
||||
pub fn normal(&self) -> Dir3 {
|
||||
self.normal
|
||||
}
|
||||
|
||||
pub fn material(&self) -> &'sc dyn Material<R> {
|
||||
self.material
|
||||
}
|
||||
}
|
||||
|
|
|
|||
11
ray-tracing-image/Cargo.toml
Normal file
11
ray-tracing-image/Cargo.toml
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
[package]
|
||||
name = "ray-tracing-image"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
image = "0.25.2"
|
||||
rand = { version = "0.8.5", features = ["small_rng"] }
|
||||
ray-tracing-core = { path = "../ray-tracing-core" }
|
||||
ray-tracing-scene = { path = "../ray-tracing-scene" }
|
||||
rayon = "1.10.0"
|
||||
52
ray-tracing-image/src/main.rs
Normal file
52
ray-tracing-image/src/main.rs
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
use image::{ImageBuffer, ImageResult, Rgb};
|
||||
use rand::{rngs::SmallRng, SeedableRng};
|
||||
use ray_tracing_core::{
|
||||
camera::BasicCamera,
|
||||
prelude::*,
|
||||
renderer::{ClassicalRenderer, DepthRenderer},
|
||||
};
|
||||
use ray_tracing_scene::BasicScene;
|
||||
use rayon::prelude::*;
|
||||
use std::path::Path;
|
||||
|
||||
fn render_image<C: ClassicalRenderer<SmallRng> + Sync>(
|
||||
renderer: C,
|
||||
outputfilename: impl AsRef<Path>,
|
||||
samples_per_pixel: usize,
|
||||
) -> ImageResult<()> {
|
||||
let mut data = vec![Color::black(); (renderer.width() * renderer.height()) as usize];
|
||||
|
||||
data.par_iter_mut().enumerate().for_each(|(i, c)| {
|
||||
let x = (i % renderer.width() as usize) as u32;
|
||||
let y = (i / renderer.width() as usize) as u32;
|
||||
|
||||
let mut rng = SmallRng::seed_from_u64((x + y * renderer.width()) as u64);
|
||||
for _ in 0..samples_per_pixel {
|
||||
*c += renderer.render_pixel(x, y, &mut rng) / (samples_per_pixel as Float);
|
||||
}
|
||||
});
|
||||
|
||||
let img = ImageBuffer::from_fn(renderer.width(), renderer.height(), |x, y| {
|
||||
let c = data[(x + y * renderer.width()) as usize];
|
||||
Rgb::<Float>([c.r(), c.g(), c.b()])
|
||||
});
|
||||
|
||||
img.save(outputfilename)
|
||||
}
|
||||
|
||||
fn main() -> ImageResult<()> {
|
||||
let s = BasicScene::new();
|
||||
|
||||
let c = BasicCamera::new(
|
||||
640,
|
||||
400,
|
||||
Pos3::new(-10.0, 0.0, 0.0),
|
||||
Dir3::new(1.0, 0.0, 0.0),
|
||||
Dir3::up(),
|
||||
Float::to_radians(90.0),
|
||||
);
|
||||
|
||||
let r = DepthRenderer::new(s, c);
|
||||
|
||||
render_image(r, "test.exr", 16)
|
||||
}
|
||||
8
ray-tracing-scene/Cargo.toml
Normal file
8
ray-tracing-scene/Cargo.toml
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
[package]
|
||||
name = "ray-tracing-scene"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
rand = "0.8.5"
|
||||
ray-tracing-core = { path = "../ray-tracing-core" }
|
||||
51
ray-tracing-scene/src/lib.rs
Normal file
51
ray-tracing-scene/src/lib.rs
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
use rand::Rng;
|
||||
use ray_tracing_core::material::DefaultMaterial;
|
||||
use ray_tracing_core::prelude::*;
|
||||
use ray_tracing_core::scene::{Intersection, Scene};
|
||||
|
||||
pub mod sphere;
|
||||
|
||||
pub struct BasicScene {
|
||||
spheres: Vec<(Pos3, Float)>,
|
||||
}
|
||||
|
||||
impl BasicScene {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
spheres: vec![(Pos3::zero(), 1.0), (Pos3::new(0.0, 0.0, 2.5), 2.0)],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: Rng> Scene<R> for BasicScene {
|
||||
fn intersect(&self, ray: Ray, min: Float, max: Float) -> Option<Intersection<'_, R>> {
|
||||
let mut intersection: Option<Intersection<'_, R>> = None;
|
||||
|
||||
for &(c, r) in &self.spheres {
|
||||
let offset = ray.start() - c;
|
||||
let p = Dir3::dot(ray.dir(), offset);
|
||||
let delta = p * p - (offset.length_squared() - r * r);
|
||||
|
||||
if delta >= 0.0 {
|
||||
let d = -p - Float::sqrt(delta);
|
||||
|
||||
let int = Intersection::new(
|
||||
d,
|
||||
((ray.start() + d * ray.dir()) - c).normalize(),
|
||||
&DefaultMaterial {},
|
||||
);
|
||||
if d >= min && d <= max {
|
||||
if let Some(i) = intersection.as_ref() {
|
||||
if i.t() > d {
|
||||
intersection.replace(int);
|
||||
}
|
||||
} else {
|
||||
intersection = Some(int)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
intersection
|
||||
}
|
||||
}
|
||||
0
ray-tracing-scene/src/sphere.rs
Normal file
0
ray-tracing-scene/src/sphere.rs
Normal file
Loading…
Add table
Add a link
Reference in a new issue