Draw earth texture to the sphere
This commit is contained in:
parent
8ab0a9d139
commit
bd06d32b34
8 changed files with 85 additions and 19 deletions
|
@ -29,7 +29,9 @@ pub struct Image {
|
|||
|
||||
impl Image {
|
||||
pub fn from_file(path: impl AsRef<Path>) -> Result<Self> {
|
||||
let file = File::open(path.as_ref())?;
|
||||
let path = path.as_ref();
|
||||
let file = File::open(path)
|
||||
.with_context(|| format!("Could not open file at {path:?}"))?;
|
||||
Self::read(file)
|
||||
}
|
||||
|
||||
|
|
|
@ -113,7 +113,7 @@ fn main() -> Result<()> {
|
|||
Ok(match earliest_intersection {
|
||||
// Take the object's material color
|
||||
Some((obj_idx, intersection_context, object)) => {
|
||||
scene.compute_pixel_color(obj_idx, object, intersection_context)
|
||||
scene.compute_pixel_color(obj_idx, object, intersection_context)?
|
||||
}
|
||||
|
||||
// There was no intersection, so this should default to the scene's
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use std::iter;
|
||||
|
||||
use anyhow::Result;
|
||||
use ordered_float::NotNan;
|
||||
use rand::Rng;
|
||||
use rayon::prelude::{
|
||||
|
@ -10,7 +11,8 @@ use rayon::prelude::{
|
|||
use crate::{image::Color, ray::Ray, utils::dot, Point, Vector};
|
||||
|
||||
use super::{
|
||||
data::{DepthCueing, Light, LightKind, Object},
|
||||
data::{DepthCueing, Light, LightKind},
|
||||
object::Object,
|
||||
Scene,
|
||||
};
|
||||
|
||||
|
@ -27,20 +29,22 @@ impl Scene {
|
|||
obj_idx: usize,
|
||||
object: &Object,
|
||||
intersection_context: IntersectionContext,
|
||||
) -> Color {
|
||||
// TODO: Does it make sense to make this function fallible from an API
|
||||
// design standpoint?
|
||||
) -> Result<Color> {
|
||||
let material = match self.materials.get(object.material_idx) {
|
||||
Some(v) => v,
|
||||
None => return self.bkg_color,
|
||||
None => bail!("Material index not found."),
|
||||
};
|
||||
|
||||
let diffuse_color = match object.texture_idx {
|
||||
Some(texture_idx) => {
|
||||
let texture = &self.textures[texture_idx];
|
||||
let (u, v) = object.kind.get_texture_coord(&intersection_context)?;
|
||||
|
||||
// TODO: need to implement
|
||||
material.diffuse_color
|
||||
let texture = match self.textures.get(texture_idx) {
|
||||
Some(v) => v,
|
||||
None => bail!("Texture index not found."),
|
||||
};
|
||||
|
||||
texture.pixel_at(u, v)
|
||||
}
|
||||
None => material.diffuse_color,
|
||||
};
|
||||
|
@ -132,7 +136,7 @@ impl Scene {
|
|||
// Need to clamp the result so none of the components goes over 1
|
||||
let clamped_result = color.map(|v| v.min(1.0));
|
||||
|
||||
clamped_result
|
||||
Ok(clamped_result)
|
||||
}
|
||||
|
||||
/// Perform another ray casting to see if there are any objects obstructing
|
||||
|
|
|
@ -10,15 +10,17 @@ use crate::{
|
|||
image::{Color, Image},
|
||||
scene::{
|
||||
cylinder::Cylinder,
|
||||
data::{Attenuation, Light, LightKind, Material, Object},
|
||||
data::{Attenuation, Light, LightKind, Material},
|
||||
object::{Object, ObjectKind},
|
||||
sphere::Sphere,
|
||||
texture::Texture,
|
||||
triangle::Triangle,
|
||||
Scene, texture::Texture,
|
||||
Scene,
|
||||
},
|
||||
Point, Vector,
|
||||
};
|
||||
|
||||
use super::data::{DepthCueing, ObjectKind};
|
||||
use super::data::DepthCueing;
|
||||
|
||||
impl Scene {
|
||||
/// Parse the input file into a scene
|
||||
|
|
|
@ -2,15 +2,16 @@ pub mod cylinder;
|
|||
pub mod data;
|
||||
pub mod illumination;
|
||||
pub mod input_file;
|
||||
pub mod object;
|
||||
pub mod sphere;
|
||||
pub mod texture;
|
||||
pub mod triangle;
|
||||
pub mod object;
|
||||
|
||||
use crate::image::{Color, Image};
|
||||
use crate::{Point, Point2, Vector};
|
||||
|
||||
use self::data::{Attenuation, DepthCueing, Light, Material, Object};
|
||||
use self::data::{Attenuation, DepthCueing, Light, Material};
|
||||
use self::object::Object;
|
||||
use self::texture::Texture;
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
|
|
|
@ -44,4 +44,17 @@ impl ObjectKind {
|
|||
ObjectKind::Triangle(triangle) => triangle.intersects_ray_at(scene, ray),
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the coordinates in the texture (between 0 and 1) that corresponds to
|
||||
/// the intersection point
|
||||
pub fn get_texture_coord(
|
||||
&self,
|
||||
ctx: &IntersectionContext,
|
||||
) -> Result<(f64, f64)> {
|
||||
match self {
|
||||
ObjectKind::Sphere(sphere) => sphere.get_texture_coord(ctx),
|
||||
ObjectKind::Cylinder(cylinder) => todo!(),
|
||||
ObjectKind::Triangle(triangle) => todo!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
use std::f64::consts::PI;
|
||||
|
||||
use anyhow::Result;
|
||||
use ordered_float::NotNan;
|
||||
|
||||
|
@ -72,4 +74,21 @@ impl Sphere {
|
|||
normal,
|
||||
}))
|
||||
}
|
||||
|
||||
pub fn get_texture_coord(
|
||||
&self,
|
||||
ctx: &IntersectionContext,
|
||||
) -> Result<(f64, f64)> {
|
||||
// Reverse engineer the angles from the coordinate of the intersection
|
||||
let cosp = (ctx.point.z - self.center.z) / self.radius;
|
||||
let phi = cosp.acos();
|
||||
let theta =
|
||||
(ctx.point.y - self.center.y).atan2(ctx.point.x - self.center.x);
|
||||
|
||||
// Map theta and phi into 0 - 1 range
|
||||
let v = phi / PI;
|
||||
let u = 0.5 + theta / (2.0 * PI);
|
||||
|
||||
Ok((u, v))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,9 +8,34 @@ impl Texture {
|
|||
Self(image)
|
||||
}
|
||||
|
||||
pub fn pixel_at_exact(&self, x: usize, y: usize) -> Color {
|
||||
// TODO: Debug asserts?
|
||||
|
||||
self.0.data[y * self.0.width + x]
|
||||
}
|
||||
|
||||
/// Returns a pixel at the given coordinate. For non-lattice coordinates,
|
||||
/// interpolation of the image is done.
|
||||
pub fn pixel_at(&self, x: f64, y: f64) -> Option<Color> {
|
||||
todo!()
|
||||
/// bi-linear interpolation of the image is done.
|
||||
pub fn pixel_at(&self, u: f64, v: f64) -> Color {
|
||||
debug_assert!(0.0 <= u && u <= 1.0, "u must be between 0 and 1");
|
||||
debug_assert!(0.0 <= v && v <= 1.0, "u must be between 0 and 1");
|
||||
|
||||
// Slide 121
|
||||
let x = u * (self.0.width - 1) as f64;
|
||||
let y = v * (self.0.height - 1) as f64;
|
||||
|
||||
let i = x.floor();
|
||||
let j = y.floor();
|
||||
|
||||
let alpha = x - i;
|
||||
let beta = y - j;
|
||||
|
||||
let i = i as usize;
|
||||
let j = j as usize;
|
||||
|
||||
(1.0 - alpha) * (1.0 - beta) * self.pixel_at_exact(i, j)
|
||||
+ (alpha) * (1.0 - beta) * self.pixel_at_exact(i + 1, j)
|
||||
+ (1.0 - alpha) * (beta) * self.pixel_at_exact(i, j + 1)
|
||||
+ (alpha) * (beta) * self.pixel_at_exact(i + 1, j + 1)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue