mirror of
https://github.com/blender/blender
synced 2026-09-29 04:37:17 +03:00
Cycles: Fallback to area PDF when spherical rectangles are too small
This fixes #69535 and #98930. We use a equi-solid-angle sampling algorithm for rectangular area lights, but it is not particularly robust for small area lights (either small in general and/or small because it's being viewed from grazing angles). The actual sampling part is fine since it just gets clamped into the valid area anyways, and the difference isn't notable for small lights. However, we also need to compute the solid angle to get the sampling PDF, and that computation is quite sensitive to numerical issues for small values. Therefore, this commit adds a fallback path for small values, which instead uses the classic equi-area sampling PDF term times the area-to-solid-angle Jacobian term. This approximation assumes that all points on the light have the same distance and angle to the sampling point, which is of course not strictly the case, but it's close enough for small area lights and better than failing altogether. Pull Request: https://projects.blender.org/blender/blender/pulls/122323
This commit is contained in:
parent
a5dc233aa2
commit
fbc770d58b
2 changed files with 17 additions and 8 deletions
|
|
@ -81,11 +81,20 @@ ccl_device_inline float area_light_rect_sample(float3 P,
|
|||
}
|
||||
|
||||
/* return pdf */
|
||||
if (S != 0.0f) {
|
||||
return 1.0f / S;
|
||||
if (S < 1e-5f || reduce_min(sqr(nz)) > 0.99999f) {
|
||||
/* The solid angle is too small to be computed accurately in single precision.
|
||||
* As a fallback, approximate it using the planar sampling PDF,
|
||||
* for such tiny lights the difference is irrelevant.
|
||||
*
|
||||
* A threshold of 1e-5 was found to be the smallest option that avoids structured
|
||||
* artifacts at all tested parameter combinations. The additional check of nz is
|
||||
* needed for the case where the light is viewed from grazing angles, see e.g. #98930.
|
||||
*/
|
||||
const float t = len(dir);
|
||||
return -t * t * t / (z0 * len_u * len_v);
|
||||
}
|
||||
else {
|
||||
return 0.0f;
|
||||
return 1.0f / S;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -387,6 +387,11 @@ ccl_device_inline float len_squared(const float4 a)
|
|||
return dot(a, a);
|
||||
}
|
||||
|
||||
ccl_device_inline float4 sqr(const float4 a)
|
||||
{
|
||||
return a * a;
|
||||
}
|
||||
|
||||
#if !defined(__KERNEL_METAL__)
|
||||
ccl_device_inline float distance(const float4 a, const float4 b)
|
||||
{
|
||||
|
|
@ -412,11 +417,6 @@ ccl_device_inline float4 sqrt(const float4 a)
|
|||
# endif
|
||||
}
|
||||
|
||||
ccl_device_inline float4 sqr(const float4 a)
|
||||
{
|
||||
return a * a;
|
||||
}
|
||||
|
||||
ccl_device_inline float4 cross(const float4 a, const float4 b)
|
||||
{
|
||||
# ifdef __KERNEL_SSE__
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue