Skip to content

Commit dcb6c3e

Browse files
authored
Merge pull request #3 from VirtualPlantLab/new_mesh
Update to new mesh API
2 parents 4310971 + 2ca5e00 commit dcb6c3e

6 files changed

Lines changed: 71 additions & 70 deletions

File tree

nice_trees.png

-655 KB
Binary file not shown.

test/forest.jl

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -207,15 +207,15 @@ And we can render the forest with the function `render` as in the binary tree
207207
example but passing the whole forest at once
208208
209209
=#
210-
render(Scene(newforest))
210+
render(Mesh(newforest))
211211
#=
212212
213213
If we iterate 4 more iterations we will start seeing the different individuals
214214
diverging in size due to the differences in growth rates
215215
216216
=#
217217
newforest = [simulate(tree, getInternode, 15) for tree in newforest];
218-
render(Scene(newforest))
218+
render(Mesh(newforest))
219219
#=
220220
221221
## Multithreaded simulation
@@ -233,7 +233,7 @@ newforest = deepcopy(forest)
233233
@threads for i in eachindex(forest)
234234
newforest[i] = simulate(forest[i], getInternode, 6)
235235
end
236-
render(Scene(newforest, parallel = true))
236+
render(Mesh(newforest, parallel = true))
237237
#=
238238
239239
An alternative way to perform the simulation is to have an outer loop for each timestep and an internal loop over the different trees. Although this approach is not required for this simple model, most FSP models will probably need such a scheme as growth of each individual plant will depend on competition for resources with neighbouring plants. In this case, this approach would look as follows:
@@ -245,18 +245,18 @@ for step in 1:15
245245
newforest[i] = simulate(newforest[i], getInternode, 1)
246246
end
247247
end
248-
render(Scene(newforest, parallel = true))
248+
render(Mesh(newforest, parallel = true))
249249
#=
250250
251-
# Customizing the scene
251+
# Customizing the mesh
252252
253-
Here we are going to customize the scene of our simulation by adding a horizontal tile represting soil and
253+
Here we are going to customize the mesh of our simulation by adding a horizontal tile represting soil and
254254
tweaking the 3D representation. When we want to combine plants generated from graphs with any other
255-
geometric element it is best to combine all these geometries in a `GLScene` object. We can start the scene
255+
geometric element it is best to combine all these geometries in a `GLScene` object. We can start the mesh
256256
with the `newforest` generated in the above:
257257
258258
=#
259-
scene = Scene(newforest);
259+
mesh = Mesh(newforest);
260260
#=
261261
262262
We can create the soil tile directly, without having to create a graph. The simplest approach is two use
@@ -273,29 +273,29 @@ rotatey!(soil, pi/2)
273273
VirtualPlantLab.translate!(soil, Vec(0.0, 10.5, 0.0))
274274
#=
275275
276-
We can now add the `soil` to the `scene` object with the `add!` function.
276+
We can now add the `soil` to the `mesh` object with the `add!` function.
277277
278278
=#
279-
VirtualPlantLab.add!(scene, mesh = soil, colors = RGB(1,1,0))
279+
VirtualPlantLab.add!(mesh, soil, colors = RGB(1,1,0))
280280
#=
281281
282-
We can now render the scene that combines the random forest of binary trees and a yellow soil. Notice that
282+
We can now render the mesh that combines the random forest of binary trees and a yellow soil. Notice that
283283
in all previous figures, a coordinate system with grids was being depicted. This is helpful for debugging
284-
your code but also to help setup the scene (e.g. if you are not sure how big the soil tile should be).
284+
your code but also to help setup the mesh (e.g. if you are not sure how big the soil tile should be).
285285
Howver, it may be distracting for the visualization. It turns out that we can turn that off with
286286
`show_axes = false`:
287287
288288
=#
289-
render(scene, axes = false)
289+
render(mesh, axes = false)
290290
#=
291291
292-
We may also want to save a screenshot of the scene. For this, we need to store the output of the `render` function.
293-
We can then resize the window rendering the scene, move around, zoom, etc. When we have a perspective that we like,
292+
We may also want to save a screenshot of the mesh. For this, we need to store the output of the `render` function.
293+
We can then resize the window rendering the mesh, move around, zoom, etc. When we have a perspective that we like,
294294
we can run the `save_scene` function on the object returned from `render`. The argument `resolution` can be adjusted in both
295295
`render` to increase the number of pixels in the final image. A helper function `calculate_resolution` is provided to
296296
compute the resolution from a physical width and height in cm and a dpi (e.g., useful for publications and posters):
297297
298298
=#
299299
res = calculate_resolution(width = 16.0, height = 16.0, dpi = 1_000)
300-
output = render(scene, axes = false, size = res)
300+
output = render(mesh, axes = false, size = res)
301301
export_scene(scene = output, filename = "nice_trees.png")

test/growthforest.jl

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ Centre for Crop Systems Analysis - Wageningen University
1111
> - Growth rules, based on information stored in organs (dimensions, carbon assimilation)
1212
> - Update dimensions in function of assimilation
1313
> - Compute sink strength
14-
> - Merge Scenes
14+
> - Merge meshes
1515
> - Generate forest on grid and retrieve canopy-level data (e.g., LAI)
1616
>
1717
@@ -395,8 +395,8 @@ end
395395
396396
As in the previous example, it makes sense to visualize the forest with a soil
397397
tile beneath it. Unlike in the previous example, we will construct the soil tile
398-
using a dedicated graph and generate a `Scene` object which can later be
399-
merged with the rest of scene generated in daily step:
398+
using a dedicated graph and generate a `Mesh` object which can later be
399+
merged with the rest of mesh generated in daily step:
400400
401401
=#
402402
Base.@kwdef struct Soil <: VirtualPlantLab.Node
@@ -408,19 +408,19 @@ function VirtualPlantLab.feed!(turtle::Turtle, s::Soil, vars)
408408
end
409409
soil_graph = RA(-90.0) + T(Vec(0.0, 10.0, 0.0)) + ## Moves into position
410410
Soil(length = 20.0, width = 20.0) ## Draws the soil tile
411-
soil = Scene(Graph(axiom = soil_graph));
411+
soil = Mesh(Graph(axiom = soil_graph));
412412
render(soil, axes = false)
413413
#=
414414
415-
And the following function renders the entire scene (notice that we need to
416-
use `display()` to force the rendering of the scene when called within a loop
415+
And the following function renders the entire mesh (notice that we need to
416+
use `display()` to force the rendering of the mesh when called within a loop
417417
or a function):
418418
419419
=#
420420
function render_forest(forest, soil)
421-
scene = Scene(vec(forest)) ## create scene from forest
422-
scene = Scene([scene, soil]) ## merges the two scenes
423-
render(scene)
421+
mesh = Mesh(vec(forest)) ## create mesh from forest
422+
mesh = Mesh([mesh, soil]) ## merges the two scenes
423+
render(mesh)
424424
end
425425
#=
426426

test/raytracedforest.jl

Lines changed: 33 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -206,14 +206,14 @@ end
206206
207207
As growth is now dependent on intercepted PAR via RUE, we now need to simulate
208208
light interception by the trees. We will use a ray-tracing approach to do so.
209-
The first step is to create a scene with the trees and the light sources. As for
210-
rendering, the scene can be created from the `forest` object by simply calling
211-
`Scene(forest)` that will generate the 3D meshes and connect them to their
209+
The first step is to create a mesh with the trees and the light sources. As for
210+
rendering, the mesh can be created from the `forest` object by simply calling
211+
`Mesh(forest)` that will generate the 3D meshes and connect them to their
212212
optical properties.
213213
214214
However, we also want to add the soil surface as this will affect the light
215-
distribution within the scene due to reflection from the soil surface. This is
216-
similar to the customized scene that we created before for rendering, but now
215+
distribution within the mesh due to reflection from the soil surface. This is
216+
similar to the customized mesh that we created before for rendering, but now
217217
for the light simulation.
218218
219219
=#
@@ -225,29 +225,29 @@ function create_soil()
225225
end
226226
function create_scene(forest)
227227
# These are the trees
228-
scene = Scene(vec(forest))
228+
mesh = Mesh(vec(forest))
229229
# Add a soil surface
230230
soil = create_soil()
231231
soil_material = Lambertian= 0.0, ρ = 0.21)
232-
add!(scene, mesh = soil, materials = soil_material)
233-
# Return the scene
234-
return scene
232+
add!(mesh, soil, materials = soil_material)
233+
# Return the mesh
234+
return mesh
235235
end
236236
#=
237237
238-
Given the scene, we can create the light sources that can approximate the solar
238+
Given the mesh, we can create the light sources that can approximate the solar
239239
irradiance on a given day, location and time of the day using the functions from
240240
the package (see package documentation for details). Given the latitude,
241241
day of year and fraction of the day (`f = 0` being sunrise and `f = 1` being sunset),
242242
the function `clear_sky()` computes the direct and diffuse solar radiation assuming
243243
a clear sky. These values may be converted to different wavebands and units using
244244
`waveband_conversion()`. Finally, the collection of light sources approximating
245245
the solar irradiance distribution over the sky hemisphere is constructed with the
246-
function `sky()` (this last step requires the 3D scene as input in order to place
246+
function `sky()` (this last step requires the 3D mesh as input in order to place
247247
the light sources adequately).
248248
249249
=#
250-
function create_sky(;scene, lat = 52.0*π/180.0, DOY = 182)
250+
function create_sky(;mesh, lat = 52.0*π/180.0, DOY = 182)
251251
# Fraction of the day and day length
252252
fs = collect(0.1:0.1:0.9)
253253
dec = declination(DOY)
@@ -264,7 +264,7 @@ function create_sky(;scene, lat = 52.0*π/180.0, DOY = 182)
264264
Idir_PAR = f_dir.*Idir
265265
Idif_PAR = f_dif.*Idif
266266
# Create the dome of diffuse light
267-
dome = sky(scene,
267+
dome = sky(mesh,
268268
Idir = 0.0, ## No direct solar radiation
269269
Idif = sum(Idir_PAR)/10*DL, ## Daily Diffuse solar radiation
270270
nrays_dif = 1_000_000, ## Total number of rays for diffuse solar radiation
@@ -274,20 +274,20 @@ function create_sky(;scene, lat = 52.0*π/180.0, DOY = 182)
274274
nphi = 12) ## Number of discretization steps in the azimuth angle
275275
# Add direct sources for different times of the day
276276
for I in Idir_PAR
277-
push!(dome, sky(scene, Idir = I/10*DL, nrays_dir = 100_000, Idif = 0.0)[1])
277+
push!(dome, sky(mesh, Idir = I/10*DL, nrays_dir = 100_000, Idif = 0.0)[1])
278278
end
279279
return dome
280280
end
281281
#=
282282
283-
The 3D scene and the light sources are then combined into a `RayTracer` object,
283+
The 3D mesh and the light sources are then combined into a `RayTracer` object,
284284
together with general settings for the ray tracing simulation chosen via `RTSettings()`.
285285
The most important settings refer to the Russian roulette system and the grid
286286
cloner (see section on Ray Tracing for details). The settings for the Russian
287287
roulette system include the number of times a ray will be traced
288288
deterministically (`maxiter`) and the probability that a ray that exceeds `maxiter`
289289
is terminated (`pkill`). The grid cloner is used to approximate an infinite canopy
290-
by replicating the scene in the different directions (`nx` and `ny` being the
290+
by replicating the mesh in the different directions (`nx` and `ny` being the
291291
number of replicates in each direction along the x and y axes, respectively). It
292292
is also possible to turn on parallelization of the ray tracing simulation by
293293
setting `parallel = true` (currently this uses Julia's builtin multithreading
@@ -296,26 +296,26 @@ capabilities).
296296
In addition `RTSettings()`, an acceleration structure and a splitting rule can
297297
be defined when creating the `RayTracer` object (see ray tracing documentation
298298
for details). The acceleration structure allows speeding up the ray tracing
299-
by avoiding testing all rays against all objects in the scene.
299+
by avoiding testing all rays against all objects in the mesh.
300300
301301
=#
302-
function create_raytracer(scene, sources)
302+
function create_raytracer(mesh, sources)
303303
settings = RTSettings(pkill = 0.9, maxiter = 4, nx = 5, ny = 5, parallel = true)
304-
RayTracer(scene, sources, settings = settings, acceleration = BVH,
304+
RayTracer(mesh, sources, settings = settings, acceleration = BVH,
305305
rule = SAH{3}(5, 10));
306306
end
307307
#=
308308
309309
The actual ray tracing simulation is performed by calling the `trace!()` method
310310
on the ray tracing object. This will trace all rays from all light sources and
311-
update the radiant power absorbed by the different surfaces in the scene inside
311+
update the radiant power absorbed by the different surfaces in the mesh inside
312312
the `Material` objects (see `feed!()` above):
313313
314314
=#
315315
function run_raytracer!(forest; DOY = 182)
316-
scene = create_scene(forest)
317-
sources = create_sky(scene = scene, DOY = DOY)
318-
rtobj = create_raytracer(scene, sources)
316+
mesh = create_scene(forest)
317+
sources = create_sky(mesh = mesh, DOY = DOY)
318+
rtobj = create_raytracer(mesh, sources)
319319
trace!(rtobj)
320320
return nothing
321321
end
@@ -544,32 +544,33 @@ end
544544
545545
As in the previous example, it makes sense to visualize the forest with a soil
546546
tile beneath it. Unlike in the previous example, we will construct the soil tile
547-
using a dedicated graph and generate a `Scene` object which can later be
548-
merged with the rest of scene generated in daily step:
547+
using a dedicated graph and generate a `Mesh` object which can later be
548+
merged with the rest of mesh generated in daily step:
549549
550550
=#
551551
Base.@kwdef struct Soil <: VirtualPlantLab.Node
552552
length::Float64
553553
width::Float64
554554
end
555555
function VirtualPlantLab.feed!(turtle::Turtle, s::Soil, data)
556-
Rectangle!(turtle, length = s.length, width = s.width, colors = RGB(255/255, 236/255, 179/255))
556+
Rectangle!(turtle, length = s.length, width = s.width, colors = RGB(255/255, 236/255, 179/255),
557+
materials = Lambertian= 0.0, ρ = 0.21))
557558
end
558559
soil_graph = RA(-90.0) + T(Vec(0.0, 10.0, 0.0)) + ## Moves into position
559560
Soil(length = 20.0, width = 20.0) ## Draws the soil tile
560-
soil = Scene(Graph(axiom = soil_graph));
561+
soil = Mesh(Graph(axiom = soil_graph));
561562
render(soil, axes = false)
562563
#=
563564
564-
And the following function renders the entire scene (notice that we need to
565-
use `display()` to force the rendering of the scene when called within a loop
565+
And the following function renders the entire mesh (notice that we need to
566+
use `display()` to force the rendering of the mesh when called within a loop
566567
or a function):
567568
568569
=#
569570
function render_forest(forest, soil)
570-
scene = Scene(vec(forest)) ## create scene from forest
571-
scene = Scene([scene, soil]) ## merges the two scenes
572-
render(scene)
571+
mesh = Mesh(vec(forest)) ## create mesh from forest
572+
mesh = Mesh([mesh, soil]) ## merges the two scenes
573+
render(mesh)
573574
end
574575
#=
575576

test/snowflakes.jl

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ class to implement the edges of the snowflake. This can be achieved as follows:
4848
4949
=#
5050
using VirtualPlantLab
51-
import GLMakie ## Import rather than "using" to avoid masking Scene
51+
import GLMakie ## Import rather than "using" to avoid masking Mesh
5252
using ColorTypes ## To define colors for the rendering
5353
module sn
5454
import VirtualPlantLab
@@ -128,7 +128,7 @@ After defining the method, we can now call the function render on the graph to
128128
generate a 3D interactive image of the Koch snowflake in the current state
129129
130130
=#
131-
sc = Scene(Koch)
131+
sc = Mesh(Koch)
132132
render(sc, axes = false)
133133
#=
134134
@@ -138,7 +138,7 @@ snowflake. Let's execute the rules once to verify that we get the 2nd iteration
138138
139139
=#
140140
rewrite!(Koch)
141-
render(Scene(Koch), axes = false)
141+
render(Mesh(Koch), axes = false)
142142
#=
143143
144144
And two more times
@@ -147,7 +147,7 @@ And two more times
147147
for i in 1:3
148148
rewrite!(Koch)
149149
end
150-
render(Scene(Koch), axes = false)
150+
render(Mesh(Koch), axes = false)
151151
#=
152152
153153
# Other snowflake fractals
@@ -172,13 +172,13 @@ iterations and render the results
172172
=#
173173
## First iteration
174174
rewrite!(Koch2)
175-
render(Scene(Koch2), axes = false)
175+
render(Mesh(Koch2), axes = false)
176176
## Second iteration
177177
rewrite!(Koch2)
178-
render(Scene(Koch2), axes = false)
178+
render(Mesh(Koch2), axes = false)
179179
## Third iteration
180180
rewrite!(Koch2)
181-
render(Scene(Koch2), axes = false)
181+
render(Mesh(Koch2), axes = false)
182182
#=
183183
184184
This is know as [Koch
@@ -190,18 +190,18 @@ axiom:
190190
=#
191191
axiomCesaro = sn.E(L) + RU(90.0) + sn.E(L) + RU(90.0) + sn.E(L) + RU(90.0) + sn.E(L)
192192
Cesaro = Graph(axiom = axiomCesaro, rules = (rule2,))
193-
render(Scene(Cesaro), axes = false)
193+
render(Mesh(Cesaro), axes = false)
194194
#=
195195
196196
And, as before, let's go through the first three iterations
197197
198198
=#
199199
## First iteration
200200
rewrite!(Cesaro)
201-
render(Scene(Cesaro), axes = false)
201+
render(Mesh(Cesaro), axes = false)
202202
## Second iteration
203203
rewrite!(Cesaro)
204-
render(Scene(Cesaro), axes = false)
204+
render(Mesh(Cesaro), axes = false)
205205
## Third iteration
206206
rewrite!(Cesaro)
207-
render(Scene(Cesaro), axes = false)
207+
render(Mesh(Cesaro), axes = false)

test/tree.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -186,11 +186,11 @@ newtree = simulate(tree, getInternode, 2)
186186
The binary tree after two iterations has two branches, as expected:
187187
188188
=#
189-
render(Scene(newtree))
189+
render(Mesh(newtree))
190190
#=
191191
192192
Notice how the lengths of the prisms representing internodes decreases as the branching order increases, as the internodes are younger (i.e. were generated fewer generations ago). Further steps will generate a structure that is more tree-like.
193193
194194
=#
195195
newtree = simulate(newtree, getInternode, 15)
196-
render(Scene(newtree))
196+
render(Mesh(newtree))

0 commit comments

Comments
 (0)