forked from bartvdbraak/blender
Cycles: Option to Sample all Lights in the Branched Path integrator for indirect samples
This adds a new option "Sample All Lights" to the Sampling panel in Cycles (Branched Path). When enabled, Cycles will sample all the lights in the scene for the indirect samples, instead of randomly picking one. This is already happening for direct samples, now you can optionally enable it for indirect. Example file and renders: Blend file: http://www.pasteall.org/blend/27411 Random: http://www.pasteall.org/pic/show.php?id=68033 All: http://www.pasteall.org/pic/show.php?id=68034 Sampling all lights is a bit slower, but there is less variance, so it should help in situations with many lights. Patch by myself with some tweaks by Brecht. Differential Revision: https://developer.blender.org/D391
This commit is contained in:
parent
6fdbab4366
commit
99e20d7b89
@ -252,6 +252,11 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
|
||||
items=enum_use_layer_samples,
|
||||
default='USE',
|
||||
)
|
||||
cls.sample_all_lights_indirect = BoolProperty(
|
||||
name="Sample All Lights",
|
||||
description="Sample all lights (for indirect samples), rather than randomly picking one",
|
||||
default=False,
|
||||
)
|
||||
|
||||
cls.no_caustics = BoolProperty(
|
||||
name="No Caustics",
|
||||
|
@ -133,6 +133,8 @@ class CyclesRender_PT_sampling(CyclesButtonsPanel, Panel):
|
||||
sub.label(text="AA Samples:")
|
||||
sub.prop(cscene, "aa_samples", text="Render")
|
||||
sub.prop(cscene, "preview_aa_samples", text="Preview")
|
||||
sub.separator()
|
||||
sub.prop(cscene, "sample_all_lights_indirect")
|
||||
|
||||
col = split.column()
|
||||
sub = col.column(align=True)
|
||||
|
@ -197,6 +197,8 @@ void BlenderSync::sync_integrator()
|
||||
#endif
|
||||
|
||||
integrator->method = (Integrator::Method)get_enum(cscene, "progressive");
|
||||
|
||||
integrator->sample_all_lights_indirect = get_boolean(cscene, "sample_all_lights_indirect");
|
||||
|
||||
int diffuse_samples = get_int(cscene, "diffuse_samples");
|
||||
int glossy_samples = get_int(cscene, "glossy_samples");
|
||||
|
@ -133,6 +133,93 @@ ccl_device_inline bool kernel_path_integrate_scatter_lighting(KernelGlobals *kg,
|
||||
|
||||
#if defined(__BRANCHED_PATH__) || defined(__SUBSURFACE__)
|
||||
|
||||
ccl_device void kernel_branched_path_integrate_direct_lighting(KernelGlobals *kg, RNG *rng,
|
||||
ShaderData *sd, PathState *state, float3 throughput, float num_samples_adjust, PathRadiance *L, bool sample_all_lights)
|
||||
{
|
||||
/* sample illumination from lights to find path contribution */
|
||||
if(sd->flag & SD_BSDF_HAS_EVAL) {
|
||||
Ray light_ray;
|
||||
BsdfEval L_light;
|
||||
bool is_lamp;
|
||||
|
||||
#ifdef __OBJECT_MOTION__
|
||||
light_ray.time = sd->time;
|
||||
#endif
|
||||
|
||||
if(sample_all_lights) {
|
||||
/* lamp sampling */
|
||||
for(int i = 0; i < kernel_data.integrator.num_all_lights; i++) {
|
||||
int num_samples = ceil_to_int(num_samples_adjust*light_select_num_samples(kg, i));
|
||||
float num_samples_inv = num_samples_adjust/(num_samples*kernel_data.integrator.num_all_lights);
|
||||
RNG lamp_rng = cmj_hash(*rng, i);
|
||||
|
||||
if(kernel_data.integrator.pdf_triangles != 0.0f)
|
||||
num_samples_inv *= 0.5f;
|
||||
|
||||
for(int j = 0; j < num_samples; j++) {
|
||||
float light_u, light_v;
|
||||
path_branched_rng_2D(kg, &lamp_rng, state, j, num_samples, PRNG_LIGHT_U, &light_u, &light_v);
|
||||
|
||||
if(direct_emission(kg, sd, i, 0.0f, 0.0f, light_u, light_v, &light_ray, &L_light, &is_lamp, state->bounce)) {
|
||||
/* trace shadow ray */
|
||||
float3 shadow;
|
||||
|
||||
if(!shadow_blocked(kg, state, &light_ray, &shadow)) {
|
||||
/* accumulate */
|
||||
path_radiance_accum_light(L, throughput*num_samples_inv, &L_light, shadow, num_samples_inv, state->bounce, is_lamp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* mesh light sampling */
|
||||
if(kernel_data.integrator.pdf_triangles != 0.0f) {
|
||||
int num_samples = ceil_to_int(num_samples_adjust*kernel_data.integrator.mesh_light_samples);
|
||||
float num_samples_inv = num_samples_adjust/num_samples;
|
||||
|
||||
if(kernel_data.integrator.num_all_lights)
|
||||
num_samples_inv *= 0.5f;
|
||||
|
||||
for(int j = 0; j < num_samples; j++) {
|
||||
float light_t = path_branched_rng_1D(kg, rng, state, j, num_samples, PRNG_LIGHT);
|
||||
float light_u, light_v;
|
||||
path_branched_rng_2D(kg, rng, state, j, num_samples, PRNG_LIGHT_U, &light_u, &light_v);
|
||||
|
||||
/* only sample triangle lights */
|
||||
if(kernel_data.integrator.num_all_lights)
|
||||
light_t = 0.5f*light_t;
|
||||
|
||||
if(direct_emission(kg, sd, -1, light_t, 0.0f, light_u, light_v, &light_ray, &L_light, &is_lamp, state->bounce)) {
|
||||
/* trace shadow ray */
|
||||
float3 shadow;
|
||||
|
||||
if(!shadow_blocked(kg, state, &light_ray, &shadow)) {
|
||||
/* accumulate */
|
||||
path_radiance_accum_light(L, throughput*num_samples_inv, &L_light, shadow, num_samples_inv, state->bounce, is_lamp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
float light_t = path_state_rng_1D(kg, rng, state, PRNG_LIGHT);
|
||||
float light_u, light_v;
|
||||
path_state_rng_2D(kg, rng, state, PRNG_LIGHT_U, &light_u, &light_v);
|
||||
|
||||
/* sample random light */
|
||||
if(direct_emission(kg, sd, -1, light_t, 0.0f, light_u, light_v, &light_ray, &L_light, &is_lamp, state->bounce)) {
|
||||
/* trace shadow ray */
|
||||
float3 shadow;
|
||||
|
||||
if(!shadow_blocked(kg, state, &light_ray, &shadow)) {
|
||||
/* accumulate */
|
||||
path_radiance_accum_light(L, throughput, &L_light, shadow, 1.0f, state->bounce, is_lamp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ccl_device void kernel_path_indirect(KernelGlobals *kg, RNG *rng, Ray ray, ccl_global float *buffer,
|
||||
float3 throughput, int num_samples, PathState state, PathRadiance *L)
|
||||
{
|
||||
@ -302,36 +389,8 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg, RNG *rng, Ray ray, ccl_g
|
||||
|
||||
#ifdef __EMISSION__
|
||||
if(kernel_data.integrator.use_direct_light) {
|
||||
/* sample illumination from lights to find path contribution */
|
||||
if(sd.flag & SD_BSDF_HAS_EVAL) {
|
||||
float light_t = path_state_rng_1D(kg, rng, &state, PRNG_LIGHT);
|
||||
#ifdef __MULTI_CLOSURE__
|
||||
float light_o = 0.0f;
|
||||
#else
|
||||
float light_o = path_state_rng_1D(kg, rng, &state, PRNG_LIGHT_F);
|
||||
#endif
|
||||
float light_u, light_v;
|
||||
path_state_rng_2D(kg, rng, &state, PRNG_LIGHT_U, &light_u, &light_v);
|
||||
|
||||
Ray light_ray;
|
||||
BsdfEval L_light;
|
||||
bool is_lamp;
|
||||
|
||||
#ifdef __OBJECT_MOTION__
|
||||
light_ray.time = sd.time;
|
||||
#endif
|
||||
|
||||
/* sample random light */
|
||||
if(direct_emission(kg, &sd, -1, light_t, light_o, light_u, light_v, &light_ray, &L_light, &is_lamp, state.bounce)) {
|
||||
/* trace shadow ray */
|
||||
float3 shadow;
|
||||
|
||||
if(!shadow_blocked(kg, &state, &light_ray, &shadow)) {
|
||||
/* accumulate */
|
||||
path_radiance_accum_light(L, throughput, &L_light, shadow, 1.0f, state.bounce, is_lamp);
|
||||
}
|
||||
}
|
||||
}
|
||||
bool all = kernel_data.integrator.sample_all_lights_indirect;
|
||||
kernel_branched_path_integrate_direct_lighting(kg, rng, &sd, &state, throughput, 1.0f, L, all);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -898,70 +957,7 @@ ccl_device_noinline void kernel_branched_path_integrate_lighting(KernelGlobals *
|
||||
PathState *state, PathRadiance *L, ccl_global float *buffer)
|
||||
{
|
||||
#ifdef __EMISSION__
|
||||
/* sample illumination from lights to find path contribution */
|
||||
if(sd->flag & SD_BSDF_HAS_EVAL) {
|
||||
Ray light_ray;
|
||||
BsdfEval L_light;
|
||||
bool is_lamp;
|
||||
|
||||
#ifdef __OBJECT_MOTION__
|
||||
light_ray.time = sd->time;
|
||||
#endif
|
||||
|
||||
/* lamp sampling */
|
||||
for(int i = 0; i < kernel_data.integrator.num_all_lights; i++) {
|
||||
int num_samples = ceil_to_int(num_samples_adjust*light_select_num_samples(kg, i));
|
||||
float num_samples_inv = num_samples_adjust/(num_samples*kernel_data.integrator.num_all_lights);
|
||||
RNG lamp_rng = cmj_hash(*rng, i);
|
||||
|
||||
if(kernel_data.integrator.pdf_triangles != 0.0f)
|
||||
num_samples_inv *= 0.5f;
|
||||
|
||||
for(int j = 0; j < num_samples; j++) {
|
||||
float light_u, light_v;
|
||||
path_branched_rng_2D(kg, &lamp_rng, state, j, num_samples, PRNG_LIGHT_U, &light_u, &light_v);
|
||||
|
||||
if(direct_emission(kg, sd, i, 0.0f, 0.0f, light_u, light_v, &light_ray, &L_light, &is_lamp, state->bounce)) {
|
||||
/* trace shadow ray */
|
||||
float3 shadow;
|
||||
|
||||
if(!shadow_blocked(kg, state, &light_ray, &shadow)) {
|
||||
/* accumulate */
|
||||
path_radiance_accum_light(L, throughput*num_samples_inv, &L_light, shadow, num_samples_inv, state->bounce, is_lamp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* mesh light sampling */
|
||||
if(kernel_data.integrator.pdf_triangles != 0.0f) {
|
||||
int num_samples = ceil_to_int(num_samples_adjust*kernel_data.integrator.mesh_light_samples);
|
||||
float num_samples_inv = num_samples_adjust/num_samples;
|
||||
|
||||
if(kernel_data.integrator.num_all_lights)
|
||||
num_samples_inv *= 0.5f;
|
||||
|
||||
for(int j = 0; j < num_samples; j++) {
|
||||
float light_t = path_branched_rng_1D(kg, rng, state, j, num_samples, PRNG_LIGHT);
|
||||
float light_u, light_v;
|
||||
path_branched_rng_2D(kg, rng, state, j, num_samples, PRNG_LIGHT_U, &light_u, &light_v);
|
||||
|
||||
/* only sample triangle lights */
|
||||
if(kernel_data.integrator.num_all_lights)
|
||||
light_t = 0.5f*light_t;
|
||||
|
||||
if(direct_emission(kg, sd, -1, light_t, 0.0f, light_u, light_v, &light_ray, &L_light, &is_lamp, state->bounce)) {
|
||||
/* trace shadow ray */
|
||||
float3 shadow;
|
||||
|
||||
if(!shadow_blocked(kg, state, &light_ray, &shadow)) {
|
||||
/* accumulate */
|
||||
path_radiance_accum_light(L, throughput*num_samples_inv, &L_light, shadow, num_samples_inv, state->bounce, is_lamp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
kernel_branched_path_integrate_direct_lighting(kg, rng, sd, state, throughput, num_samples_adjust, L, true);
|
||||
#endif
|
||||
|
||||
for(int i = 0; i< sd->num_closure; i++) {
|
||||
|
@ -834,6 +834,7 @@ typedef struct KernelIntegrator {
|
||||
int ao_samples;
|
||||
int mesh_light_samples;
|
||||
int subsurface_samples;
|
||||
int sample_all_lights_indirect;
|
||||
|
||||
/* mis */
|
||||
int use_lamp_mis;
|
||||
@ -847,7 +848,7 @@ typedef struct KernelIntegrator {
|
||||
int volume_max_steps;
|
||||
float volume_step_size;
|
||||
int volume_samples;
|
||||
int pad1, pad2;
|
||||
int pad1;
|
||||
} KernelIntegrator;
|
||||
|
||||
typedef struct KernelBVH {
|
||||
|
@ -130,6 +130,7 @@ void Integrator::device_update(Device *device, DeviceScene *dscene, Scene *scene
|
||||
kintegrator->mesh_light_samples = mesh_light_samples;
|
||||
kintegrator->subsurface_samples = subsurface_samples;
|
||||
kintegrator->volume_samples = volume_samples;
|
||||
kintegrator->sample_all_lights_indirect = sample_all_lights_indirect;
|
||||
|
||||
kintegrator->sampling_pattern = sampling_pattern;
|
||||
|
||||
@ -197,7 +198,8 @@ bool Integrator::modified(const Integrator& integrator)
|
||||
subsurface_samples == integrator.subsurface_samples &&
|
||||
volume_samples == integrator.volume_samples &&
|
||||
motion_blur == integrator.motion_blur &&
|
||||
sampling_pattern == integrator.sampling_pattern);
|
||||
sampling_pattern == integrator.sampling_pattern &&
|
||||
sample_all_lights_indirect == integrator.sample_all_lights_indirect);
|
||||
}
|
||||
|
||||
void Integrator::tag_update(Scene *scene)
|
||||
|
@ -63,6 +63,7 @@ public:
|
||||
int mesh_light_samples;
|
||||
int subsurface_samples;
|
||||
int volume_samples;
|
||||
bool sample_all_lights_indirect;
|
||||
|
||||
enum Method {
|
||||
BRANCHED_PATH = 0,
|
||||
|
Loading…
Reference in New Issue
Block a user