Cycles: add rejection of inf/nan samples, in principle these should not happen

but this makes it more reliable for now.

Also add an integrator "Clamp" option, to clamp very light samples to a maximum
value. This will reduce accuracy but may help reducing noise and speed up
convergence.
This commit is contained in:
Brecht Van Lommel
2012-04-05 15:17:45 +00:00
parent 5d0bfc0325
commit 6e93e33294
8 changed files with 72 additions and 2 deletions

View File

@@ -174,6 +174,13 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
default=0, default=0,
) )
cls.sample_clamp = FloatProperty(
name="Clamp",
description="If non-zero, the maximum value for a sample, higher values will be scaled down to avoid too much noise and slow convergence at the cost of accuracy.",
min=0.0, max=1e8,
default=0.0,
)
cls.debug_tile_size = IntProperty( cls.debug_tile_size = IntProperty(
name="Tile Size", name="Tile Size",
description="", description="",

View File

@@ -67,6 +67,7 @@ class CyclesRender_PT_integrator(CyclesButtonsPanel, Panel):
sub.prop(cscene, "samples", text="Render") sub.prop(cscene, "samples", text="Render")
sub.prop(cscene, "preview_samples", text="Preview") sub.prop(cscene, "preview_samples", text="Preview")
sub.prop(cscene, "seed") sub.prop(cscene, "seed")
sub.prop(cscene, "sample_clamp")
sub = col.column(align=True) sub = col.column(align=True)
sub.label("Transparency:") sub.label("Transparency:")

View File

@@ -157,6 +157,8 @@ void BlenderSync::sync_integrator()
integrator->layer_flag = render_layer.layer; integrator->layer_flag = render_layer.layer;
integrator->sample_clamp = get_float(cscene, "sample_clamp");
if(integrator->modified(previntegrator)) if(integrator->modified(previntegrator))
integrator->tag_update(scene); integrator->tag_update(scene);
} }

View File

@@ -294,5 +294,49 @@ __device_inline float3 path_radiance_sum(PathRadiance *L)
#endif #endif
} }
__device_inline void path_radiance_clamp(PathRadiance *L, float3 *L_sum, float clamp)
{
float sum = fabsf(L_sum->x) + fabsf(L_sum->y) + fabsf(L_sum->z);
if(!isfinite(sum)) {
/* invalid value, reject */
*L_sum = make_float3(0.0f, 0.0f, 0.0f);
#ifdef __PASSES__
if(L->use_light_pass) {
L->direct_diffuse = make_float3(0.0f, 0.0f, 0.0f);
L->direct_glossy = make_float3(0.0f, 0.0f, 0.0f);
L->direct_transmission = make_float3(0.0f, 0.0f, 0.0f);
L->indirect_diffuse = make_float3(0.0f, 0.0f, 0.0f);
L->indirect_glossy = make_float3(0.0f, 0.0f, 0.0f);
L->indirect_transmission = make_float3(0.0f, 0.0f, 0.0f);
L->emission = make_float3(0.0f, 0.0f, 0.0f);
}
#endif
}
else if(sum > clamp) {
/* value to high, scale down */
float scale = clamp/sum;
*L_sum *= scale;
#ifdef __PASSES__
if(L->use_light_pass) {
L->direct_diffuse *= scale;
L->direct_glossy *= scale;
L->direct_transmission *= scale;
L->indirect_diffuse *= scale;
L->indirect_glossy *= scale;
L->indirect_transmission *= scale;
L->emission *= scale;
}
#endif
}
}
CCL_NAMESPACE_END CCL_NAMESPACE_END

View File

@@ -396,6 +396,10 @@ __device float4 kernel_path_integrate(KernelGlobals *kg, RNG *rng, int sample, R
float3 L_sum = path_radiance_sum(&L); float3 L_sum = path_radiance_sum(&L);
#ifdef __CLAMP_SAMPLE__
path_radiance_clamp(&L, &L_sum, kernel_data.integrator.sample_clamp);
#endif
kernel_write_light_passes(kg, buffer, &L, sample); kernel_write_light_passes(kg, buffer, &L, sample);
return make_float4(L_sum.x, L_sum.y, L_sum.z, 1.0f - L_transparent); return make_float4(L_sum.x, L_sum.y, L_sum.z, 1.0f - L_transparent);

View File

@@ -60,6 +60,7 @@ CCL_NAMESPACE_BEGIN
#define __RAY_DIFFERENTIALS__ #define __RAY_DIFFERENTIALS__
#define __CAMERA_CLIPPING__ #define __CAMERA_CLIPPING__
#define __INTERSECTION_REFINE__ #define __INTERSECTION_REFINE__
#define __CLAMP_SAMPLE__
#ifdef __KERNEL_SHADING__ #ifdef __KERNEL_SHADING__
#define __SVM__ #define __SVM__
@@ -521,7 +522,12 @@ typedef struct KernelIntegrator {
/* render layer */ /* render layer */
int layer_flag; int layer_flag;
int pad1, pad2;
/* clamp */
float sample_clamp;
/* padding */
int pad;
} KernelIntegrator; } KernelIntegrator;
typedef struct KernelBVH { typedef struct KernelBVH {

View File

@@ -43,6 +43,7 @@ Integrator::Integrator()
no_caustics = false; no_caustics = false;
seed = 0; seed = 0;
layer_flag = ~0; layer_flag = ~0;
sample_clamp = 0.0f;
need_update = true; need_update = true;
} }
@@ -85,6 +86,8 @@ void Integrator::device_update(Device *device, DeviceScene *dscene)
kintegrator->use_ambient_occlusion = kintegrator->use_ambient_occlusion =
((dscene->data.film.pass_flag & PASS_AO) || dscene->data.background.ao_factor != 0.0f); ((dscene->data.film.pass_flag & PASS_AO) || dscene->data.background.ao_factor != 0.0f);
kintegrator->sample_clamp = (sample_clamp == 0.0f)? FLT_MAX: sample_clamp*3.0f;
/* sobol directions table */ /* sobol directions table */
int dimensions = PRNG_BASE_NUM + (max_bounce + transparent_max_bounce + 2)*PRNG_BOUNCE_NUM; int dimensions = PRNG_BASE_NUM + (max_bounce + transparent_max_bounce + 2)*PRNG_BOUNCE_NUM;
@@ -117,7 +120,8 @@ bool Integrator::modified(const Integrator& integrator)
transparent_shadows == integrator.transparent_shadows && transparent_shadows == integrator.transparent_shadows &&
no_caustics == integrator.no_caustics && no_caustics == integrator.no_caustics &&
layer_flag == integrator.layer_flag && layer_flag == integrator.layer_flag &&
seed == integrator.seed); seed == integrator.seed &&
sample_clamp == integrator.sample_clamp);
} }
void Integrator::tag_update(Scene *scene) void Integrator::tag_update(Scene *scene)

View File

@@ -45,6 +45,8 @@ public:
int seed; int seed;
int layer_flag; int layer_flag;
float sample_clamp;
bool need_update; bool need_update;
Integrator(); Integrator();