Fix emissive volumes generates unexpected fireflies around intersections
Discard the whole volume stack on the last bounce (but keep world volume if present). Volumes are expected to be closed manifol meshes, meaning if ray entered the volume there should be an intersection event of ray exisintg the volume. Case when ray hit nothing and there are still non-world volumes in the stack can happen in either of cases. 1. Mesh is not closed manifold. Such configurations are not really supported anyway and should not be used. Previous code would have consider the infinite length of the ray to sample across, so render result wasn't really correct anyway. 2. Exit intersection is more far away than the camera far clip distance. This case also will behave differently now, but previously it wasn't really correct either, so it's not like we're breaking something which was working as expected. 3. We missed exit event due to intersection precision issues. This is exact the case which this patch fixes and avoid fireflies. 4. Volume has Camera only visibility (all the rest visibility is set to off) This is what could be considered a regression but could be solved quite easily by checking volume stack's objects flags and keep entries which doesn't have Volume Scatter visibility (or even better: ensure Volume Scatter visibility for objects with volume closure), Fixes T46108: Cycles - Overlapping emissive volumes generates unexpected bright hotspots around the intersection Also fixes fireflies appearing on the edges of cube with emissive volue. Reviewers: juicyfruit, brecht Reviewed By: brecht Maniphest Tasks: T46108 Differential Revision: https://developer.blender.org/D2212
This commit is contained in:
parent
0a26904a75
commit
dd58390d71
@ -141,6 +141,10 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg,
|
|||||||
#endif /* __LAMP_MIS__ */
|
#endif /* __LAMP_MIS__ */
|
||||||
|
|
||||||
#ifdef __VOLUME__
|
#ifdef __VOLUME__
|
||||||
|
/* Sanitize volume stack. */
|
||||||
|
if(!hit) {
|
||||||
|
kernel_volume_clean_stack(kg, state->volume_stack);
|
||||||
|
}
|
||||||
/* volume attenuation, emission, scatter */
|
/* volume attenuation, emission, scatter */
|
||||||
if(state->volume_stack[0].shader != SHADER_NONE) {
|
if(state->volume_stack[0].shader != SHADER_NONE) {
|
||||||
Ray volume_ray = *ray;
|
Ray volume_ray = *ray;
|
||||||
@ -658,6 +662,10 @@ ccl_device_inline float4 kernel_path_integrate(KernelGlobals *kg,
|
|||||||
#endif /* __LAMP_MIS__ */
|
#endif /* __LAMP_MIS__ */
|
||||||
|
|
||||||
#ifdef __VOLUME__
|
#ifdef __VOLUME__
|
||||||
|
/* Sanitize volume stack. */
|
||||||
|
if(!hit) {
|
||||||
|
kernel_volume_clean_stack(kg, state.volume_stack);
|
||||||
|
}
|
||||||
/* volume attenuation, emission, scatter */
|
/* volume attenuation, emission, scatter */
|
||||||
if(state.volume_stack[0].shader != SHADER_NONE) {
|
if(state.volume_stack[0].shader != SHADER_NONE) {
|
||||||
Ray volume_ray = ray;
|
Ray volume_ray = ray;
|
||||||
|
@ -294,6 +294,10 @@ ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, in
|
|||||||
#endif /* __KERNEL_DEBUG__ */
|
#endif /* __KERNEL_DEBUG__ */
|
||||||
|
|
||||||
#ifdef __VOLUME__
|
#ifdef __VOLUME__
|
||||||
|
/* Sanitize volume stack. */
|
||||||
|
if(!hit) {
|
||||||
|
kernel_volume_clean_stack(kg, state.volume_stack);
|
||||||
|
}
|
||||||
/* volume attenuation, emission, scatter */
|
/* volume attenuation, emission, scatter */
|
||||||
if(state.volume_stack[0].shader != SHADER_NONE) {
|
if(state.volume_stack[0].shader != SHADER_NONE) {
|
||||||
Ray volume_ray = ray;
|
Ray volume_ray = ray;
|
||||||
|
@ -1262,4 +1262,30 @@ ccl_device void kernel_volume_stack_update_for_subsurface(KernelGlobals *kg,
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* Clean stack after the last bounce.
|
||||||
|
*
|
||||||
|
* It is expected that all volumes are closed manifolds, so at the time when ray
|
||||||
|
* hits nothing (for example, it is a last bounce which goes to environment) the
|
||||||
|
* only expected volume in the stack is the world's one. All the rest volume
|
||||||
|
* entries should have been exited already.
|
||||||
|
*
|
||||||
|
* This isn't always true because of ray intersection precision issues, which
|
||||||
|
* could lead us to an infinite non-world volume in the stack, causing render
|
||||||
|
* artifacts.
|
||||||
|
*
|
||||||
|
* Use this function after the last bounce to get rid of all volumes apart from
|
||||||
|
* the world's one after the last bounce to avoid render artifacts.
|
||||||
|
*/
|
||||||
|
ccl_device_inline void kernel_volume_clean_stack(KernelGlobals *kg,
|
||||||
|
VolumeStack *volume_stack)
|
||||||
|
{
|
||||||
|
if(kernel_data.background.volume_shader != SHADER_NONE) {
|
||||||
|
/* Keep the world's volume in stack. */
|
||||||
|
volume_stack[1].shader = SHADER_NONE;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
volume_stack[0].shader = SHADER_NONE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
CCL_NAMESPACE_END
|
CCL_NAMESPACE_END
|
||||||
|
Loading…
Reference in New Issue
Block a user