Note: Bump mapping with non-diffuse materials does not work correctly, and smoothed normals will be flat when using a bump map.

```
extruded_path(
points,
x = 0,
y = 0,
z = 0,
polygon = NA,
polygon_end = NA,
breaks = NA,
closed = FALSE,
closed_smooth = TRUE,
polygon_add_points = 0,
twists = 0,
texture_repeats = 1,
straight = FALSE,
precomputed_control_points = FALSE,
width = 1,
width_end = NA,
width_ease = "spline",
smooth_normals = FALSE,
u_min = 0,
u_max = 1,
linear_step = FALSE,
end_caps = c(TRUE, TRUE),
material = diffuse(),
material_caps = NA,
angle = c(0, 0, 0),
order_rotation = c(1, 2, 3),
flipped = FALSE,
scale = c(1, 1, 1)
)
```

- points
Either a list of length-3 numeric vectors or 3-column matrix/data.frame specifying the x/y/z points that the path should go through.

- x
Default `0`. x-coordinate offset for the path.

- y
Default `0`. y-coordinate offset for the path.

- z
Default `0`. z-coordinate offset for the path.

- polygon
Defaults to a circle. A polygon with no holes, specified by a data.frame() parsable by `xy.coords()`. Vertices are taken as sequential rows. If the polygon isn't closed (the last vertex equal to the first), it will be closed automatically.

- polygon_end
Defaults to `polygon`. If specified, the number of vertices should equal the to the number of vertices of the polygon set in `polygon`. Vertices are taken as sequential rows. If the polygon isn't closed (the last vertex equal to the first), it will be closed automatically.

- breaks
Defaults to `20` times the number of control points in the bezier curve.

- closed
Default `FALSE`. If `TRUE`, the path will be closed by smoothly connecting the first and last points, also ensuring the final polygon is aligned to the first.

- closed_smooth
Default `TRUE`. If `closed = TRUE`, this will ensure C2 (second derivative) continuity between the ends. If `closed = FALSE`, the curve will only have C1 (first derivative) continuity between the ends.

- polygon_add_points
Default `0`. Positive integer specifying the number of points to fill in between polygon vertices. Higher numbers can give smoother results (especially when combined with `smooth_normals = TRUE`.

- twists
Default `0`. Number of twists in the polygon from one end to another.

- texture_repeats
Default `1`. Number of times to repeat the texture along the length of the path.

- straight
Default `FALSE`. If `TRUE`, straight lines will be used to connect the points instead of bezier curves.

- precomputed_control_points
Default `FALSE`. If `TRUE`, `points` argument will expect a list of control points calculated with the internal rayrender function `rayrender:::calculate_control_points()`.

- width
Default `0.1`. Curve width. If `width_ease == "spline"`, `width` is specified in a format that can be read by `xy.coords()` (with `y` as the width), and the `x` coordinate is between `0` and `1`, this can also specify the exact positions along the curve for the corresponding width values. If a numeric vector, specifies the different values of the width evenly along the curve. If not a single value, `width_end` will be ignored.

- width_end
Default `NA`. Width at end of path. Same as `width`, unless specified. Ignored if multiple width values specified in `width`.

- width_ease
Default `spline`. Ease function between width values. Other options: `linear`, `quad`, `cubic`, `exp`.

- smooth_normals
Default `FALSE`. Whether to smooth the normals of the polygon to remove sharp angles.

- u_min
Default `0`. Minimum parametric coordinate for the path. If `closed = TRUE`, values greater than one will refer to the beginning of the loop (but the path will be generated as two objects).

- u_max
Default `1`. Maximum parametric coordinate for the path. If `closed = TRUE`, values greater than one will refer to the beginning of the loop (but the path will be generated as two objects).

- linear_step
Default `FALSE`. Whether the polygon intervals should be set at linear intervals, rather than intervals based on the underlying bezier curve parameterization.

- end_caps
Default `c(TRUE, TRUE)`. Specifies whether to add an end cap to the beginning and end of a path.

- material
Default

`diffuse`

. The material, called from one of the material functions.- material_caps
Defaults to the same material set in `material`. Note: emissive objects may not currently function correctly when scaled.

- angle
Default `c(0, 0, 0)`. Angle of rotation around the x, y, and z axes, applied in the order specified in `order_rotation`.

- order_rotation
Default `c(1, 2, 3)`. The order to apply the rotations, referring to "x", "y", and "z".

- flipped
Default `FALSE`. Whether to flip the normals.

- scale
Default `c(1, 1, 1)`. Scale transformation in the x, y, and z directions. If this is a single value, number, the object will be scaled uniformly.

Single row of a tibble describing the cube in the scene.

```
if(run_documentation()) {
#Specify the points for the path to travel though and the ground material
points = list(c(0,0,1),c(-0.5,0,-1),c(0,1,-1),c(1,0.5,0),c(0.6,0.3,1))
ground_mat = material=diffuse(color="grey50",
checkercolor = "grey20",checkerperiod = 1.5)
}
if(run_documentation()) {
#Default path shape is a circle
generate_studio(depth=-0.4,material=ground_mat) |>
add_object(extruded_path(points = points, width=0.25,
material=diffuse(color="red"))) |>
add_object(sphere(y=3,z=5,x=2,material=light(intensity=15))) |>
render_scene(lookat=c(0.3,0.5,0.5),fov=12, width=800,height=800, clamp_value = 10,
aperture=0.025, samples=128, sample_method="sobol_blue")
}
if(run_documentation()) {
#Change the width evenly along the tube
generate_studio(depth=-0.4,material=ground_mat) |>
add_object(extruded_path(points = points, width=0.25,
width_end = 0.5,
material=diffuse(color="red"))) |>
add_object(sphere(y=3,z=5,x=2,material=light(intensity=15))) |>
render_scene(lookat=c(0.3,0.5,0.5),fov=12, width=800,height=800, clamp_value = 10,
aperture=0.025, samples=128, sample_method="sobol_blue")
}
if(run_documentation()) {
#Change the width along the full length of the tube
generate_studio(depth=-0.4,material=ground_mat) |>
add_object(extruded_path(points = points,
width=0.25*sinpi(0:72*20/180),
material=diffuse(color="red"))) |>
add_object(sphere(y=3,z=5,x=2,material=light(intensity=15))) |>
render_scene(lookat=c(0.3,0.5,0.5),fov=12, width=800,height=800, clamp_value = 10,
aperture=0.025, samples=128, sample_method="sobol_blue")
}
if(run_documentation()) {
#Specify the exact parametric x positions for the width values:
custom_width = data.frame(x=c(0,0.2,0.5,0.8,1), y=c(0.25,0.5,0,0.5,0.25))
generate_studio(depth=-0.4,material=ground_mat) |>
add_object(extruded_path(points = points,
width=custom_width,
material=diffuse(color="red"))) |>
add_object(sphere(y=3,z=5,x=2,material=light(intensity=15))) |>
render_scene(lookat=c(0.3,0.5,0.5),fov=12, width=800,height=800, clamp_value = 10,
aperture=0.025, samples=128, sample_method="sobol_blue")
}
if(run_documentation()) {
#Generate a star polygon
angles = seq(360,0,length.out=21)
xx = c(rep(c(1,0.75,0.5,0.75),5),1) * sinpi(angles/180)/4
yy = c(rep(c(1,0.75,0.5,0.75),5),1) * cospi(angles/180)/4
star_polygon = data.frame(x=xx,y=yy)
#Extrude a path using a star polygon
generate_studio(depth=-0.4,material=ground_mat) |>
add_object(extruded_path(points = points, width=0.5,
polygon = star_polygon,
material=diffuse(color="red"))) |>
add_object(sphere(y=3,z=5,x=2,material=light(intensity=15))) |>
render_scene(lookat=c(0.3,0.5,1),fov=12, width=800,height=800, clamp_value = 10,
aperture=0.025, samples=128, sample_method="sobol_blue")
}
if(run_documentation()) {
#Specify a circle polygon
angles = seq(360,0,length.out=21)
xx = sinpi(angles/180)/4
yy = cospi(angles/180)/4
circ_polygon = data.frame(x=xx,y=yy)
#Transform from the circle polygon to the star polygon and change the end cap material
generate_studio(depth=-0.4,material=ground_mat) |>
add_object(extruded_path(points = points, width=0.5,
polygon=circ_polygon, polygon_end = star_polygon,
material_cap = diffuse(color="white"),
material=diffuse(color="red"))) |>
add_object(sphere(y=3,z=5,x=2,material=light(intensity=15))) |>
render_scene(lookat=c(0.3,0.5,0.5),fov=12, width=800,height=800, clamp_value = 10,
aperture=0.025, samples=128, sample_method="sobol_blue")
}
if(run_documentation()) {
#Add three and a half twists along the path, and make sure the breaks are evenly spaced
generate_studio(depth=-0.4,material=ground_mat) |>
add_object(extruded_path(points = points, width=0.5, twists = 3.5,
polygon=star_polygon, linear_step = TRUE, breaks=360,
material_cap = diffuse(color="white"),
material=diffuse(color="red"))) |>
add_object(sphere(y=3,z=5,x=2,material=light(intensity=15))) |>
render_scene(lookat=c(0.3,0.5,0),fov=12, width=800,height=800, clamp_value = 10,
aperture=0.025, samples=128, sample_method="sobol_blue")
}
if(run_documentation()) {
#Smooth the normals for a less sharp appearance:
generate_studio(depth=-0.4,material=ground_mat) |>
add_object(extruded_path(points = points, width=0.5, twists = 3.5,
polygon=star_polygon,
linear_step = TRUE, breaks=360,
smooth_normals = TRUE,
material_cap = diffuse(color="white"),
material=diffuse(color="red"))) |>
add_object(sphere(y=3,z=5,x=2,material=light(intensity=15))) |>
render_scene(lookat=c(0.3,0.5,0),fov=12, width=800,height=800, clamp_value = 10,
aperture=0.025, samples=128, sample_method="sobol_blue")
}
if(run_documentation()) {
#Only generate part of the curve, specified by the u_min and u_max arguments
generate_studio(depth=-0.4,material=ground_mat) |>
add_object(extruded_path(points = points, width=0.5, twists = 3.5,
u_min = 0.2, u_max = 0.8,
polygon=star_polygon, linear_step = TRUE, breaks=360,
material_cap = diffuse(color="white"),
material=diffuse(color="red"))) |>
add_object(sphere(y=3,z=5,x=2,material=light(intensity=15))) |>
render_scene(lookat=c(0.3,0.5,0),fov=12, width=800,height=800, clamp_value = 10,
aperture=0.025, samples=128, sample_method="sobol_blue")
}
if(run_documentation()) {
#Render a Mobius strip with 1.5 turns
points = list(c(0,0,0),c(0.5,0.5,0),c(0,1,0),c(-0.5,0.5,0))
square_polygon = matrix(c(-1, -0.1, 0,
1, -0.1, 0,
1, 0.1, 0,
-1, 0.1, 0)/10, ncol=3,byrow = T)
generate_studio(depth=-0.2,
material=diffuse(color = "dodgerblue4", checkercolor = "#002a61",
checkerperiod = 1)) |>
add_object(extruded_path(points = points, polygon=square_polygon, closed = TRUE,
linear_step = TRUE, twists = 1.5, breaks = 720,
material = diffuse(noisecolor = "black", noise = 10,
noiseintensity = 10))) |>
add_object(sphere(y=20,x=0,z=21,material=light(intensity = 1000))) |>
render_scene(lookat=c(0,0.5,0), fov=10, samples=128, sample_method = "sobol_blue",
width = 800, height=800)
}
if(run_documentation()) {
#Create a green glass tube with the dielectric priority interface
#and fill it with a purple neon tube light
generate_ground(depth=-0.4,material=diffuse(color="grey50",
checkercolor = "grey20",checkerperiod = 1.5)) |>
add_object(extruded_path(points = points, width=0.7, linear_step = TRUE,
polygon = circ_polygon, twists = 2, closed = TRUE,
polygon_end = star_polygon,
material=dielectric(priority = 1, refraction = 1.2,
attenuation=c(1,0.3,1)*10))) |>
add_object(extruded_path(points = points, width=0.4, linear_step = TRUE,
polygon = circ_polygon,twists = 2, closed = TRUE,
polygon_end = star_polygon,
material=dielectric(priority = 0,refraction = 1))) |>
add_object(extruded_path(points = points, width=0.05, closed = TRUE,
material=light(color="purple", intensity = 5,
importance_sample = FALSE))) |>
add_object(sphere(y=10,z=-5,x=0,radius=5,material=light(color = "white",intensity = 5))) |>
render_scene(lookat=c(0,0.5,1),fov=12,
width=800,height=800, clamp_value = 10,
aperture=0.025, samples=128, sample_method="sobol_blue")
}
```