Skip to content

Commit

Permalink
feat: expose pen and hatch options to callers
Browse files Browse the repository at this point in the history
  • Loading branch information
cbgbt committed Nov 26, 2024
1 parent 03190ca commit 4e3dbaa
Show file tree
Hide file tree
Showing 8 changed files with 164 additions and 104 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ raydeon = { path = "./raydeon", version = "0.2" }
pyrayeon = { path = "./pyraydeon", version = "0.1.0-alpha" }

anyhow = "1"
bon = "3"
cgmath = "0.17"
collision = "0.20"
env_logger = "0.11"
Expand Down
2 changes: 1 addition & 1 deletion pyraydeon/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use pyo3::prelude::*;

macro_rules! pywrap {
($name:ident, $wraps:ty) => {
#[derive(Debug, Clone, Copy)]
#[derive(Debug, Clone)]
#[pyclass(frozen)]
pub(crate) struct $name(pub(crate) $wraps);

Expand Down
28 changes: 24 additions & 4 deletions pyraydeon/src/scene.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,23 @@ use crate::linear::{ArbitrarySpace, Point2, Point3, Vec3};
use crate::material::Material;
use crate::shapes::Geometry;

pywrap!(Camera, raydeon::Camera<raydeon::Perspective, raydeon::Observation>);
#[derive(Debug, Clone)]
#[pyclass(frozen)]
pub(crate) struct Camera(pub(crate) raydeon::Camera<raydeon::Perspective, raydeon::Observation>);

impl ::std::ops::Deref for Camera {
type Target = raydeon::Camera<raydeon::Perspective, raydeon::Observation>;

fn deref(&self) -> &Self::Target {
&self.0
}
}

impl From<raydeon::Camera<raydeon::Perspective, raydeon::Observation>> for Camera {
fn from(value: raydeon::Camera<raydeon::Perspective, raydeon::Observation>) -> Self {
Self(value)
}
}

#[pymethods]
impl Camera {
Expand All @@ -29,12 +45,16 @@ impl Camera {
let up = Vec3::try_from(up)?;
Ok(self
.0
.clone()
.look_at(eye.cast_unit(), center.cast_unit(), up.cast_unit())
.into())
}

fn perspective(&self, fovy: f64, width: usize, height: usize, znear: f64, zfar: f64) -> Camera {
self.0.perspective(fovy, width, height, znear, zfar).into()
self.0
.clone()
.perspective(fovy, width, height, znear, zfar)
.into()
}

#[getter]
Expand Down Expand Up @@ -137,7 +157,7 @@ impl Scene {

fn render(&self, py: Python, camera: &Camera) -> Vec<LineSegment2D> {
py.allow_threads(|| {
let cam = self.scene.attach_camera(camera.0);
let cam = self.scene.attach_camera(camera.0.clone());
cam.render()
.into_iter()
.map(|ls| ls.cast_unit().into())
Expand All @@ -153,7 +173,7 @@ impl Scene {
seed: Option<u64>,
) -> Vec<LineSegment2D> {
py.allow_threads(|| {
let cam = self.scene.attach_camera(camera.0);
let cam = self.scene.attach_camera(camera.0.clone());
let cam = if let Some(seed) = seed {
cam.with_seed(seed)
} else {
Expand Down
4 changes: 2 additions & 2 deletions pyraydeon/src/shapes/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ impl raydeon::Shape<WorldSpace, raydeon::material::Material> for PythonGeometry
) -> Vec<raydeon::path::LineSegment3D<WorldSpace, raydeon::material::Material>> {
let segments: Option<_> = Python::with_gil(|py| {
let inner = self.slf.bind(py);
let cam = Camera::from(*cam);
let cam = Camera::from(cam.clone());
let call_result = inner.call_method1("paths", (cam,)).unwrap();

let segments = call_result
Expand Down Expand Up @@ -238,7 +238,7 @@ impl raydeon::Shape<WorldSpace, raydeon::material::Material> for PythonGeometry

impl raydeon::CollisionGeometry<WorldSpace> for PythonGeometry {
fn hit_by(&self, ray: &raydeon::Ray) -> Option<raydeon::HitData> {
if let PythonGeometryKind::Collision { aabb: Some(aabb) } = self.kind {
if let PythonGeometryKind::Collision { aabb: Some(aabb) } = &self.kind {
raydeon::shapes::AxisAlignedCuboid::from(aabb.0.cast_unit()).hit_by(ray)?;
}
Python::with_gil(|py| {
Expand Down
1 change: 1 addition & 0 deletions raydeon/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ authors = ["cbgbt <[email protected]>"]
edition = "2021"

[dependencies]
bon.workspace = true
cgmath.workspace = true
collision.workspace = true
euclid.workspace = true
Expand Down
201 changes: 122 additions & 79 deletions raydeon/src/camera.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,100 +3,48 @@ use path::SlicedSegment3D;

use crate::*;

#[derive(Debug, Copy, Clone)]
pub struct Observation {
pub eye: WPoint3,
pub center: WVec3,
pub up: WVec3,
}

impl Default for Observation {
fn default() -> Self {
Self::new((0.0, 0.0, 1.0), (0.0, 0.0, 0.0), (0.0, 1.0, 0.0))
}
}

/// Type parameter for a camera that isn't yet looking anywhere
#[derive(Debug, Copy, Clone)]
pub struct NoObservation;

impl Observation {
pub fn new(eye: impl Into<WPoint3>, center: impl Into<WVec3>, up: impl Into<WVec3>) -> Self {
let eye = eye.into();
let center = center.into();
let up = up.into().normalize();

Self { eye, center, up }
}

#[rustfmt::skip]
pub fn look_matrix(&self) -> WCTransform {
let Observation { eye, center, up, .. } = *self;
let f = (center - eye.to_vector()).normalize();
let s = f.cross(up).normalize();
let u = s.cross(f).normalize();

CWTransform::from_array(
// euclid used to let us specify things in column major order and now it doesn't.
// So we're just transposing it here.
CWTransform::new(
s.x, u.x, -f.x, eye.x,
s.y, u.y, -f.y, eye.y,
s.z, u.z, -f.z, eye.z,
0.0, 0.0, 0.0, 1.0,
)
.to_array_transposed(),
)
.inverse()
.unwrap()
}
#[derive(Debug, Clone)]
pub struct Camera<P, O> {
pub observation: O,
pub perspective: P,
pub render_options: CameraOptions,
}

#[derive(Debug, Copy, Clone)]
pub struct Perspective {
pub fovy: f64,
pub width: usize,
pub height: usize,
pub aspect: f64,
pub znear: f64,
pub zfar: f64,
#[derive(Debug, Clone)]
pub struct CameraOptions {
pub pen_px_size: f64,
pub hatch_pixel_spacing: f64,
pub hatch_pixel_chop_factor: f64,
pub hatch_slice_forgiveness: usize,
pub vert_hatch_brightness_scaling: f64,
pub diag_hatch_brightness_scaling: f64,
}

impl Default for Perspective {
impl Default for CameraOptions {
fn default() -> Self {
Self::new(45.0, 1920, 1080, 0.1, 100.0)
Self::defaults_for_pen_px_size(4.0)
}
}

/// Type parameter for a camera that doesn't yet have a defined perspective
#[derive(Debug, Copy, Clone)]
pub struct NoPerspective;

impl Perspective {
pub fn new(fovy: f64, width: usize, height: usize, znear: f64, zfar: f64) -> Self {
let aspect = width as f64 / height as f64;
impl CameraOptions {
pub fn defaults_for_pen_px_size(px_size: f64) -> Self {
Self {
fovy,
width,
height,
aspect,
znear,
zfar,
pen_px_size: px_size,
hatch_pixel_spacing: px_size * 2.0,
hatch_pixel_chop_factor: px_size / 3.0,
hatch_slice_forgiveness: 1,
vert_hatch_brightness_scaling: 0.8,
diag_hatch_brightness_scaling: 0.46,
}
}
}

#[derive(Debug, Copy, Clone)]
pub struct Camera<P, O> {
pub observation: O,
pub perspective: P,
}

impl Camera<NoPerspective, NoObservation> {
pub fn new() -> Self {
Self {
observation: NoObservation,
perspective: NoPerspective,
render_options: Default::default(),
}
}
}
Expand All @@ -106,6 +54,7 @@ impl Default for Camera<Perspective, Observation> {
Self {
observation: Observation::default(),
perspective: Perspective::default(),
render_options: Default::default(),
}
}
}
Expand All @@ -117,11 +66,16 @@ impl<P, O> Camera<P, O> {
center: impl Into<WVec3>,
up: impl Into<WVec3>,
) -> Camera<P, Observation> {
let Camera { perspective, .. } = self;
let Camera {
perspective,
render_options,
..
} = self;
let observation = Observation::new(eye.into(), center.into(), up.into());
Camera {
observation,
perspective,
render_options,
}
}

Expand All @@ -133,11 +87,16 @@ impl<P, O> Camera<P, O> {
znear: f64,
zfar: f64,
) -> Camera<Perspective, O> {
let Camera { observation, .. } = self;
let Camera {
observation,
render_options,
..
} = self;
let perspective = Perspective::new(fovy, width, height, znear, zfar);
Camera {
observation,
perspective,
render_options,
}
}
}
Expand Down Expand Up @@ -185,7 +144,8 @@ impl Camera<Perspective, Observation> {

let chunk_count = canvas_points
.map(|(p1t, p2t)| {
let rough_chop_size = (p2t - p1t).length() / (PEN_PX_SIZE / 2.0);
let rough_chop_size =
(p2t - p1t).length() / (self.render_options.pen_px_size / 2.0);
rough_chop_size.round_ties_even() as usize
})
.unwrap_or_else(|| {
Expand Down Expand Up @@ -233,6 +193,89 @@ impl<O> Camera<Perspective, O> {
}
}

#[derive(Debug, Copy, Clone)]
pub struct Observation {
pub eye: WPoint3,
pub center: WVec3,
pub up: WVec3,
}

impl Default for Observation {
fn default() -> Self {
Self::new((0.0, 0.0, 1.0), (0.0, 0.0, 0.0), (0.0, 1.0, 0.0))
}
}

/// Type parameter for a camera that isn't yet looking anywhere
#[derive(Debug, Copy, Clone)]
pub struct NoObservation;

impl Observation {
pub fn new(eye: impl Into<WPoint3>, center: impl Into<WVec3>, up: impl Into<WVec3>) -> Self {
let eye = eye.into();
let center = center.into();
let up = up.into().normalize();

Self { eye, center, up }
}

#[rustfmt::skip]
pub fn look_matrix(&self) -> WCTransform {
let Observation { eye, center, up, .. } = *self;
let f = (center - eye.to_vector()).normalize();
let s = f.cross(up).normalize();
let u = s.cross(f).normalize();

CWTransform::from_array(
// euclid used to let us specify things in column major order and now it doesn't.
// So we're just transposing it here.
CWTransform::new(
s.x, u.x, -f.x, eye.x,
s.y, u.y, -f.y, eye.y,
s.z, u.z, -f.z, eye.z,
0.0, 0.0, 0.0, 1.0,
)
.to_array_transposed(),
)
.inverse()
.unwrap()
}
}

#[derive(Debug, Copy, Clone)]
pub struct Perspective {
pub fovy: f64,
pub width: usize,
pub height: usize,
pub aspect: f64,
pub znear: f64,
pub zfar: f64,
}

impl Default for Perspective {
fn default() -> Self {
Self::new(45.0, 1920, 1080, 0.1, 100.0)
}
}

/// Type parameter for a camera that doesn't yet have a defined perspective
#[derive(Debug, Copy, Clone)]
pub struct NoPerspective;

impl Perspective {
pub fn new(fovy: f64, width: usize, height: usize, znear: f64, zfar: f64) -> Self {
let aspect = width as f64 / height as f64;
Self {
fovy,
width,
height,
aspect,
znear,
zfar,
}
}
}

#[rustfmt::skip]
fn frustum(
l: f64,
Expand Down
4 changes: 0 additions & 4 deletions raydeon/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,6 @@ pub use path::{LineSegment3D, PathMeta};
pub use ray::{HitData, Ray};
pub use scene::{Scene, SceneGeometry, SceneLighting};

// The pixel fidelity of the drawing instrument.
// TODO: Make this configurable
pub const PEN_PX_SIZE: f64 = 4.0;

#[cfg(test)]
pub(crate) static EPSILON: f64 = 0.004;

Expand Down
Loading

0 comments on commit 4e3dbaa

Please sign in to comment.