Cycles: make multiple importance sampling for lamps an option per lamp now,

disabled by default for backwards compatibility.
http://wiki.blender.org/index.php/Doc:2.6/Manual/Render/Cycles/Integrator
This commit is contained in:
Brecht Van Lommel
2013-01-30 15:57:15 +00:00
parent 4c971d5727
commit dc0f4b5618
9 changed files with 55 additions and 46 deletions

View File

@@ -462,8 +462,8 @@ class CyclesMaterialSettings(bpy.types.PropertyGroup):
type=cls, type=cls,
) )
cls.sample_as_light = BoolProperty( cls.sample_as_light = BoolProperty(
name="Sample as Lamp", name="Multiple Importance Sample",
description="Use direct light sampling for this material, " description="Use multiple importance sampling for this material, "
"disabling may reduce overall noise for large " "disabling may reduce overall noise for large "
"objects that emit little light compared to other light sources", "objects that emit little light compared to other light sources",
default=True, default=True,
@@ -499,6 +499,12 @@ class CyclesLampSettings(bpy.types.PropertyGroup):
min=1, max=10000, min=1, max=10000,
default=1, default=1,
) )
cls.use_multiple_importance_sampling = BoolProperty(
name="Multiple Importance Sample",
description="Use multiple importance sampling for the lamp, "
"reduces noise for area lamps and sharp glossy materials",
default=False,
)
@classmethod @classmethod
def unregister(cls): def unregister(cls):
@@ -514,8 +520,8 @@ class CyclesWorldSettings(bpy.types.PropertyGroup):
type=cls, type=cls,
) )
cls.sample_as_light = BoolProperty( cls.sample_as_light = BoolProperty(
name="Sample as Lamp", name="Multiple Importance Sample",
description="Use direct light sampling for the environment, " description="Use multiple importance sampling for the environment, "
"enabling for non-solid colors is recommended", "enabling for non-solid colors is recommended",
default=False, default=False,
) )

View File

@@ -574,6 +574,8 @@ class CyclesLamp_PT_lamp(CyclesButtonsPanel, Panel):
col = split.column() col = split.column()
col.prop(clamp, "cast_shadow") col.prop(clamp, "cast_shadow")
layout.prop(clamp, "use_multiple_importance_sampling")
if lamp.type == 'HEMI': if lamp.type == 'HEMI':
layout.label(text="Not supported, interpreted as sun lamp.") layout.label(text="Not supported, interpreted as sun lamp.")
@@ -807,9 +809,10 @@ class CyclesMaterial_PT_settings(CyclesButtonsPanel, Panel):
col.prop(mat, "diffuse_color", text="Viewport Color") col.prop(mat, "diffuse_color", text="Viewport Color")
col = split.column() col = split.column()
col.prop(cmat, "sample_as_light")
col.prop(mat, "pass_index") col.prop(mat, "pass_index")
layout.prop(cmat, "sample_as_light")
class CyclesTexture_PT_context(CyclesButtonsPanel, Panel): class CyclesTexture_PT_context(CyclesButtonsPanel, Panel):
bl_label = "" bl_label = ""

View File

@@ -156,6 +156,7 @@ void BlenderSync::sync_light(BL::Object b_parent, int persistent_id[OBJECT_PERSI
/* shadow */ /* shadow */
PointerRNA clamp = RNA_pointer_get(&b_lamp.ptr, "cycles"); PointerRNA clamp = RNA_pointer_get(&b_lamp.ptr, "cycles");
light->cast_shadow = get_boolean(clamp, "cast_shadow"); light->cast_shadow = get_boolean(clamp, "cast_shadow");
light->use_mis = get_boolean(clamp, "use_multiple_importance_sampling");
light->samples = get_int(clamp, "samples"); light->samples = get_int(clamp, "samples");
/* tag */ /* tag */

View File

@@ -93,7 +93,7 @@ __device bool direct_emission(KernelGlobals *kg, ShaderData *sd, int lindex,
} }
/* return lamp index for MIS */ /* return lamp index for MIS */
if(ls.use_mis) if(ls.shader & SHADER_USE_MIS)
*lamp = ls.lamp; *lamp = ls.lamp;
else else
*lamp= ~0; *lamp= ~0;
@@ -114,7 +114,7 @@ __device bool direct_emission(KernelGlobals *kg, ShaderData *sd, int lindex,
shader_bsdf_eval(kg, sd, ls.D, eval, &bsdf_pdf); shader_bsdf_eval(kg, sd, ls.D, eval, &bsdf_pdf);
if(ls.use_mis) { if(ls.shader & SHADER_USE_MIS) {
/* multiple importance sampling */ /* multiple importance sampling */
float mis_weight = power_heuristic(ls.pdf, bsdf_pdf); float mis_weight = power_heuristic(ls.pdf, bsdf_pdf);
light_eval *= mis_weight; light_eval *= mis_weight;

View File

@@ -31,7 +31,6 @@ typedef struct LightSample {
int prim; /* primitive id for triangle/curve ligths */ int prim; /* primitive id for triangle/curve ligths */
int shader; /* shader id */ int shader; /* shader id */
int lamp; /* lamp id */ int lamp; /* lamp id */
int use_mis; /* for lamps with size zero */
LightType type; /* type of light */ LightType type; /* type of light */
} LightSample; } LightSample;
@@ -218,11 +217,10 @@ __device void lamp_light_sample(KernelGlobals *kg, int lamp,
LightType type = (LightType)__float_as_int(data0.x); LightType type = (LightType)__float_as_int(data0.x);
ls->type = type; ls->type = type;
#ifdef __LAMP_MIS__ ls->shader = __float_as_int(data1.x);
ls->use_mis = true; ls->object = ~0;
#else ls->prim = ~0;
ls->use_mis = false; ls->lamp = lamp;
#endif
if(type == LIGHT_DISTANT) { if(type == LIGHT_DISTANT) {
/* distant light */ /* distant light */
@@ -233,10 +231,6 @@ __device void lamp_light_sample(KernelGlobals *kg, int lamp,
if(radius > 0.0f) if(radius > 0.0f)
D = distant_light_sample(D, radius, randu, randv); D = distant_light_sample(D, radius, randu, randv);
#ifdef __LAMP_MIS__
else
ls->use_mis = false;
#endif
ls->P = D; ls->P = D;
ls->Ng = D; ls->Ng = D;
@@ -257,9 +251,6 @@ __device void lamp_light_sample(KernelGlobals *kg, int lamp,
ls->D = -D; ls->D = -D;
ls->t = FLT_MAX; ls->t = FLT_MAX;
ls->eval_fac = 1.0f; ls->eval_fac = 1.0f;
#ifndef __LAMP_MIS__
ls->use_mis = true;
#endif
} }
#endif #endif
else { else {
@@ -271,10 +262,6 @@ __device void lamp_light_sample(KernelGlobals *kg, int lamp,
if(radius > 0.0f) if(radius > 0.0f)
/* sphere light */ /* sphere light */
ls->P += sphere_light_sample(P, ls->P, radius, randu, randv); ls->P += sphere_light_sample(P, ls->P, radius, randu, randv);
#ifdef __LAMP_MIS__
else
ls->use_mis = false;
#endif
ls->D = normalize_len(ls->P - P, &ls->t); ls->D = normalize_len(ls->P - P, &ls->t);
ls->Ng = -ls->D; ls->Ng = -ls->D;
@@ -304,13 +291,6 @@ __device void lamp_light_sample(KernelGlobals *kg, int lamp,
float invarea = data2.x; float invarea = data2.x;
if(invarea == 0.0f) {
#ifdef __LAMP_MIS__
ls->use_mis = false;
#endif
invarea = 1.0f;
}
ls->eval_fac = 0.25f*invarea; ls->eval_fac = 0.25f*invarea;
ls->pdf = invarea; ls->pdf = invarea;
} }
@@ -318,11 +298,6 @@ __device void lamp_light_sample(KernelGlobals *kg, int lamp,
ls->eval_fac *= kernel_data.integrator.inv_pdf_lights; ls->eval_fac *= kernel_data.integrator.inv_pdf_lights;
ls->pdf *= lamp_light_pdf(kg, ls->Ng, -ls->D, ls->t); ls->pdf *= lamp_light_pdf(kg, ls->Ng, -ls->D, ls->t);
} }
ls->shader = __float_as_int(data1.x);
ls->object = ~0;
ls->prim = ~0;
ls->lamp = lamp;
} }
__device bool lamp_light_eval(KernelGlobals *kg, int lamp, float3 P, float3 D, float t, LightSample *ls) __device bool lamp_light_eval(KernelGlobals *kg, int lamp, float3 P, float3 D, float t, LightSample *ls)
@@ -336,7 +311,6 @@ __device bool lamp_light_eval(KernelGlobals *kg, int lamp, float3 P, float3 D, f
ls->object = ~0; ls->object = ~0;
ls->prim = ~0; ls->prim = ~0;
ls->lamp = lamp; ls->lamp = lamp;
ls->use_mis = false; /* flag not used for eval */
if(type == LIGHT_DISTANT) { if(type == LIGHT_DISTANT) {
/* distant light */ /* distant light */
@@ -475,7 +449,7 @@ __device void triangle_light_sample(KernelGlobals *kg, int prim, int object,
ls->object = object; ls->object = object;
ls->prim = prim; ls->prim = prim;
ls->lamp = ~0; ls->lamp = ~0;
ls->use_mis = true; ls->shader |= SHADER_USE_MIS;
ls->t = 0.0f; ls->t = 0.0f;
ls->type = LIGHT_AREA; ls->type = LIGHT_AREA;
ls->eval_fac = 1.0f; ls->eval_fac = 1.0f;
@@ -529,11 +503,10 @@ __device void curve_segment_light_sample(KernelGlobals *kg, int prim, int object
ls->object = object; ls->object = object;
ls->prim = prim; ls->prim = prim;
ls->lamp = ~0; ls->lamp = ~0;
ls->use_mis = true;
ls->t = 0.0f; ls->t = 0.0f;
ls->type = LIGHT_STRAND; ls->type = LIGHT_STRAND;
ls->eval_fac = 1.0f; ls->eval_fac = 1.0f;
ls->shader = __float_as_int(v00.z); ls->shader = __float_as_int(v00.z) | SHADER_USE_MIS;
object_transform_light_sample(kg, ls, object, time); object_transform_light_sample(kg, ls, object, time);
} }

View File

@@ -254,7 +254,7 @@ __device float4 kernel_path_progressive(KernelGlobals *kg, RNG *rng, int sample,
bool hit = scene_intersect(kg, &ray, visibility, &isect); bool hit = scene_intersect(kg, &ray, visibility, &isect);
#ifdef __LAMP_MIS__ #ifdef __LAMP_MIS__
if(kernel_data.integrator.pdf_lights > 0.0f && !(state.flag & PATH_RAY_CAMERA)) { if(kernel_data.integrator.use_lamp_mis && !(state.flag & PATH_RAY_CAMERA)) {
/* ray starting from previous non-transparent bounce */ /* ray starting from previous non-transparent bounce */
Ray light_ray; Ray light_ray;
@@ -501,7 +501,7 @@ __device void kernel_path_indirect(KernelGlobals *kg, RNG *rng, int sample, Ray
bool hit = scene_intersect(kg, &ray, visibility, &isect); bool hit = scene_intersect(kg, &ray, visibility, &isect);
#ifdef __LAMP_MIS__ #ifdef __LAMP_MIS__
if(kernel_data.integrator.pdf_lights > 0.0f && !(state.flag & PATH_RAY_CAMERA)) { if(kernel_data.integrator.use_lamp_mis && !(state.flag & PATH_RAY_CAMERA)) {
/* ray starting from previous non-transparent bounce */ /* ray starting from previous non-transparent bounce */
Ray light_ray; Ray light_ray;

View File

@@ -288,8 +288,9 @@ typedef enum ShaderFlag {
SHADER_SMOOTH_NORMAL = (1 << 31), SHADER_SMOOTH_NORMAL = (1 << 31),
SHADER_CAST_SHADOW = (1 << 30), SHADER_CAST_SHADOW = (1 << 30),
SHADER_AREA_LIGHT = (1 << 29), SHADER_AREA_LIGHT = (1 << 29),
SHADER_USE_MIS = (1 << 28),
SHADER_MASK = ~(SHADER_SMOOTH_NORMAL|SHADER_CAST_SHADOW|SHADER_AREA_LIGHT) SHADER_MASK = ~(SHADER_SMOOTH_NORMAL|SHADER_CAST_SHADOW|SHADER_AREA_LIGHT|SHADER_USE_MIS)
} ShaderFlag; } ShaderFlag;
/* Light Type */ /* Light Type */
@@ -680,7 +681,7 @@ typedef struct KernelIntegrator {
int transmission_samples; int transmission_samples;
int ao_samples; int ao_samples;
int mesh_light_samples; int mesh_light_samples;
int pad1; int use_lamp_mis;
} KernelIntegrator; } KernelIntegrator;
typedef struct KernelBVH { typedef struct KernelBVH {

View File

@@ -115,6 +115,8 @@ Light::Light()
spot_smooth = 0.0f; spot_smooth = 0.0f;
cast_shadow = true; cast_shadow = true;
use_mis = false;
shader = 0; shader = 0;
samples = 1; samples = 1;
} }
@@ -291,13 +293,19 @@ void LightManager::device_update_distribution(Device *device, DeviceScene *dscen
/* point lights */ /* point lights */
float lightarea = (totarea > 0.0f)? totarea/scene->lights.size(): 1.0f; float lightarea = (totarea > 0.0f)? totarea/scene->lights.size(): 1.0f;
bool use_lamp_mis = false;
for(int i = 0; i < scene->lights.size(); i++, offset++) { for(int i = 0; i < scene->lights.size(); i++, offset++) {
Light *light = scene->lights[i];
distribution[offset].x = totarea; distribution[offset].x = totarea;
distribution[offset].y = __int_as_float(~(int)i); distribution[offset].y = __int_as_float(~(int)i);
distribution[offset].z = 1.0f; distribution[offset].z = 1.0f;
distribution[offset].w = scene->lights[i]->size; distribution[offset].w = light->size;
totarea += lightarea; totarea += lightarea;
if(light->size > 0.0f && light->use_mis)
use_lamp_mis = true;
} }
/* normalize cumulative distribution functions */ /* normalize cumulative distribution functions */
@@ -344,6 +352,8 @@ void LightManager::device_update_distribution(Device *device, DeviceScene *dscen
kintegrator->inv_pdf_lights = 1.0f/kintegrator->pdf_lights; kintegrator->inv_pdf_lights = 1.0f/kintegrator->pdf_lights;
} }
kintegrator->use_lamp_mis = use_lamp_mis;
/* CDF */ /* CDF */
device->tex_alloc("__light_distribution", dscene->light_distribution); device->tex_alloc("__light_distribution", dscene->light_distribution);
} }
@@ -355,6 +365,7 @@ void LightManager::device_update_distribution(Device *device, DeviceScene *dscen
kintegrator->pdf_triangles = 0.0f; kintegrator->pdf_triangles = 0.0f;
kintegrator->pdf_lights = 0.0f; kintegrator->pdf_lights = 0.0f;
kintegrator->inv_pdf_lights = 0.0f; kintegrator->inv_pdf_lights = 0.0f;
kintegrator->use_lamp_mis = false;
} }
} }
@@ -484,6 +495,9 @@ void LightManager::device_update_points(Device *device, DeviceScene *dscene, Sce
float radius = light->size; float radius = light->size;
float invarea = (radius > 0.0f)? 1.0f/(M_PI_F*radius*radius): 1.0f; float invarea = (radius > 0.0f)? 1.0f/(M_PI_F*radius*radius): 1.0f;
if(light->use_mis && radius > 0.0f)
shader_id |= SHADER_USE_MIS;
light_data[i*LIGHT_SIZE + 0] = make_float4(__int_as_float(light->type), co.x, co.y, co.z); light_data[i*LIGHT_SIZE + 0] = make_float4(__int_as_float(light->type), co.x, co.y, co.z);
light_data[i*LIGHT_SIZE + 1] = make_float4(__int_as_float(shader_id), radius, invarea, 0.0f); light_data[i*LIGHT_SIZE + 1] = make_float4(__int_as_float(shader_id), radius, invarea, 0.0f);
light_data[i*LIGHT_SIZE + 2] = make_float4(0.0f, 0.0f, 0.0f, 0.0f); light_data[i*LIGHT_SIZE + 2] = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
@@ -498,6 +512,9 @@ void LightManager::device_update_points(Device *device, DeviceScene *dscene, Sce
float area = M_PI_F*radius*radius; float area = M_PI_F*radius*radius;
float invarea = (area > 0.0f)? 1.0f/area: 1.0f; float invarea = (area > 0.0f)? 1.0f/area: 1.0f;
if(light->use_mis && area > 0.0f)
shader_id |= SHADER_USE_MIS;
light_data[i*LIGHT_SIZE + 0] = make_float4(__int_as_float(light->type), dir.x, dir.y, dir.z); light_data[i*LIGHT_SIZE + 0] = make_float4(__int_as_float(light->type), dir.x, dir.y, dir.z);
light_data[i*LIGHT_SIZE + 1] = make_float4(__int_as_float(shader_id), radius, cosangle, invarea); light_data[i*LIGHT_SIZE + 1] = make_float4(__int_as_float(shader_id), radius, cosangle, invarea);
light_data[i*LIGHT_SIZE + 2] = make_float4(0.0f, 0.0f, 0.0f, 0.0f); light_data[i*LIGHT_SIZE + 2] = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
@@ -505,6 +522,7 @@ void LightManager::device_update_points(Device *device, DeviceScene *dscene, Sce
} }
else if(light->type == LIGHT_BACKGROUND) { else if(light->type == LIGHT_BACKGROUND) {
shader_id &= ~SHADER_AREA_LIGHT; shader_id &= ~SHADER_AREA_LIGHT;
shader_id |= SHADER_USE_MIS;
light_data[i*LIGHT_SIZE + 0] = make_float4(__int_as_float(light->type), 0.0f, 0.0f, 0.0f); light_data[i*LIGHT_SIZE + 0] = make_float4(__int_as_float(light->type), 0.0f, 0.0f, 0.0f);
light_data[i*LIGHT_SIZE + 1] = make_float4(__int_as_float(shader_id), 0.0f, 0.0f, 0.0f); light_data[i*LIGHT_SIZE + 1] = make_float4(__int_as_float(shader_id), 0.0f, 0.0f, 0.0f);
@@ -515,7 +533,10 @@ void LightManager::device_update_points(Device *device, DeviceScene *dscene, Sce
float3 axisu = light->axisu*(light->sizeu*light->size); float3 axisu = light->axisu*(light->sizeu*light->size);
float3 axisv = light->axisv*(light->sizev*light->size); float3 axisv = light->axisv*(light->sizev*light->size);
float area = len(axisu)*len(axisv); float area = len(axisu)*len(axisv);
float invarea = (area > 0.0f)? 1.0f/area: 0.0f; float invarea = (area > 0.0f)? 1.0f/area: 1.0f;
if(light->use_mis && area > 0.0f)
shader_id |= SHADER_USE_MIS;
light_data[i*LIGHT_SIZE + 0] = make_float4(__int_as_float(light->type), co.x, co.y, co.z); light_data[i*LIGHT_SIZE + 0] = make_float4(__int_as_float(light->type), co.x, co.y, co.z);
light_data[i*LIGHT_SIZE + 1] = make_float4(__int_as_float(shader_id), axisu.x, axisu.y, axisu.z); light_data[i*LIGHT_SIZE + 1] = make_float4(__int_as_float(shader_id), axisu.x, axisu.y, axisu.z);
@@ -530,6 +551,9 @@ void LightManager::device_update_points(Device *device, DeviceScene *dscene, Sce
float spot_angle = cosf(light->spot_angle*0.5f); float spot_angle = cosf(light->spot_angle*0.5f);
float spot_smooth = (1.0f - spot_angle)*light->spot_smooth; float spot_smooth = (1.0f - spot_angle)*light->spot_smooth;
if(light->use_mis && radius > 0.0f)
shader_id |= SHADER_USE_MIS;
light_data[i*LIGHT_SIZE + 0] = make_float4(__int_as_float(light->type), co.x, co.y, co.z); light_data[i*LIGHT_SIZE + 0] = make_float4(__int_as_float(light->type), co.x, co.y, co.z);
light_data[i*LIGHT_SIZE + 1] = make_float4(__int_as_float(shader_id), radius, invarea, spot_angle); light_data[i*LIGHT_SIZE + 1] = make_float4(__int_as_float(shader_id), radius, invarea, spot_angle);
light_data[i*LIGHT_SIZE + 2] = make_float4(spot_smooth, dir.x, dir.y, dir.z); light_data[i*LIGHT_SIZE + 2] = make_float4(spot_smooth, dir.x, dir.y, dir.z);

View File

@@ -52,6 +52,7 @@ public:
float spot_smooth; float spot_smooth;
bool cast_shadow; bool cast_shadow;
bool use_mis;
int shader; int shader;
int samples; int samples;