Cycles: Change sun lamp to have uniform intensity at high angles #108996
This fixes the issue described in #108957.
Instead of modeling distant lights like a disk light at infinity, it models them as cones. This way, the radiance is constant across the entire range of directions that it covers.
For smaller angles, the difference is very subtle, but for very large angles it becomes obvious (here's the file from #108957, the angle is 179°):
One notable detail is the sampling method: Using
sample_uniform_cone can increase noise, since the sampling method no longer preserves the stratification of the samples. This is visible in the "light tree multi distant" test scene.
Turns out we can do better, and after a bit of testing I found a way to adapt the concentric Shirley mapping to uniform cone sampling. I hope the comment explains the logic behind it reasonably well.
Here's the result, note that even the noise distribution is the same when using the new sampling:
|Method||Old||New, basic sampling||New, concentric sampling|
|Render time (at higher spp)||9.03sec||8.79sec||8.96sec|
I'm not sure if I got the
light->normalized handling right, since I don't really know what the expectation from Hydra is here.
I am unable to look into this patch properly this week because I am at a festival, but according to my experience cone sampling has severe numerical problems when the cone angle is small (is that the reason you are using
if (angle > 1e-4f)?). I have a sample_uniform_cone_concentric() in #108506 that deals with small angles.
I am unable to look into this patch properly this week because I am at a festival, but according to my experience cone sampling has severe numerical problems when the cone angle is small (is that the reason you are using if (angle > 1e-4f)?). I have a sample_uniform_cone_concentric() in #108506 that deals with small angles.
Ah, yeah, good catch - looks like we both ended up deriving the same method, but your implementation has the terms simplified further, and using
1-cos(x) directly helps with numerical issues of course.
In my version, I indeed noticed problems when the angle becomes too small (makes sense, since there's not that much resolution around 1.0), that's why I put the limit there. Using the
1-cos(x) trick together with
precise_angle should make that unnecessary, I'll give it a try.
Okay, I've updated the PR. As far as I can tell, it behaves correctly for small angles (on the order of 0.01°) now.
For those angles, the previous
dot(a, b) < cos(angle) actually becomes an issue, it stops working properly around 0.1° (due to the same cancellation issue - both values are almost 1).
This can be avoided with
precise_angle, but for performance reasons I added a variant using
fast_atan2f which is still more than sufficient here.
Performance numbers (quick test, not super reliable):
- without PR: 9.03sec
- before angle fix: 8.96sec
- with angle fix and simplified math (thanks @weizhen): 8.46sec
Still faster than the original state, and now it's more robust for small angles and more consistent for large ones.
I changed the
eval_fac so that it gives the same intensity regardless of the angular diameter. I will change the description here #108505.
How does it look like without
vector_angle()? For me comparing with dot product seems to behave properly even at
1e-7f, so I wonder if this is platform-related, because of fast math or something.
No due date set.
No dependencies set.
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?