Skip to content

Commit

Permalink
refactor: use builder pattern for camera and scene
Browse files Browse the repository at this point in the history
  • Loading branch information
cbgbt committed Nov 26, 2024
1 parent 4e3dbaa commit d7d6431
Show file tree
Hide file tree
Showing 15 changed files with 235 additions and 279 deletions.
76 changes: 56 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,51 +8,83 @@ steal his words (because this port isn't theft enough):
> The output of an OpenGL pipeline is a rastered image. The output of raydeon is
> a set of 2D vector paths.
![](/raydeon/examples/cityscape.png)
This repository has added support for screen-space hatching based on lights
placed within the scene.

Currently less featureful though probably more performant than the prior art.
![](/raydeon/examples/cityscape.png)

## Example

Have a look at any of the [Rust examples](/raydeon/examples) or
[Python examples](/pyraydeon/examples/).

The following Rust code draws the cube which is included as an example in the
original `ln` repo.
The following Rust code draws the 3 cubes below with hatching based on the
lighting.

```rust
use raydeon::lights::PointLight;
use raydeon::shapes::AxisAlignedCuboid;
use raydeon::{Camera, Scene, WPoint3, WVec3};
use raydeon::Material;
use raydeon::{Camera, Scene, SceneLighting, WPoint3, WVec3};
use std::sync::Arc;

fn main() {
env_logger::Builder::from_default_env()
.format_timestamp_nanos()
.init();

let scene = Scene::new().with_geometry(vec![Arc::new(AxisAlignedCuboid::new(
WVec3::new(-1.0, -1.0, -1.0),
WVec3::new(1.0, 1.0, 1.0),
))]);

let eye = WPoint3::new(4.0, 3.0, 2.0);
let scene = Scene::new()
.geometry(vec![
Arc::new(AxisAlignedCuboid::tagged(
(-1.0, -1.0, -1.0),
(1.0, 1.0, 1.0),
Material::new(3.0, 2.0, 2.0, 0),
)),
Arc::new(AxisAlignedCuboid::tagged(
(1.8, -1.0, -1.0),
(3.8, 1.0, 1.0),
Material::new(2.0, 2.0, 2.0, 0),
)),
Arc::new(AxisAlignedCuboid::tagged(
(-1.4, 1.8, -1.0),
(0.6, 3.8, 1.0),
Material::new(3.0, 2.0, 2.0, 0),
)),
])
.lighting(
SceneLighting::new()
.with_lights(vec![Arc::new(PointLight::new(
20.0,
100.0,
(5.5, 12.0, 7.3),
0.0,
0.09,
0.23,
))])
.with_ambient_lighting(0.13),
)
.construct();

let eye = WPoint3::new(8.0, 6.0, 4.0);
let focus = WVec3::new(0.0, 0.0, 0.0);
let up = WVec3::new(0.0, 0.0, 1.0);

let fovy = 50.0;
let width = 1024;
let height = 1024;
let znear = 0.1;
let zfar = 10.0;
let zfar = 20.0;

let camera = Camera::new()
.look_at(eye, focus, up)
.perspective(fovy, width, height, znear, zfar);
let camera = Camera::configure()
.observation(Camera::look_at(eye, focus, up))
.perspective(Camera::perspective(fovy, width, height, znear, zfar))
.build();

let paths = scene.attach_camera(camera).render();
let render_result = scene
.attach_camera(camera)
.with_seed(0)
.render_with_lighting();

// We currently don't have any functionality to aid in emitting SVG images, so you will
// be required to use the [svg crate.](https://crates.io/crates/svg)
let mut svg_doc = svg::Document::new()
.set("width", "8in")
.set("height", "8in")
Expand All @@ -73,7 +105,11 @@ fn main() {
let mut item_group = svg::node::element::Group::new()
.set("transform", format!("translate(0, {}) scale(1,-1)", height));

for path in paths {
for path in render_result
.geometry_paths
.iter()
.chain(render_result.hatch_paths.iter())
{
let (p1, p2) = (path.p1, path.p2);
item_group = item_group.add(
svg::node::element::Line::new()
Expand All @@ -89,4 +125,4 @@ fn main() {
}
```

![](/raydeon/examples/cube.png)
![](/raydeon/examples/lit_cubes_expected.svg)
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)]
#[derive(Debug, Clone, Copy)]
#[pyclass(frozen)]
pub(crate) struct $name(pub(crate) $wraps);

Expand Down
36 changes: 15 additions & 21 deletions pyraydeon/src/scene.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,18 @@ use crate::shapes::Geometry;

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

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

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 {
impl From<raydeon::Camera> for Camera {
fn from(value: raydeon::Camera) -> Self {
Self(value)
}
}
Expand All @@ -43,18 +43,16 @@ impl Camera {
let eye = Point3::try_from(eye)?;
let center = Vec3::try_from(center)?;
let up = Vec3::try_from(up)?;
Ok(self
.0
.clone()
.look_at(eye.cast_unit(), center.cast_unit(), up.cast_unit())
.into())
let mut ncam = self.0.clone();
ncam.observation =
raydeon::Camera::look_at(eye.cast_unit(), center.cast_unit(), up.cast_unit());
Ok(ncam.into())
}

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

#[getter]
Expand Down Expand Up @@ -110,12 +108,7 @@ impl Camera {

#[pyclass(frozen)]
pub(crate) struct Scene {
scene: Arc<
raydeon::Scene<
raydeon::scene::SceneGeometry<raydeon::material::Material>,
raydeon::scene::SceneLighting,
>,
>,
scene: Arc<raydeon::Scene<raydeon::Material>>,
}

#[pymethods]
Expand Down Expand Up @@ -149,8 +142,9 @@ impl Scene {
.with_ambient_lighting(ambient_light);
let scene = Arc::new(
raydeon::Scene::new()
.with_geometry(geometry)
.with_lighting(lighting),
.geometry(geometry)
.lighting(lighting)
.construct(),
);
Ok(Self { scene })
}
Expand Down
2 changes: 1 addition & 1 deletion pyraydeon/src/shapes/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ impl raydeon::Shape<WorldSpace, raydeon::material::Material> for PythonGeometry

fn paths(
&self,
cam: &raydeon::Camera<raydeon::Perspective, raydeon::Observation>,
cam: &raydeon::Camera,
) -> Vec<raydeon::path::LineSegment3D<WorldSpace, raydeon::material::Material>> {
let segments: Option<_> = Python::with_gil(|py| {
let inner = self.slf.bind(py);
Expand Down
20 changes: 12 additions & 8 deletions raydeon/examples/cube.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
use raydeon::shapes::AxisAlignedCuboid;
use raydeon::{Camera, Scene, WPoint3, WVec3};
use raydeon::{Camera, CameraOptions, Scene, WPoint3, WVec3};
use std::sync::Arc;

fn main() {
env_logger::Builder::from_default_env()
.format_timestamp_nanos()
.init();

let scene = Scene::new().with_geometry(vec![Arc::new(AxisAlignedCuboid::new(
WVec3::new(-1.0, -1.0, -1.0),
WVec3::new(1.0, 1.0, 1.0),
))]);
let scene = Scene::new()
.geometry(vec![Arc::new(AxisAlignedCuboid::new(
WVec3::new(-1.0, -1.0, -1.0),
WVec3::new(1.0, 1.0, 1.0),
))])
.construct();

let eye = WPoint3::new(4.0, 3.0, 2.0);
let focus = WVec3::new(0.0, 0.0, 0.0);
Expand All @@ -22,9 +24,11 @@ fn main() {
let znear = 0.1;
let zfar = 10.0;

let camera = Camera::new()
.look_at(eye, focus, up)
.perspective(fovy, width, height, znear, zfar);
let camera = Camera::configure()
.observation(Camera::look_at(eye, focus, up))
.perspective(Camera::perspective(fovy, width, height, znear, zfar))
.render_options(CameraOptions::defaults_for_pen_px_size(4.0))
.build();

let paths = scene.attach_camera(camera).render();

Expand Down
9 changes: 5 additions & 4 deletions raydeon/examples/geom_perf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,12 @@ fn main() {
let znear = 0.1;
let zfar = 100.0;

let scene = Scene::new().with_geometry(generate_scene());
let scene = Scene::new().geometry(generate_scene()).construct();

let camera = Camera::new()
.look_at(eye, focus, up)
.perspective(fovy, width, height, znear, zfar);
let camera = Camera::configure()
.observation(Camera::look_at(eye, focus, up))
.perspective(Camera::perspective(fovy, width, height, znear, zfar))
.build();

let paths = scene.attach_camera(camera).render();

Expand Down
16 changes: 9 additions & 7 deletions raydeon/examples/lit_cubes.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use raydeon::lights::PointLight;
use raydeon::material::Material;
use raydeon::shapes::AxisAlignedCuboid;
use raydeon::Material;
use raydeon::{Camera, Scene, SceneLighting, WPoint3, WVec3};
use std::sync::Arc;

Expand All @@ -10,7 +10,7 @@ fn main() {
.init();

let scene = Scene::new()
.with_geometry(vec![
.geometry(vec![
Arc::new(AxisAlignedCuboid::tagged(
(-1.0, -1.0, -1.0),
(1.0, 1.0, 1.0),
Expand All @@ -27,7 +27,7 @@ fn main() {
Material::new(3.0, 2.0, 2.0, 0),
)),
])
.with_lighting(
.lighting(
SceneLighting::new()
.with_lights(vec![Arc::new(PointLight::new(
20.0,
Expand All @@ -38,7 +38,8 @@ fn main() {
0.23,
))])
.with_ambient_lighting(0.13),
);
)
.construct();

let eye = WPoint3::new(8.0, 6.0, 4.0);
let focus = WVec3::new(0.0, 0.0, 0.0);
Expand All @@ -50,9 +51,10 @@ fn main() {
let znear = 0.1;
let zfar = 20.0;

let camera = Camera::new()
.look_at(eye, focus, up)
.perspective(fovy, width, height, znear, zfar);
let camera = Camera::configure()
.observation(Camera::look_at(eye, focus, up))
.perspective(Camera::perspective(fovy, width, height, znear, zfar))
.build();

let render_result = scene
.attach_camera(camera)
Expand Down
33 changes: 18 additions & 15 deletions raydeon/examples/triangles.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,20 @@ fn main() {
.format_timestamp_nanos()
.init();

let scene = Scene::new().with_geometry(vec![
Arc::new(Triangle::new(
WPoint3::new(0.0, 0.0, 0.0),
WPoint3::new(0.0, 0.0, 1.0),
WPoint3::new(1.0, 0.0, 1.0),
)),
Arc::new(Triangle::new(
WPoint3::new(0.25, 0.25, 0.0),
WPoint3::new(0.0, 0.25, 1.0),
WPoint3::new(-0.65, 0.25, 1.0),
)),
]);
let scene = Scene::new()
.geometry(vec![
Arc::new(Triangle::new(
WPoint3::new(0.0, 0.0, 0.0),
WPoint3::new(0.0, 0.0, 1.0),
WPoint3::new(1.0, 0.0, 1.0),
)),
Arc::new(Triangle::new(
WPoint3::new(0.25, 0.25, 0.0),
WPoint3::new(0.0, 0.25, 1.0),
WPoint3::new(-0.65, 0.25, 1.0),
)),
])
.construct();

let eye = WPoint3::new(0.0, 3.0, 0.0);
let focus = WVec3::new(0.0, 0.0, 0.0);
Expand All @@ -33,9 +35,10 @@ fn main() {
let znear = 0.1;
let zfar = 10.0;

let camera = Camera::new()
.look_at(eye, focus, up)
.perspective(fovy, width, height, znear, zfar);
let camera = Camera::configure()
.observation(Camera::look_at(eye, focus, up))
.perspective(Camera::perspective(fovy, width, height, znear, zfar))
.build();

let paths = scene.attach_camera(camera).render();

Expand Down
Loading

0 comments on commit d7d6431

Please sign in to comment.