Fix #139718: Always treat OSL cameras as inside a volume

Cycles automatically tries to decide if the camera ray should be a
surface or a volume + surface camera ray by checking to see if the
scene contains a volumetric material, and if it does, is it near
where the camera rays are expected to spawn. This step is done
during scene intialization.

With the OSL camera, it is impratical to predict where the
camera rays will spawn during scene intialization, which makes it
impratical to predict if the OSL camera ray will spawn near a
volumetric object. So this commit marks all OSL cameras as
"inside a volume", leading to the spawning of volume + surface camera
rays for OSL cameras while the scene contains a volumetric material.

This leads to increased render times ranging between 1% - 5% in scenes
that use a OSL camera, has a volumetric object in it, and the
volumetric object is far away from the camera. Every other scene should
see no performance impact.

Testing was done on a AMD Ryzen 9 5950X and a NVIDIA GeForce RTX 4090.

Pull Request: https://projects.blender.org/blender/blender/pulls/142036
This commit is contained in:
Alaska
2025-07-16 16:25:38 +02:00
committed by Brecht Van Lommel
parent 89f966df4d
commit 736559f320
2 changed files with 27 additions and 21 deletions

View File

@@ -549,28 +549,34 @@ void Camera::device_update_volume(Device * /*device*/, DeviceScene *dscene, Scen
KernelIntegrator *kintegrator = &dscene->data.integrator;
if (kintegrator->use_volumes) {
BoundBox viewplane_boundbox = viewplane_bounds_get();
if (camera_type == CAMERA_CUSTOM) {
kernel_camera.is_inside_volume = 1;
LOG_INFO << "Considering custom camera to be inside volume.";
}
else {
BoundBox viewplane_boundbox = viewplane_bounds_get();
/* Parallel object update, with grain size to avoid too much threading overhead
* for individual objects. */
static const int OBJECTS_PER_TASK = 32;
parallel_for(blocked_range<size_t>(0, scene->objects.size(), OBJECTS_PER_TASK),
[&](const blocked_range<size_t> &r) {
for (size_t i = r.begin(); i != r.end(); i++) {
Object *object = scene->objects[i];
if (object->get_geometry()->has_volume &&
viewplane_boundbox.intersects(object->bounds)) {
/* TODO(sergey): Consider adding more grained check. */
LOG_INFO << "Detected camera inside volume.";
kernel_camera.is_inside_volume = 1;
parallel_for_cancel();
break;
/* Parallel object update, with grain size to avoid too much threading overhead
* for individual objects. */
static const int OBJECTS_PER_TASK = 32;
parallel_for(blocked_range<size_t>(0, scene->objects.size(), OBJECTS_PER_TASK),
[&](const blocked_range<size_t> &r) {
for (size_t i = r.begin(); i != r.end(); i++) {
Object *object = scene->objects[i];
if (object->get_geometry()->has_volume &&
viewplane_boundbox.intersects(object->bounds)) {
/* TODO(sergey): Consider adding more grained check. */
LOG_INFO << "Detected camera inside volume.";
kernel_camera.is_inside_volume = 1;
parallel_for_cancel();
break;
}
}
}
});
});
if (!kernel_camera.is_inside_volume) {
LOG_INFO << "Camera is outside of the volume.";
if (!kernel_camera.is_inside_volume) {
LOG_INFO << "Camera is outside of the volume.";
}
}
}