if (FALSE) { # interactive() || identical(Sys.getenv("IN_PKGDOWN"), "true")
# Write explicitly linear RGB radiance to EXR, including values greater than 1.
write_environment = function(image) {
file = tempfile(fileext = ".exr")
image = rayimage::ray_read_image(
image,
normalize = FALSE,
source_linear = TRUE,
assume_colorspace = rayimage::CS_SRGB
)
rayimage::ray_write_image(image, file, clamp = FALSE)
file
}
# 1. Add an independently adjustable fill to an existing environment.
# These constant-color maps make the color and brightness changes easy to see.
warm = cool = array(0, c(32, 64, 3))
warm_rgb = c(0.8, 0.3, 0.1)
cool_rgb = c(0.1, 0.3, 0.8)
for (channel in 1:3) {
warm[,, channel] = warm_rgb[channel]
cool[,, channel] = cool_rgb[channel]
}
warm_file = write_environment(warm)
cool_file = write_environment(cool)
# The included R logo retains its blue lettering and gray surround.
# The ground and oblique camera reveal contact shadows and the beveled edges.
base_scene = obj_model(r_obj(), scale = 2.5) |>
add_object(generate_ground(
depth = -0.96,
material = diffuse(color = "grey20")
)) |>
add_camera(camera(
lookfrom = c(2.5, 1.2, -6),
lookat = c(0, -0.05, 0),
fov = 28,
aperture = 0
))
warm_scene = base_scene |>
add_infinite_light(infinite_light(warm_file, name = "warm"))
set.seed(724)
render_scene(
warm_scene,
width = 600,
height = 500,
samples = 128,
integrator_type = "nee",
bloom = FALSE
)
# The two lights contribute warm + 0.5 * cool. The extra cool radiance
# lifts the blue lettering and shifts the background color.
# Keep exposure fixed between renders to see both the color and brightness change.
# The same approach adds fill to a photographic HDRI without editing that image.
additive_scene = warm_scene |>
add_infinite_light(infinite_light(cool_file, intensity = 0.5, name = "cool"))
set.seed(724)
render_scene(
additive_scene,
width = 600,
height = 500,
samples = 128,
integrator_type = "nee",
bloom = FALSE
)
# 2. Warm and cool fills on opposite sides, like two broad studio softboxes.
# Each EXR is dark except for a bright patch above the horizon. The patch is
# one-quarter across the map. Rotations of 30 and 210 degrees put the patches
# on opposite sides. A dim neutral environment keeps the front readable.
u = (seq_len(256) - 0.5) / 256
v = (seq_len(128) - 0.5) / 128
# Longitude wraps around: keep the softbox continuous at the EXR's edges.
du = ((u - 0.25 + 0.5) %% 1) - 0.5
softbox = outer(
exp(-((v - 0.32) / 0.18)^2),
exp(-(du / 0.12)^2)
)
warm_side = cool_side = array(0, c(128, 256, 3))
for (channel in 1:3) {
warm_side[,, channel] = 8 * warm_rgb[channel] * softbox
cool_side[,, channel] = 8 * cool_rgb[channel] * softbox
}
neutral_file = write_environment(array(0.08, c(32, 64, 3)))
warm_side_file = write_environment(warm_side)
cool_side_file = write_environment(cool_side)
fill_scene = base_scene |>
add_infinite_light(infinite_light(neutral_file, name = "neutral")) |>
add_infinite_light(infinite_light(
warm_side_file,
rotation = 30,
name = "warm_fill"
)) |>
add_infinite_light(infinite_light(
cool_side_file,
rotation = 210,
intensity = 0.75,
name = "cool_fill"
))
set.seed(724)
render_scene(
fill_scene,
width = 600,
height = 500,
samples = 128,
integrator_type = "nee",
bloom = FALSE
)
# Change either fill's intensity or rotation independently to shape the lighting.
# This gives independent control over both sides while retaining the base light.
}
Run the code above in your browser using DataLab