Fix #123324: Improve Cycles camera bounding box size calculation

Cycles runs a check to see if the camera is possibly inside a
volumetric object by seeing if the bounding box of the camera
and volumetric object intersect.

If the calculation is wrong (Cycles says the camera is outside the
volume when it's inside it), then the volume will not render properly.

This commit resolves most of these issues by making the camera
bounding box larger than before, taking into consideration
features like:

1. The impact DOF could have on the camera ray start position and how
that should impact the bounding box size.
2. Taking into consideration near clipping, which was missed from the
orthographic camera due to a oversight in a previous commit
(08cc73a9bb).

Pull Request: https://projects.blender.org/blender/blender/pulls/123341
This commit is contained in:
Alaska
2024-06-18 17:35:16 +02:00
committed by Brecht Van Lommel
parent 751745b2de
commit 56bb8b2b3c

View File

@@ -593,40 +593,70 @@ BoundBox Camera::viewplane_bounds_get()
* checks we need in a more clear and smart fashion? */
BoundBox bounds = BoundBox::empty;
const float max_aperture_size = aperture_ratio < 1.0f ? aperturesize / aperture_ratio :
aperturesize;
if (camera_type == CAMERA_PANORAMA) {
const float extend = max_aperture_size + nearclip;
if (use_spherical_stereo == false) {
bounds.grow(make_float3(cameratoworld.x.w, cameratoworld.y.w, cameratoworld.z.w), nearclip);
bounds.grow(make_float3(cameratoworld.x.w, cameratoworld.y.w, cameratoworld.z.w), extend);
}
else {
float half_eye_distance = interocular_distance * 0.5f;
bounds.grow(
make_float3(cameratoworld.x.w + half_eye_distance, cameratoworld.y.w, cameratoworld.z.w),
nearclip);
extend);
bounds.grow(
make_float3(cameratoworld.z.w, cameratoworld.y.w + half_eye_distance, cameratoworld.z.w),
nearclip);
extend);
bounds.grow(
make_float3(cameratoworld.x.w - half_eye_distance, cameratoworld.y.w, cameratoworld.z.w),
nearclip);
extend);
bounds.grow(
make_float3(cameratoworld.x.w, cameratoworld.y.w - half_eye_distance, cameratoworld.z.w),
nearclip);
extend);
}
}
else {
bounds.grow(transform_raster_to_world(0.0f, 0.0f));
bounds.grow(transform_raster_to_world(0.0f, (float)height));
bounds.grow(transform_raster_to_world((float)width, (float)height));
bounds.grow(transform_raster_to_world((float)width, 0.0f));
/* max_aperture_size = Max horizontal distance a ray travels from aperture edge to focus point.
* Scale that value based on the ratio between focaldistance and nearclip to figure out the
* horizontal distance the DOF ray will travel before reaching the nearclip plane, where it
* will start rendering from.
* In some cases (focus distance is close to camera, and nearclip plane is far from camera),
* this scaled value is larger than nearclip, in which case we add it to `extend` to extend the
* bounding box to account for these rays.
*
* ----------------- nearclip plane
* / scaled_horz_dof_ray, nearclip
* /
* /
* / horz_dof_ray, focaldistance
* /|
* / |
* / |
* / |
* ------ max_aperture_size, 0
* 0, 0
*/
const float scaled_horz_dof_ray = (max_aperture_size > 0.0f) ?
max_aperture_size * (nearclip / focaldistance) :
0.0f;
const float extend = max_aperture_size + max(nearclip, scaled_horz_dof_ray);
bounds.grow(transform_raster_to_world(0.0f, 0.0f), extend);
bounds.grow(transform_raster_to_world(0.0f, (float)height), extend);
bounds.grow(transform_raster_to_world((float)width, (float)height), extend);
bounds.grow(transform_raster_to_world((float)width, 0.0f), extend);
if (camera_type == CAMERA_PERSPECTIVE) {
/* Center point has the most distance in local Z axis,
* use it to construct bounding box/
*/
bounds.grow(transform_raster_to_world(0.5f * width, 0.5f * height));
bounds.grow(transform_raster_to_world(0.5f * width, 0.5f * height), extend);
}
}
return bounds;