Skip to content

Commit d7d6431

Browse files
committed
refactor: use builder pattern for camera and scene
1 parent 4e3dbaa commit d7d6431

File tree

15 files changed

+235
-279
lines changed

15 files changed

+235
-279
lines changed

README.md

Lines changed: 56 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -8,51 +8,83 @@ steal his words (because this port isn't theft enough):
88
> The output of an OpenGL pipeline is a rastered image. The output of raydeon is
99
> a set of 2D vector paths.
1010
11-
![](/raydeon/examples/cityscape.png)
11+
This repository has added support for screen-space hatching based on lights
12+
placed within the scene.
1213

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

1516
## Example
1617

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

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

2324
```rust
25+
use raydeon::lights::PointLight;
2426
use raydeon::shapes::AxisAlignedCuboid;
25-
use raydeon::{Camera, Scene, WPoint3, WVec3};
27+
use raydeon::Material;
28+
use raydeon::{Camera, Scene, SceneLighting, WPoint3, WVec3};
2629
use std::sync::Arc;
2730

2831
fn main() {
2932
env_logger::Builder::from_default_env()
3033
.format_timestamp_nanos()
3134
.init();
3235

33-
let scene = Scene::new().with_geometry(vec![Arc::new(AxisAlignedCuboid::new(
34-
WVec3::new(-1.0, -1.0, -1.0),
35-
WVec3::new(1.0, 1.0, 1.0),
36-
))]);
37-
38-
let eye = WPoint3::new(4.0, 3.0, 2.0);
36+
let scene = Scene::new()
37+
.geometry(vec![
38+
Arc::new(AxisAlignedCuboid::tagged(
39+
(-1.0, -1.0, -1.0),
40+
(1.0, 1.0, 1.0),
41+
Material::new(3.0, 2.0, 2.0, 0),
42+
)),
43+
Arc::new(AxisAlignedCuboid::tagged(
44+
(1.8, -1.0, -1.0),
45+
(3.8, 1.0, 1.0),
46+
Material::new(2.0, 2.0, 2.0, 0),
47+
)),
48+
Arc::new(AxisAlignedCuboid::tagged(
49+
(-1.4, 1.8, -1.0),
50+
(0.6, 3.8, 1.0),
51+
Material::new(3.0, 2.0, 2.0, 0),
52+
)),
53+
])
54+
.lighting(
55+
SceneLighting::new()
56+
.with_lights(vec![Arc::new(PointLight::new(
57+
20.0,
58+
100.0,
59+
(5.5, 12.0, 7.3),
60+
0.0,
61+
0.09,
62+
0.23,
63+
))])
64+
.with_ambient_lighting(0.13),
65+
)
66+
.construct();
67+
68+
let eye = WPoint3::new(8.0, 6.0, 4.0);
3969
let focus = WVec3::new(0.0, 0.0, 0.0);
4070
let up = WVec3::new(0.0, 0.0, 1.0);
4171

4272
let fovy = 50.0;
4373
let width = 1024;
4474
let height = 1024;
4575
let znear = 0.1;
46-
let zfar = 10.0;
76+
let zfar = 20.0;
4777

48-
let camera = Camera::new()
49-
.look_at(eye, focus, up)
50-
.perspective(fovy, width, height, znear, zfar);
78+
let camera = Camera::configure()
79+
.observation(Camera::look_at(eye, focus, up))
80+
.perspective(Camera::perspective(fovy, width, height, znear, zfar))
81+
.build();
5182

52-
let paths = scene.attach_camera(camera).render();
83+
let render_result = scene
84+
.attach_camera(camera)
85+
.with_seed(0)
86+
.render_with_lighting();
5387

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

76-
for path in paths {
108+
for path in render_result
109+
.geometry_paths
110+
.iter()
111+
.chain(render_result.hatch_paths.iter())
112+
{
77113
let (p1, p2) = (path.p1, path.p2);
78114
item_group = item_group.add(
79115
svg::node::element::Line::new()
@@ -89,4 +125,4 @@ fn main() {
89125
}
90126
```
91127

92-
![](/raydeon/examples/cube.png)
128+
![](/raydeon/examples/lit_cubes_expected.svg)

pyraydeon/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use pyo3::prelude::*;
22

33
macro_rules! pywrap {
44
($name:ident, $wraps:ty) => {
5-
#[derive(Debug, Clone)]
5+
#[derive(Debug, Clone, Copy)]
66
#[pyclass(frozen)]
77
pub(crate) struct $name(pub(crate) $wraps);
88

pyraydeon/src/scene.rs

Lines changed: 15 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -11,18 +11,18 @@ use crate::shapes::Geometry;
1111

1212
#[derive(Debug, Clone)]
1313
#[pyclass(frozen)]
14-
pub(crate) struct Camera(pub(crate) raydeon::Camera<raydeon::Perspective, raydeon::Observation>);
14+
pub(crate) struct Camera(pub(crate) raydeon::Camera);
1515

1616
impl ::std::ops::Deref for Camera {
17-
type Target = raydeon::Camera<raydeon::Perspective, raydeon::Observation>;
17+
type Target = raydeon::Camera;
1818

1919
fn deref(&self) -> &Self::Target {
2020
&self.0
2121
}
2222
}
2323

24-
impl From<raydeon::Camera<raydeon::Perspective, raydeon::Observation>> for Camera {
25-
fn from(value: raydeon::Camera<raydeon::Perspective, raydeon::Observation>) -> Self {
24+
impl From<raydeon::Camera> for Camera {
25+
fn from(value: raydeon::Camera) -> Self {
2626
Self(value)
2727
}
2828
}
@@ -43,18 +43,16 @@ impl Camera {
4343
let eye = Point3::try_from(eye)?;
4444
let center = Vec3::try_from(center)?;
4545
let up = Vec3::try_from(up)?;
46-
Ok(self
47-
.0
48-
.clone()
49-
.look_at(eye.cast_unit(), center.cast_unit(), up.cast_unit())
50-
.into())
46+
let mut ncam = self.0.clone();
47+
ncam.observation =
48+
raydeon::Camera::look_at(eye.cast_unit(), center.cast_unit(), up.cast_unit());
49+
Ok(ncam.into())
5150
}
5251

5352
fn perspective(&self, fovy: f64, width: usize, height: usize, znear: f64, zfar: f64) -> Camera {
54-
self.0
55-
.clone()
56-
.perspective(fovy, width, height, znear, zfar)
57-
.into()
53+
let mut ncam = self.0.clone();
54+
ncam.perspective = raydeon::Camera::perspective(fovy, width, height, znear, zfar);
55+
ncam.into()
5856
}
5957

6058
#[getter]
@@ -110,12 +108,7 @@ impl Camera {
110108

111109
#[pyclass(frozen)]
112110
pub(crate) struct Scene {
113-
scene: Arc<
114-
raydeon::Scene<
115-
raydeon::scene::SceneGeometry<raydeon::material::Material>,
116-
raydeon::scene::SceneLighting,
117-
>,
118-
>,
111+
scene: Arc<raydeon::Scene<raydeon::Material>>,
119112
}
120113

121114
#[pymethods]
@@ -149,8 +142,9 @@ impl Scene {
149142
.with_ambient_lighting(ambient_light);
150143
let scene = Arc::new(
151144
raydeon::Scene::new()
152-
.with_geometry(geometry)
153-
.with_lighting(lighting),
145+
.geometry(geometry)
146+
.lighting(lighting)
147+
.construct(),
154148
);
155149
Ok(Self { scene })
156150
}

pyraydeon/src/shapes/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,7 @@ impl raydeon::Shape<WorldSpace, raydeon::material::Material> for PythonGeometry
202202

203203
fn paths(
204204
&self,
205-
cam: &raydeon::Camera<raydeon::Perspective, raydeon::Observation>,
205+
cam: &raydeon::Camera,
206206
) -> Vec<raydeon::path::LineSegment3D<WorldSpace, raydeon::material::Material>> {
207207
let segments: Option<_> = Python::with_gil(|py| {
208208
let inner = self.slf.bind(py);

raydeon/examples/cube.rs

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,18 @@
11
use raydeon::shapes::AxisAlignedCuboid;
2-
use raydeon::{Camera, Scene, WPoint3, WVec3};
2+
use raydeon::{Camera, CameraOptions, Scene, WPoint3, WVec3};
33
use std::sync::Arc;
44

55
fn main() {
66
env_logger::Builder::from_default_env()
77
.format_timestamp_nanos()
88
.init();
99

10-
let scene = Scene::new().with_geometry(vec![Arc::new(AxisAlignedCuboid::new(
11-
WVec3::new(-1.0, -1.0, -1.0),
12-
WVec3::new(1.0, 1.0, 1.0),
13-
))]);
10+
let scene = Scene::new()
11+
.geometry(vec![Arc::new(AxisAlignedCuboid::new(
12+
WVec3::new(-1.0, -1.0, -1.0),
13+
WVec3::new(1.0, 1.0, 1.0),
14+
))])
15+
.construct();
1416

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

25-
let camera = Camera::new()
26-
.look_at(eye, focus, up)
27-
.perspective(fovy, width, height, znear, zfar);
27+
let camera = Camera::configure()
28+
.observation(Camera::look_at(eye, focus, up))
29+
.perspective(Camera::perspective(fovy, width, height, znear, zfar))
30+
.render_options(CameraOptions::defaults_for_pen_px_size(4.0))
31+
.build();
2832

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

raydeon/examples/geom_perf.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,12 @@ fn main() {
2020
let znear = 0.1;
2121
let zfar = 100.0;
2222

23-
let scene = Scene::new().with_geometry(generate_scene());
23+
let scene = Scene::new().geometry(generate_scene()).construct();
2424

25-
let camera = Camera::new()
26-
.look_at(eye, focus, up)
27-
.perspective(fovy, width, height, znear, zfar);
25+
let camera = Camera::configure()
26+
.observation(Camera::look_at(eye, focus, up))
27+
.perspective(Camera::perspective(fovy, width, height, znear, zfar))
28+
.build();
2829

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

raydeon/examples/lit_cubes.rs

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use raydeon::lights::PointLight;
2-
use raydeon::material::Material;
32
use raydeon::shapes::AxisAlignedCuboid;
3+
use raydeon::Material;
44
use raydeon::{Camera, Scene, SceneLighting, WPoint3, WVec3};
55
use std::sync::Arc;
66

@@ -10,7 +10,7 @@ fn main() {
1010
.init();
1111

1212
let scene = Scene::new()
13-
.with_geometry(vec![
13+
.geometry(vec![
1414
Arc::new(AxisAlignedCuboid::tagged(
1515
(-1.0, -1.0, -1.0),
1616
(1.0, 1.0, 1.0),
@@ -27,7 +27,7 @@ fn main() {
2727
Material::new(3.0, 2.0, 2.0, 0),
2828
)),
2929
])
30-
.with_lighting(
30+
.lighting(
3131
SceneLighting::new()
3232
.with_lights(vec![Arc::new(PointLight::new(
3333
20.0,
@@ -38,7 +38,8 @@ fn main() {
3838
0.23,
3939
))])
4040
.with_ambient_lighting(0.13),
41-
);
41+
)
42+
.construct();
4243

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

53-
let camera = Camera::new()
54-
.look_at(eye, focus, up)
55-
.perspective(fovy, width, height, znear, zfar);
54+
let camera = Camera::configure()
55+
.observation(Camera::look_at(eye, focus, up))
56+
.perspective(Camera::perspective(fovy, width, height, znear, zfar))
57+
.build();
5658

5759
let render_result = scene
5860
.attach_camera(camera)

raydeon/examples/triangles.rs

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,20 @@ fn main() {
88
.format_timestamp_nanos()
99
.init();
1010

11-
let scene = Scene::new().with_geometry(vec![
12-
Arc::new(Triangle::new(
13-
WPoint3::new(0.0, 0.0, 0.0),
14-
WPoint3::new(0.0, 0.0, 1.0),
15-
WPoint3::new(1.0, 0.0, 1.0),
16-
)),
17-
Arc::new(Triangle::new(
18-
WPoint3::new(0.25, 0.25, 0.0),
19-
WPoint3::new(0.0, 0.25, 1.0),
20-
WPoint3::new(-0.65, 0.25, 1.0),
21-
)),
22-
]);
11+
let scene = Scene::new()
12+
.geometry(vec![
13+
Arc::new(Triangle::new(
14+
WPoint3::new(0.0, 0.0, 0.0),
15+
WPoint3::new(0.0, 0.0, 1.0),
16+
WPoint3::new(1.0, 0.0, 1.0),
17+
)),
18+
Arc::new(Triangle::new(
19+
WPoint3::new(0.25, 0.25, 0.0),
20+
WPoint3::new(0.0, 0.25, 1.0),
21+
WPoint3::new(-0.65, 0.25, 1.0),
22+
)),
23+
])
24+
.construct();
2325

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

36-
let camera = Camera::new()
37-
.look_at(eye, focus, up)
38-
.perspective(fovy, width, height, znear, zfar);
38+
let camera = Camera::configure()
39+
.observation(Camera::look_at(eye, focus, up))
40+
.perspective(Camera::perspective(fovy, width, height, znear, zfar))
41+
.build();
3942

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

0 commit comments

Comments
 (0)