Paste Code
Paste Blends
Paste Images
From 85d809edeb76988ea8ec4ee9e6d7e0668a267f87 Mon Sep 17 00:00:00 2001
From: Lukas Stockner <lukas.stockner@freenet.de>
Date: Sat, 7 Feb 2015 23:08:17 +0100
Subject: [PATCH] Cycles: Added support for light portals

---
intern/cycles/blender/addon/properties.py | 6 +
intern/cycles/blender/addon/ui.py | 2 +
intern/cycles/blender/blender_object.cpp | 49 ++--
intern/cycles/kernel/kernel_emission.h | 2 +-
intern/cycles/kernel/kernel_light.h | 405 +++++++++++++++++++-----------
intern/cycles/kernel/kernel_types.h | 5 +
intern/cycles/render/light.cpp | 149 +++++++----
intern/cycles/render/light.h | 2 +
8 files changed, 401 insertions(+), 219 deletions(-)

diff --git a/intern/cycles/blender/addon/properties.py b/intern/cycles/blender/addon/properties.py
index 4b84146..d7bbec2 100644
--- a/intern/cycles/blender/addon/properties.py
+++ b/intern/cycles/blender/addon/properties.py
@@ -693,6 +693,12 @@ class CyclesLampSettings(bpy.types.PropertyGroup):
"reduces noise for area lamps and sharp glossy materials",
default=False,
)
+ cls.is_portal = BoolProperty(
+ name="Is Portal",
+ description="Uses this area lamp to guide sampling of the background, "
+ "note that this will make the lamp invisible",
+ default=False,
+ )

@classmethod
def unregister(cls):
diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py
index 651114a..ad5bf94 100644
--- a/intern/cycles/blender/addon/ui.py
+++ b/intern/cycles/blender/addon/ui.py
@@ -734,6 +734,8 @@ class CyclesLamp_PT_lamp(CyclesButtonsPanel, Panel):
col = split.column()
col.prop(clamp, "cast_shadow")
col.prop(clamp, "use_multiple_importance_sampling", text="Multiple Importance")
+ if lamp.type == 'AREA':
+ col.prop(clamp, "is_portal")

if lamp.type == 'HEMI':
layout.label(text="Not supported, interpreted as sun lamp")
diff --git a/intern/cycles/blender/blender_object.cpp b/intern/cycles/blender/blender_object.cpp
index e827d46..abdec9d 100644
--- a/intern/cycles/blender/blender_object.cpp
+++ b/intern/cycles/blender/blender_object.cpp
@@ -171,6 +171,11 @@ void BlenderSync::sync_light(BL::Object b_parent, int persistent_id[OBJECT_PERSI

light->max_bounces = get_int(clamp, "max_bounces");

+ if(light->type == LIGHT_AREA)
+ light->portal = get_boolean(clamp, "is_portal");
+ else
+ light->portal = false;
+
/* visibility */
uint visibility = object_ray_visibility(b_ob);
light->use_diffuse = (visibility & PATH_RAY_DIFFUSE) != 0;
@@ -189,30 +194,28 @@ void BlenderSync::sync_background_light()
if(b_world) {
PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
PointerRNA cworld = RNA_pointer_get(&b_world.ptr, "cycles");
- bool sample_as_light = get_boolean(cworld, "sample_as_light");
-
- if(sample_as_light) {
- /* test if we need to sync */
- Light *light;
- ObjectKey key(b_world, 0, b_world);
-
- if(light_map.sync(&light, b_world, b_world, key) ||
- world_recalc ||
- b_world.ptr.data != world_map)
- {
- light->type = LIGHT_BACKGROUND;
- light->map_resolution = get_int(cworld, "sample_map_resolution");
- light->shader = scene->default_background;
+
+ /* test if we need to sync */
+ Light *light;
+ ObjectKey key(b_world, 0, b_world);
+
+ if(light_map.sync(&light, b_world, b_world, key) ||
+ world_recalc ||
+ b_world.ptr.data != world_map)
+ {
+ light->type = LIGHT_BACKGROUND;
+ light->map_resolution = get_int(cworld, "sample_map_resolution");
+ light->shader = scene->default_background;
+ light->use_mis = get_boolean(cworld, "sample_as_light");

- int samples = get_int(cworld, "samples");
- if(get_boolean(cscene, "use_square_samples"))
- light->samples = samples * samples;
- else
- light->samples = samples;
-
- light->tag_update(scene);
- light_map.set_recalc(b_world);
- }
+ int samples = get_int(cworld, "samples");
+ if(get_boolean(cscene, "use_square_samples"))
+ light->samples = samples * samples;
+ else
+ light->samples = samples;
+
+ light->tag_update(scene);
+ light_map.set_recalc(b_world);
}
}

diff --git a/intern/cycles/kernel/kernel_emission.h b/intern/cycles/kernel/kernel_emission.h
index 7523105..d75e48f 100644
--- a/intern/cycles/kernel/kernel_emission.h
+++ b/intern/cycles/kernel/kernel_emission.h
@@ -252,7 +252,7 @@ ccl_device_noinline float3 indirect_background(KernelGlobals *kg, PathState *sta
if(!(state->flag & PATH_RAY_MIS_SKIP) && res) {
/* multiple importance sampling, get background light pdf for ray
* direction, and compute weight with respect to BSDF pdf */
- float pdf = background_light_pdf(kg, ray->D);
+ float pdf = background_light_pdf(kg, ray->P, ray->D);
float mis_weight = power_heuristic(state->ray_pdf, pdf);

return L*mis_weight;
diff --git a/intern/cycles/kernel/kernel_light.h b/intern/cycles/kernel/kernel_light.h
index 41920e4..55437a7 100644
--- a/intern/cycles/kernel/kernel_light.h
+++ b/intern/cycles/kernel/kernel_light.h
@@ -33,156 +33,24 @@ typedef struct LightSample {
LightType type; /* type of light */
} LightSample;

-/* Background Light */
-
-#ifdef __BACKGROUND_MIS__
-
-ccl_device float3 background_light_sample(KernelGlobals *kg, float randu, float randv, float *pdf)
-{
- /* for the following, the CDF values are actually a pair of floats, with the
- * function value as X and the actual CDF as Y. The last entry's function
- * value is the CDF total. */
- int res = kernel_data.integrator.pdf_background_res;
- int cdf_count = res + 1;
-
- /* this is basically std::lower_bound as used by pbrt */
- int first = 0;
- int count = res;
-
- while(count > 0) {
- int step = count >> 1;
- int middle = first + step;
-
- if(kernel_tex_fetch(__light_background_marginal_cdf, middle).y < randv) {
- first = middle + 1;
- count -= step + 1;
- }
- else
- count = step;
- }
-
- int index_v = max(0, first - 1);
- kernel_assert(index_v >= 0 && index_v < res);
-
- float2 cdf_v = kernel_tex_fetch(__light_background_marginal_cdf, index_v);
- float2 cdf_next_v = kernel_tex_fetch(__light_background_marginal_cdf, index_v + 1);
- float2 cdf_last_v = kernel_tex_fetch(__light_background_marginal_cdf, res);
-
- /* importance-sampled V direction */
- float dv = (randv - cdf_v.y) / (cdf_next_v.y - cdf_v.y);
- float v = (index_v + dv) / res;
-
- /* this is basically std::lower_bound as used by pbrt */
- first = 0;
- count = res;
- while(count > 0) {
- int step = count >> 1;
- int middle = first + step;
-
- if(kernel_tex_fetch(__light_background_conditional_cdf, index_v * cdf_count + middle).y < randu) {
- first = middle + 1;
- count -= step + 1;
- }
- else
- count = step;
- }
-
- int index_u = max(0, first - 1);
- kernel_assert(index_u >= 0 && index_u < res);
-
- float2 cdf_u = kernel_tex_fetch(__light_background_conditional_cdf, index_v * cdf_count + index_u);
- float2 cdf_next_u = kernel_tex_fetch(__light_background_conditional_cdf, index_v * cdf_count + index_u + 1);
- float2 cdf_last_u = kernel_tex_fetch(__light_background_conditional_cdf, index_v * cdf_count + res);
-
- /* importance-sampled U direction */
- float du = (randu - cdf_u.y) / (cdf_next_u.y - cdf_u.y);
- float u = (index_u + du) / res;
-
- /* compute pdf */
- float denom = cdf_last_u.x * cdf_last_v.x;
- float sin_theta = sinf(M_PI_F * v);
-
- if(sin_theta == 0.0f || denom == 0.0f)
- *pdf = 0.0f;
- else
- *pdf = (cdf_u.x * cdf_v.x)/(M_2PI_F * M_PI_F * sin_theta * denom);
-
- *pdf *= kernel_data.integrator.pdf_lights;
-
- /* compute direction */
- return -equirectangular_to_direction(u, v);
-}
-
-ccl_device float background_light_pdf(KernelGlobals *kg, float3 direction)
-{
- float2 uv = direction_to_equirectangular(direction);
- int res = kernel_data.integrator.pdf_background_res;
-
- float sin_theta = sinf(uv.y * M_PI_F);
-
- if(sin_theta == 0.0f)
- return 0.0f;
-
- int index_u = clamp(float_to_int(uv.x * res), 0, res - 1);
- int index_v = clamp(float_to_int(uv.y * res), 0, res - 1);
-
- /* pdfs in V direction */
- float2 cdf_last_u = kernel_tex_fetch(__light_background_conditional_cdf, index_v * (res + 1) + res);
- float2 cdf_last_v = kernel_tex_fetch(__light_background_marginal_cdf, res);
-
- float denom = cdf_last_u.x * cdf_last_v.x;
-
- if(denom == 0.0f)
- return 0.0f;
-
- /* pdfs in U direction */
- float2 cdf_u = kernel_tex_fetch(__light_background_conditional_cdf, index_v * (res + 1) + index_u);
- float2 cdf_v = kernel_tex_fetch(__light_background_marginal_cdf, index_v);
-
- float pdf = (cdf_u.x * cdf_v.x)/(M_2PI_F * M_PI_F * sin_theta * denom);
-
- return pdf * kernel_data.integrator.pdf_lights;
-}
-#endif
-
-/* Regular Light */
-
-ccl_device float3 disk_light_sample(float3 v, float randu, float randv)
-{
- float3 ru, rv;
-
- make_orthonormals(v, &ru, &rv);
- to_unit_disk(&randu, &randv);
-
- return ru*randu + rv*randv;
-}
-
-ccl_device float3 distant_light_sample(float3 D, float radius, float randu, float randv)
-{
- return normalize(D + disk_light_sample(D, randu, randv)*radius);
-}
-
-ccl_device float3 sphere_light_sample(float3 P, float3 center, float radius, float randu, float randv)
-{
- return disk_light_sample(normalize(P - center), randu, randv)*radius;
-}
+/* Area light sampling */

/* Uses the following paper:
- *
- * Carlos Urena et al.
- * An Area-Preserving Parametrization for Spherical Rectangles.
- *
- * https://www.solidangle.com/research/egsr2013_spherical_rectangle.pdf
- */
+*
+* Carlos Urena et al.
+* An Area-Preserving Parametrization for Spherical Rectangles.
+*
+* https://www.solidangle.com/research/egsr2013_spherical_rectangle.pdf
+*/
ccl_device float3 area_light_sample(float3 P,
- float3 light_p,
- float3 axisu, float3 axisv,
- float randu, float randv,
- float *pdf)
+ float3 light_p,
+ float3 axisu, float3 axisv,
+ float randu, float randv,
+ float *pdf)
{
/* In our name system we're using P for the center,
- * which is o in the paper.
- */
+ * which is o in the paper.
+ */

float3 corner = light_p - axisu * 0.5f - axisv * 0.5f;
float axisu_len, axisv_len;
@@ -253,15 +121,15 @@ ccl_device float3 area_light_sample(float3 P,
}

/* TODO(sergey): This is actually a duplicated code from above, but how to avoid
- * this without having some nasty function with loads of parameters?
- */
+* this without having some nasty function with loads of parameters?
+*/
ccl_device float area_light_pdf(float3 P,
- float3 light_p,
- float3 axisu, float3 axisv)
+ float3 light_p,
+ float3 axisu, float3 axisv)
{
/* In our name system we're using P for the center,
- * which is o in the paper.
- */
+ * which is o in the paper.
+ */

float3 corner = light_p - axisu * 0.5f - axisv * 0.5f;
float axisu_len, axisv_len;
@@ -306,6 +174,239 @@ ccl_device float area_light_pdf(float3 P,
return 0.0f;
}

+/* Background Light */
+
+#ifdef __BACKGROUND_MIS__
+
+ccl_device float3 background_sample_cdf(KernelGlobals *kg, float randu, float randv, float *pdf) {
+ /* for the following, the CDF values are actually a pair of floats, with the
+ * function value as X and the actual CDF as Y. The last entry's function
+ * value is the CDF total. */
+ int res = kernel_data.integrator.pdf_background_res;
+ int cdf_count = res + 1;
+
+ /* this is basically std::lower_bound as used by pbrt */
+ int first = 0;
+ int count = res;
+
+ while (count > 0) {
+ int step = count >> 1;
+ int middle = first + step;
+
+ if (kernel_tex_fetch(__light_background_marginal_cdf, middle).y < randv) {
+ first = middle + 1;
+ count -= step + 1;
+ }
+ else
+ count = step;
+ }
+
+ int index_v = max(0, first - 1);
+ kernel_assert(index_v >= 0 && index_v < res);
+
+ float2 cdf_v = kernel_tex_fetch(__light_background_marginal_cdf, index_v);
+ float2 cdf_next_v = kernel_tex_fetch(__light_background_marginal_cdf, index_v + 1);
+ float2 cdf_last_v = kernel_tex_fetch(__light_background_marginal_cdf, res);
+
+ /* importance-sampled V direction */
+ float dv = (randv - cdf_v.y) / (cdf_next_v.y - cdf_v.y);
+ float v = (index_v + dv) / res;
+
+ /* this is basically std::lower_bound as used by pbrt */
+ first = 0;
+ count = res;
+ while (count > 0) {
+ int step = count >> 1;
+ int middle = first + step;
+
+ if (kernel_tex_fetch(__light_background_conditional_cdf, index_v * cdf_count + middle).y < randu) {
+ first = middle + 1;
+ count -= step + 1;
+ }
+ else
+ count = step;
+ }
+
+ int index_u = max(0, first - 1);
+ kernel_assert(index_u >= 0 && index_u < res);
+
+ float2 cdf_u = kernel_tex_fetch(__light_background_conditional_cdf, index_v * cdf_count + index_u);
+ float2 cdf_next_u = kernel_tex_fetch(__light_background_conditional_cdf, index_v * cdf_count + index_u + 1);
+ float2 cdf_last_u = kernel_tex_fetch(__light_background_conditional_cdf, index_v * cdf_count + res);
+
+ /* importance-sampled U direction */
+ float du = (randu - cdf_u.y) / (cdf_next_u.y - cdf_u.y);
+ float u = (index_u + du) / res;
+
+ /* compute pdf */
+ float denom = cdf_last_u.x * cdf_last_v.x;
+ float sin_theta = sinf(M_PI_F * v);
+
+ if (sin_theta == 0.0f || denom == 0.0f)
+ *pdf = 0.0f;
+ else
+ *pdf = (cdf_u.x * cdf_v.x) / (M_2PI_F * M_PI_F * sin_theta * denom);
+
+ *pdf *= kernel_data.integrator.pdf_lights;
+
+ /* compute direction */
+ return equirectangular_to_direction(u, v);
+}
+
+ccl_device float background_pdf_cdf(KernelGlobals *kg, float3 direction) {
+ float2 uv = direction_to_equirectangular(direction);
+ int res = kernel_data.integrator.pdf_background_res;
+
+ float sin_theta = sinf(uv.y * M_PI_F);
+
+ if(sin_theta == 0.0f)
+ return 0.0f;
+
+ int index_u = clamp(float_to_int(uv.x * res), 0, res - 1);
+ int index_v = clamp(float_to_int(uv.y * res), 0, res - 1);
+
+ /* pdfs in V direction */
+ float2 cdf_last_u = kernel_tex_fetch(__light_background_conditional_cdf, index_v * (res + 1) + res);
+ float2 cdf_last_v = kernel_tex_fetch(__light_background_marginal_cdf, res);
+
+ float denom = cdf_last_u.x * cdf_last_v.x;
+
+ if(denom == 0.0f)
+ return 0.0f;
+
+ /* pdfs in U direction */
+ float2 cdf_u = kernel_tex_fetch(__light_background_conditional_cdf, index_v * (res + 1) + index_u);
+ float2 cdf_v = kernel_tex_fetch(__light_background_marginal_cdf, index_v);
+
+ return (cdf_u.x * cdf_v.x)/(M_2PI_F * M_PI_F * sin_theta * denom) * kernel_data.integrator.pdf_lights;
+}
+
+ccl_device float3 background_sample_portal(KernelGlobals *kg, float3 P, float randu, float randv, float *pdf) {
+ randv *= kernel_data.integrator.num_portals;
+ int portal = (int)randv;
+ randv -= portal;
+
+ portal += kernel_data.integrator.portal_offset;
+
+ float4 data0 = kernel_tex_fetch(__light_data, portal*LIGHT_SIZE + 0);
+ float4 data1 = kernel_tex_fetch(__light_data, portal*LIGHT_SIZE + 1);
+ float4 data2 = kernel_tex_fetch(__light_data, portal*LIGHT_SIZE + 2);
+
+ float3 lightpos = make_float3(data0.y, data0.z, data0.w);
+ float3 axisu = make_float3(data1.y, data1.z, data1.w);
+ float3 axisv = make_float3(data2.y, data2.z, data2.w);
+
+ float3 lightPoint = area_light_sample(P, lightpos,
+ axisu, axisv,
+ randu, randv,
+ pdf);
+
+ *pdf /= kernel_data.integrator.num_portals;
+
+ return normalize(lightPoint - P);
+}
+
+ccl_device float background_pdf_portal(KernelGlobals *kg, float3 P, float3 direction) {
+ float portal_pdf = 0.0f;
+ for (int p = 0; p < kernel_data.integrator.num_portals; p++) {
+ float4 data0 = kernel_tex_fetch(__light_data, (p + kernel_data.integrator.portal_offset)*LIGHT_SIZE + 0);
+ float4 data1 = kernel_tex_fetch(__light_data, (p + kernel_data.integrator.portal_offset)*LIGHT_SIZE + 1);
+ float4 data2 = kernel_tex_fetch(__light_data, (p + kernel_data.integrator.portal_offset)*LIGHT_SIZE + 2);
+ float4 data3 = kernel_tex_fetch(__light_data, (p + kernel_data.integrator.portal_offset)*LIGHT_SIZE + 3);
+
+ float3 lightpos = make_float3(data0.y, data0.z, data0.w);
+ float3 axisu = make_float3(data1.y, data1.z, data1.w);
+ float3 axisv = make_float3(data2.y, data2.z, data2.w);
+ float3 dir = make_float3(data3.y, data3.z, data3.w);
+
+ //Hits portal?
+ float t = -(dot(P, dir) - dot(lightpos, dir)) / dot(direction, dir);
+ if (t <= 0) continue;
+ float3 hit = P + t*direction;
+ float3 inplane = hit - lightpos;
+ if (fabsf(dot(inplane, axisu) / dot(axisu, axisu)) > 1.0f) continue;
+ if (fabsf(dot(inplane, axisv) / dot(axisv, axisv)) > 1.0f) continue;
+
+ portal_pdf += area_light_pdf(P, lightpos, axisu, axisv);
+ }
+ return portal_pdf / kernel_data.integrator.num_portals;
+}
+
+ccl_device float3 background_light_sample(KernelGlobals *kg, float3 P, float randu, float randv, float *pdf)
+{
+ bool sample_portal;
+ if (kernel_data.integrator.portal_pdf == 0.0f)
+ sample_portal = false;
+ else if (kernel_data.integrator.portal_pdf == 1.0f)
+ sample_portal = true;
+ else {
+ if (randu < kernel_data.integrator.portal_pdf) {
+ sample_portal = true;
+ randu /= kernel_data.integrator.portal_pdf;
+ }
+ else {
+ sample_portal = false;
+ randu = (randu - kernel_data.integrator.portal_pdf) / (1.0f - kernel_data.integrator.portal_pdf);
+ }
+ }
+
+ if (sample_portal) {
+ float3 D = background_sample_portal(kg, P, randu, randv, pdf);
+
+ /* Could the CDF be sampled? If yes, use MIS! */
+ if (kernel_data.integrator.portal_pdf < 1.0f) {
+ float cdf_pdf = background_pdf_cdf(kg, D);
+ *pdf = (kernel_data.integrator.portal_pdf * (*pdf) + (1.0f - kernel_data.integrator.portal_pdf) * cdf_pdf);
+ }
+ return D;
+ }
+ else {
+ float3 D = background_sample_cdf(kg, randu, randv, pdf);
+ /* Could light portals be sampled? If yes, use MIS! */
+ if (kernel_data.integrator.portal_pdf > 0.0f) {
+ float portal_pdf = background_pdf_portal(kg, P, D);
+ *pdf = (kernel_data.integrator.portal_pdf * portal_pdf + (1.0f - kernel_data.integrator.portal_pdf) * (*pdf));
+ }
+ return D;
+ }
+}
+
+ccl_device float background_light_pdf(KernelGlobals *kg, float3 P, float3 direction)
+{
+ /* Only CDF? */
+ if (kernel_data.integrator.portal_pdf == 0.0f) return background_pdf_cdf(kg, direction);
+
+ /* Only Portal? */
+ if (kernel_data.integrator.portal_pdf == 1.0f) return background_pdf_portal(kg, P, direction);
+
+ /* Both, so combine them by MIS */
+ return background_pdf_cdf(kg, direction) * (1.0f - kernel_data.integrator.portal_pdf)
+ + background_pdf_portal(kg, P, direction) * kernel_data.integrator.portal_pdf;
+}
+#endif
+
+/* Regular Light */
+
+ccl_device float3 disk_light_sample(float3 v, float randu, float randv)
+{
+ float3 ru, rv;
+
+ make_orthonormals(v, &ru, &rv);
+ to_unit_disk(&randu, &randv);
+
+ return ru*randu + rv*randv;
+}
+
+ccl_device float3 distant_light_sample(float3 D, float radius, float randu, float randv)
+{
+ return normalize(D + disk_light_sample(D, randu, randv)*radius);
+}
+
+ccl_device float3 sphere_light_sample(float3 P, float3 center, float radius, float randu, float randv)
+{
+ return disk_light_sample(normalize(P - center), randu, randv)*radius;
+}
+
ccl_device float spot_light_attenuation(float4 data1, float4 data2, LightSample *ls)
{
float3 dir = make_float3(data2.y, data2.z, data2.w);
@@ -376,7 +477,7 @@ ccl_device void lamp_light_sample(KernelGlobals *kg, int lamp,
#ifdef __BACKGROUND_MIS__
else if(type == LIGHT_BACKGROUND) {
/* infinite area light (e.g. light dome or env light) */
- float3 D = background_light_sample(kg, randu, randv, &ls->pdf);
+ float3 D = -background_light_sample(kg, P, randu, randv, &ls->pdf);

ls->P = D;
ls->Ng = D;
diff --git a/intern/cycles/kernel/kernel_types.h b/intern/cycles/kernel/kernel_types.h
index 77d3ea8..cc1512c 100644
--- a/intern/cycles/kernel/kernel_types.h
+++ b/intern/cycles/kernel/kernel_types.h
@@ -895,6 +895,11 @@ typedef struct KernelIntegrator {
float inv_pdf_lights;
int pdf_background_res;

+ /* light portals */
+ float portal_pdf;
+ int num_portals;
+ int portal_offset;
+
/* bounces */
int min_bounce;
int max_bounce;
diff --git a/intern/cycles/render/light.cpp b/intern/cycles/render/light.cpp
index ca6853e..b8ac51b 100644
--- a/intern/cycles/render/light.cpp
+++ b/intern/cycles/render/light.cpp
@@ -126,6 +126,8 @@ Light::Light()
shader = 0;
samples = 1;
max_bounces = 1024;
+
+ portal = false;
}

void Light::tag_update(Scene *scene)
@@ -150,10 +152,16 @@ void LightManager::device_update_distribution(Device *device, DeviceScene *dscen
progress.set_status("Updating Lights", "Computing distribution");

/* count */
- size_t num_lights = scene->lights.size();
+ size_t num_lights = 0;
size_t num_background_lights = 0;
+ bool background_mis = false;
size_t num_triangles = 0;

+ foreach(Light *light, scene->lights) {
+ if (!light->portal)
+ num_lights++;
+ }
+
foreach(Object *object, scene->objects) {
Mesh *mesh = object->mesh;
bool have_emission = false;
@@ -284,22 +292,28 @@ void LightManager::device_update_distribution(Device *device, DeviceScene *dscen
float trianglearea = totarea;

/* point lights */
- float lightarea = (totarea > 0.0f)? totarea/scene->lights.size(): 1.0f;
+ float lightarea = (totarea > 0.0f) ? totarea / num_lights : 1.0f;
bool use_lamp_mis = false;

- for(int i = 0; i < scene->lights.size(); i++, offset++) {
- Light *light = scene->lights[i];
+ int pos = 0;
+ foreach(Light *light, scene->lights) {
+ if (light->portal) continue;

distribution[offset].x = totarea;
- distribution[offset].y = __int_as_float(~(int)i);
+ distribution[offset].y = __int_as_float(~(int)pos);
distribution[offset].z = 1.0f;
distribution[offset].w = light->size;
totarea += lightarea;

if(light->size > 0.0f && light->use_mis)
use_lamp_mis = true;
- if(light->type == LIGHT_BACKGROUND)
+ if (light->type == LIGHT_BACKGROUND) {
num_background_lights++;
+ background_mis = light->use_mis;
+ }
+
+ pos++;
+ offset++;
}

/* normalize cumulative distribution functions */
@@ -361,6 +375,17 @@ void LightManager::device_update_distribution(Device *device, DeviceScene *dscen

/* CDF */
device->tex_alloc("__light_distribution", dscene->light_distribution);
+
+ if (num_background_lights > 0 && pos != scene->lights.size()) {
+ kintegrator->portal_offset = pos;
+ kintegrator->num_portals = scene->lights.size() - pos;
+ kintegrator->portal_pdf = background_mis? 0.5f: 1.0f;
+ }
+ else {
+ kintegrator->num_portals = 0;
+ kintegrator->portal_offset = 0;
+ kintegrator->portal_pdf = 0.0f;
+ }
}
else {
dscene->light_distribution.clear();
@@ -372,6 +397,9 @@ void LightManager::device_update_distribution(Device *device, DeviceScene *dscen
kintegrator->inv_pdf_lights = 0.0f;
kintegrator->use_lamp_mis = false;
kfilm->pass_shadow_scale = 1.0f;
+ kintegrator->num_portals = 0;
+ kintegrator->portal_offset = 0;
+ kintegrator->portal_pdf = 0.0f;
}
}

@@ -470,25 +498,34 @@ void LightManager::device_update_background(Device *device, DeviceScene *dscene,

void LightManager::device_update_points(Device *device, DeviceScene *dscene, Scene *scene)
{
+ bool has_portals = false;
+ foreach(Light *light, scene->lights) {
+ if (light->portal) {
+ has_portals = true;
+ break;
+ }
+ }
+
+ /* remove background light? */
+ foreach(Light *light, scene->lights) {
+ if (light->type != LIGHT_BACKGROUND) continue;
+ if (!(device->info.advanced_shading && (has_portals || light->use_mis)))
+ scene->lights.erase(std::remove(scene->lights.begin(), scene->lights.end(), light), scene->lights.end());
+ break;
+ }
+
if(scene->lights.size() == 0)
return;

float4 *light_data = dscene->light_data.resize(scene->lights.size()*LIGHT_SIZE);

- if(!device->info.advanced_shading) {
- /* remove unsupported light */
- foreach(Light *light, scene->lights) {
- if(light->type == LIGHT_BACKGROUND) {
- scene->lights.erase(std::remove(scene->lights.begin(), scene->lights.end(), light), scene->lights.end());
- break;
- }
- }
- }
+ int pos = 0;
+
+ foreach(Light *light, scene->lights) {
+ if (light->portal) continue;

- for(size_t i = 0; i < scene->lights.size(); i++) {
- Light *light = scene->lights[i];
float3 co = light->co;
- int shader_id = scene->shader_manager->get_shader_id(scene->lights[i]->shader);
+ int shader_id = scene->shader_manager->get_shader_id(light->shader);
float samples = __int_as_float(light->samples);
float max_bounces = __int_as_float(light->max_bounces);

@@ -521,11 +558,11 @@ void LightManager::device_update_points(Device *device, DeviceScene *dscene, Sce
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 + 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 + 3] = make_float4(samples, 0.0f, 0.0f, 0.0f);
- light_data[i*LIGHT_SIZE + 4] = make_float4(max_bounces, 0.0f, 0.0f, 0.0f);
+ light_data[pos*LIGHT_SIZE + 0] = make_float4(__int_as_float(light->type), co.x, co.y, co.z);
+ light_data[pos*LIGHT_SIZE + 1] = make_float4(__int_as_float(shader_id), radius, invarea, 0.0f);
+ light_data[pos*LIGHT_SIZE + 2] = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ light_data[pos*LIGHT_SIZE + 3] = make_float4(samples, 0.0f, 0.0f, 0.0f);
+ light_data[pos*LIGHT_SIZE + 4] = make_float4(max_bounces, 0.0f, 0.0f, 0.0f);
}
else if(light->type == LIGHT_DISTANT) {
shader_id &= ~SHADER_AREA_LIGHT;
@@ -542,11 +579,11 @@ void LightManager::device_update_points(Device *device, DeviceScene *dscene, Sce
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 + 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 + 3] = make_float4(samples, 0.0f, 0.0f, 0.0f);
- light_data[i*LIGHT_SIZE + 4] = make_float4(max_bounces, 0.0f, 0.0f, 0.0f);
+ light_data[pos*LIGHT_SIZE + 0] = make_float4(__int_as_float(light->type), dir.x, dir.y, dir.z);
+ light_data[pos*LIGHT_SIZE + 1] = make_float4(__int_as_float(shader_id), radius, cosangle, invarea);
+ light_data[pos*LIGHT_SIZE + 2] = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ light_data[pos*LIGHT_SIZE + 3] = make_float4(samples, 0.0f, 0.0f, 0.0f);
+ light_data[pos*LIGHT_SIZE + 4] = make_float4(max_bounces, 0.0f, 0.0f, 0.0f);
}
else if(light->type == LIGHT_BACKGROUND) {
uint visibility = scene->background->visibility;
@@ -571,11 +608,11 @@ void LightManager::device_update_points(Device *device, DeviceScene *dscene, Sce
use_light_visibility = true;
}

- 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 + 2] = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
- light_data[i*LIGHT_SIZE + 3] = make_float4(samples, 0.0f, 0.0f, 0.0f);
- light_data[i*LIGHT_SIZE + 4] = make_float4(max_bounces, 0.0f, 0.0f, 0.0f);
+ light_data[pos*LIGHT_SIZE + 0] = make_float4(__int_as_float(light->type), 0.0f, 0.0f, 0.0f);
+ light_data[pos*LIGHT_SIZE + 1] = make_float4(__int_as_float(shader_id), 0.0f, 0.0f, 0.0f);
+ light_data[pos*LIGHT_SIZE + 2] = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ light_data[pos*LIGHT_SIZE + 3] = make_float4(samples, 0.0f, 0.0f, 0.0f);
+ light_data[pos*LIGHT_SIZE + 4] = make_float4(max_bounces, 0.0f, 0.0f, 0.0f);
}
else if(light->type == LIGHT_AREA) {
float3 axisu = light->axisu*(light->sizeu*light->size);
@@ -589,11 +626,11 @@ void LightManager::device_update_points(Device *device, DeviceScene *dscene, Sce
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 + 1] = make_float4(__int_as_float(shader_id), axisu.x, axisu.y, axisu.z);
- light_data[i*LIGHT_SIZE + 2] = make_float4(invarea, axisv.x, axisv.y, axisv.z);
- light_data[i*LIGHT_SIZE + 3] = make_float4(samples, dir.x, dir.y, dir.z);
- light_data[i*LIGHT_SIZE + 4] = make_float4(max_bounces, 0.0f, 0.0f, 0.0f);
+ light_data[pos*LIGHT_SIZE + 0] = make_float4(__int_as_float(light->type), co.x, co.y, co.z);
+ light_data[pos*LIGHT_SIZE + 1] = make_float4(__int_as_float(shader_id), axisu.x, axisu.y, axisu.z);
+ light_data[pos*LIGHT_SIZE + 2] = make_float4(invarea, axisv.x, axisv.y, axisv.z);
+ light_data[pos*LIGHT_SIZE + 3] = make_float4(samples, dir.x, dir.y, dir.z);
+ light_data[pos*LIGHT_SIZE + 4] = make_float4(max_bounces, 0.0f, 0.0f, 0.0f);
}
else if(light->type == LIGHT_SPOT) {
shader_id &= ~SHADER_AREA_LIGHT;
@@ -609,13 +646,39 @@ void LightManager::device_update_points(Device *device, DeviceScene *dscene, Sce
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 + 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 + 3] = make_float4(samples, 0.0f, 0.0f, 0.0f);
- light_data[i*LIGHT_SIZE + 4] = make_float4(max_bounces, 0.0f, 0.0f, 0.0f);
+ light_data[pos*LIGHT_SIZE + 0] = make_float4(__int_as_float(light->type), co.x, co.y, co.z);
+ light_data[pos*LIGHT_SIZE + 1] = make_float4(__int_as_float(shader_id), radius, invarea, spot_angle);
+ light_data[pos*LIGHT_SIZE + 2] = make_float4(spot_smooth, dir.x, dir.y, dir.z);
+ light_data[pos*LIGHT_SIZE + 3] = make_float4(samples, 0.0f, 0.0f, 0.0f);
+ light_data[pos*LIGHT_SIZE + 4] = make_float4(max_bounces, 0.0f, 0.0f, 0.0f);
}
+
+ pos++;
}
+
+ foreach(Light *light, scene->lights) {
+ if (!light->portal) continue;
+ assert(light->type == LIGHT_AREA);
+
+ float3 co = light->co;
+ float3 axisu = light->axisu*(light->sizeu*light->size);
+ float3 axisv = light->axisv*(light->sizev*light->size);
+ float area = len(axisu)*len(axisv);
+ float invarea = (area > 0.0f) ? 1.0f / area : 1.0f;
+ float3 dir = light->dir;
+
+ dir = safe_normalize(dir);
+
+ light_data[pos*LIGHT_SIZE + 0] = make_float4(__int_as_float(light->type), co.x, co.y, co.z);
+ light_data[pos*LIGHT_SIZE + 1] = make_float4(area, axisu.x, axisu.y, axisu.z);
+ light_data[pos*LIGHT_SIZE + 2] = make_float4(invarea, axisv.x, axisv.y, axisv.z);
+ light_data[pos*LIGHT_SIZE + 3] = make_float4(-1, dir.x, dir.y, dir.z);
+ light_data[pos*LIGHT_SIZE + 4] = make_float4(-1, 0.0f, 0.0f, 0.0f);
+
+ pos++;
+ }
+
+ assert(pos == scene->lights.size());

device->tex_alloc("__light_data", dscene->light_data);
}
diff --git a/intern/cycles/render/light.h b/intern/cycles/render/light.h
index 1f8eac6..cbb4290 100644
--- a/intern/cycles/render/light.h
+++ b/intern/cycles/render/light.h
@@ -56,6 +56,8 @@ public:
bool use_transmission;
bool use_scatter;

+ bool portal;
+
int shader;
int samples;
int max_bounces;
--
1.9.1
  1. From 85d809edeb76988ea8ec4ee9e6d7e0668a267f87 Mon Sep 17 00:00:00 2001
  2. From: Lukas Stockner <lukas.stockner@freenet.de>
  3. Date: Sat, 7 Feb 2015 23:08:17 +0100
  4. Subject: [PATCH] Cycles: Added support for light portals
  5.  
  6. ---
  7.  intern/cycles/blender/addon/properties.py |   6 +
  8.  intern/cycles/blender/addon/ui.py         |   2 +
  9.  intern/cycles/blender/blender_object.cpp  |  49 ++--
  10.  intern/cycles/kernel/kernel_emission.h    |   2 +-
  11.  intern/cycles/kernel/kernel_light.h       | 405 +++++++++++++++++++-----------
  12.  intern/cycles/kernel/kernel_types.h       |   5 +
  13.  intern/cycles/render/light.cpp            | 149 +++++++----
  14.  intern/cycles/render/light.h              |   2 +
  15.  8 files changed, 401 insertions(+), 219 deletions(-)
  16.  
  17. diff --git a/intern/cycles/blender/addon/properties.py b/intern/cycles/blender/addon/properties.py
  18. index 4b84146..d7bbec2 100644
  19. --- a/intern/cycles/blender/addon/properties.py
  20. +++ b/intern/cycles/blender/addon/properties.py
  21. @@ -693,6 +693,12 @@ class CyclesLampSettings(bpy.types.PropertyGroup):
  22.                              "reduces noise for area lamps and sharp glossy materials",
  23.                  default=False,
  24.                  )
  25. +        cls.is_portal = BoolProperty(
  26. +                name="Is Portal",
  27. +                description="Uses this area lamp to guide sampling of the background, "
  28. +                            "note that this will make the lamp invisible",
  29. +                default=False,
  30. +                )
  31.  
  32.      @classmethod
  33.      def unregister(cls):
  34. diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py
  35. index 651114a..ad5bf94 100644
  36. --- a/intern/cycles/blender/addon/ui.py
  37. +++ b/intern/cycles/blender/addon/ui.py
  38. @@ -734,6 +734,8 @@ class CyclesLamp_PT_lamp(CyclesButtonsPanel, Panel):
  39.          col = split.column()
  40.          col.prop(clamp, "cast_shadow")
  41.          col.prop(clamp, "use_multiple_importance_sampling", text="Multiple Importance")
  42. +        if lamp.type == 'AREA':
  43. +            col.prop(clamp, "is_portal")
  44.  
  45.          if lamp.type == 'HEMI':
  46.              layout.label(text="Not supported, interpreted as sun lamp")
  47. diff --git a/intern/cycles/blender/blender_object.cpp b/intern/cycles/blender/blender_object.cpp
  48. index e827d46..abdec9d 100644
  49. --- a/intern/cycles/blender/blender_object.cpp
  50. +++ b/intern/cycles/blender/blender_object.cpp
  51. @@ -171,6 +171,11 @@ void BlenderSync::sync_light(BL::Object b_parent, int persistent_id[OBJECT_PERSI
  52.  
  53.         light->max_bounces = get_int(clamp, "max_bounces");
  54.  
  55. +       if(light->type == LIGHT_AREA)
  56. +               light->portal = get_boolean(clamp, "is_portal");
  57. +       else
  58. +               light->portal = false;
  59. +
  60.         /* visibility */
  61.         uint visibility = object_ray_visibility(b_ob);
  62.         light->use_diffuse = (visibility & PATH_RAY_DIFFUSE) != 0;
  63. @@ -189,30 +194,28 @@ void BlenderSync::sync_background_light()
  64.         if(b_world) {
  65.                 PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
  66.                 PointerRNA cworld = RNA_pointer_get(&b_world.ptr, "cycles");
  67. -               bool sample_as_light = get_boolean(cworld, "sample_as_light");
  68. -
  69. -               if(sample_as_light) {
  70. -                       /* test if we need to sync */
  71. -                       Light *light;
  72. -                       ObjectKey key(b_world, 0, b_world);
  73. -
  74. -                       if(light_map.sync(&light, b_world, b_world, key) ||
  75. -                          world_recalc ||
  76. -                          b_world.ptr.data != world_map)
  77. -                       {
  78. -                               light->type = LIGHT_BACKGROUND;
  79. -                               light->map_resolution  = get_int(cworld, "sample_map_resolution");
  80. -                               light->shader = scene->default_background;
  81. +
  82. +               /* test if we need to sync */
  83. +               Light *light;
  84. +               ObjectKey key(b_world, 0, b_world);
  85. +
  86. +               if(light_map.sync(&light, b_world, b_world, key) ||
  87. +                       world_recalc ||
  88. +                       b_world.ptr.data != world_map)
  89. +               {
  90. +                       light->type = LIGHT_BACKGROUND;
  91. +                       light->map_resolution  = get_int(cworld, "sample_map_resolution");
  92. +                       light->shader = scene->default_background;
  93. +                       light->use_mis = get_boolean(cworld, "sample_as_light");
  94.                                
  95. -                               int samples = get_int(cworld, "samples");
  96. -                               if(get_boolean(cscene, "use_square_samples"))
  97. -                                       light->samples = samples * samples;
  98. -                               else
  99. -                                       light->samples = samples;
  100. -
  101. -                               light->tag_update(scene);
  102. -                               light_map.set_recalc(b_world);
  103. -                       }
  104. +                       int samples = get_int(cworld, "samples");
  105. +                       if(get_boolean(cscene, "use_square_samples"))
  106. +                               light->samples = samples * samples;
  107. +                       else
  108. +                               light->samples = samples;
  109. +
  110. +                       light->tag_update(scene);
  111. +                       light_map.set_recalc(b_world);
  112.                 }
  113.         }
  114.  
  115. diff --git a/intern/cycles/kernel/kernel_emission.h b/intern/cycles/kernel/kernel_emission.h
  116. index 7523105..d75e48f 100644
  117. --- a/intern/cycles/kernel/kernel_emission.h
  118. +++ b/intern/cycles/kernel/kernel_emission.h
  119. @@ -252,7 +252,7 @@ ccl_device_noinline float3 indirect_background(KernelGlobals *kg, PathState *sta
  120.         if(!(state->flag & PATH_RAY_MIS_SKIP) && res) {
  121.                 /* multiple importance sampling, get background light pdf for ray
  122.                  * direction, and compute weight with respect to BSDF pdf */
  123. -               float pdf = background_light_pdf(kg, ray->D);
  124. +               float pdf = background_light_pdf(kg, ray->P, ray->D);
  125.                 float mis_weight = power_heuristic(state->ray_pdf, pdf);
  126.  
  127.                 return L*mis_weight;
  128. diff --git a/intern/cycles/kernel/kernel_light.h b/intern/cycles/kernel/kernel_light.h
  129. index 41920e4..55437a7 100644
  130. --- a/intern/cycles/kernel/kernel_light.h
  131. +++ b/intern/cycles/kernel/kernel_light.h
  132. @@ -33,156 +33,24 @@ typedef struct LightSample {
  133.         LightType type;         /* type of light */
  134.  } LightSample;
  135.  
  136. -/* Background Light */
  137. -
  138. -#ifdef __BACKGROUND_MIS__
  139. -
  140. -ccl_device float3 background_light_sample(KernelGlobals *kg, float randu, float randv, float *pdf)
  141. -{
  142. -       /* for the following, the CDF values are actually a pair of floats, with the
  143. -        * function value as X and the actual CDF as Y.  The last entry's function
  144. -        * value is the CDF total. */
  145. -       int res = kernel_data.integrator.pdf_background_res;
  146. -       int cdf_count = res + 1;
  147. -
  148. -       /* this is basically std::lower_bound as used by pbrt */
  149. -       int first = 0;
  150. -       int count = res;
  151. -
  152. -       while(count > 0) {
  153. -               int step = count >> 1;
  154. -               int middle = first + step;
  155. -
  156. -               if(kernel_tex_fetch(__light_background_marginal_cdf, middle).y < randv) {
  157. -                       first = middle + 1;
  158. -                       count -= step + 1;
  159. -               }
  160. -               else
  161. -                       count = step;
  162. -       }
  163. -
  164. -       int index_v = max(0, first - 1);
  165. -       kernel_assert(index_v >= 0 && index_v < res);
  166. -
  167. -       float2 cdf_v = kernel_tex_fetch(__light_background_marginal_cdf, index_v);
  168. -       float2 cdf_next_v = kernel_tex_fetch(__light_background_marginal_cdf, index_v + 1);
  169. -       float2 cdf_last_v = kernel_tex_fetch(__light_background_marginal_cdf, res);
  170. -
  171. -       /* importance-sampled V direction */
  172. -       float dv = (randv - cdf_v.y) / (cdf_next_v.y - cdf_v.y);
  173. -       float v = (index_v + dv) / res;
  174. -
  175. -       /* this is basically std::lower_bound as used by pbrt */
  176. -       first = 0;
  177. -       count = res;
  178. -       while(count > 0) {
  179. -               int step = count >> 1;
  180. -               int middle = first + step;
  181. -
  182. -               if(kernel_tex_fetch(__light_background_conditional_cdf, index_v * cdf_count + middle).y < randu) {
  183. -                       first = middle + 1;
  184. -                       count -= step + 1;
  185. -               }
  186. -               else
  187. -                       count = step;
  188. -       }
  189. -
  190. -       int index_u = max(0, first - 1);
  191. -       kernel_assert(index_u >= 0 && index_u < res);
  192. -
  193. -       float2 cdf_u = kernel_tex_fetch(__light_background_conditional_cdf, index_v * cdf_count + index_u);
  194. -       float2 cdf_next_u = kernel_tex_fetch(__light_background_conditional_cdf, index_v * cdf_count + index_u + 1);
  195. -       float2 cdf_last_u = kernel_tex_fetch(__light_background_conditional_cdf, index_v * cdf_count + res);
  196. -
  197. -       /* importance-sampled U direction */
  198. -       float du = (randu - cdf_u.y) / (cdf_next_u.y - cdf_u.y);
  199. -       float u = (index_u + du) / res;
  200. -
  201. -       /* compute pdf */
  202. -       float denom = cdf_last_u.x * cdf_last_v.x;
  203. -       float sin_theta = sinf(M_PI_F * v);
  204. -
  205. -       if(sin_theta == 0.0f || denom == 0.0f)
  206. -               *pdf = 0.0f;
  207. -       else
  208. -               *pdf = (cdf_u.x * cdf_v.x)/(M_2PI_F * M_PI_F * sin_theta * denom);
  209. -
  210. -       *pdf *= kernel_data.integrator.pdf_lights;
  211. -
  212. -       /* compute direction */
  213. -       return -equirectangular_to_direction(u, v);
  214. -}
  215. -
  216. -ccl_device float background_light_pdf(KernelGlobals *kg, float3 direction)
  217. -{
  218. -       float2 uv = direction_to_equirectangular(direction);
  219. -       int res = kernel_data.integrator.pdf_background_res;
  220. -
  221. -       float sin_theta = sinf(uv.y * M_PI_F);
  222. -
  223. -       if(sin_theta == 0.0f)
  224. -               return 0.0f;
  225. -
  226. -       int index_u = clamp(float_to_int(uv.x * res), 0, res - 1);
  227. -       int index_v = clamp(float_to_int(uv.y * res), 0, res - 1);
  228. -
  229. -       /* pdfs in V direction */
  230. -       float2 cdf_last_u = kernel_tex_fetch(__light_background_conditional_cdf, index_v * (res + 1) + res);
  231. -       float2 cdf_last_v = kernel_tex_fetch(__light_background_marginal_cdf, res);
  232. -
  233. -       float denom = cdf_last_u.x * cdf_last_v.x;
  234. -
  235. -       if(denom == 0.0f)
  236. -               return 0.0f;
  237. -
  238. -       /* pdfs in U direction */
  239. -       float2 cdf_u = kernel_tex_fetch(__light_background_conditional_cdf, index_v * (res + 1) + index_u);
  240. -       float2 cdf_v = kernel_tex_fetch(__light_background_marginal_cdf, index_v);
  241. -
  242. -       float pdf = (cdf_u.x * cdf_v.x)/(M_2PI_F * M_PI_F * sin_theta * denom);
  243. -
  244. -       return pdf * kernel_data.integrator.pdf_lights;
  245. -}
  246. -#endif
  247. -
  248. -/* Regular Light */
  249. -
  250. -ccl_device float3 disk_light_sample(float3 v, float randu, float randv)
  251. -{
  252. -       float3 ru, rv;
  253. -
  254. -       make_orthonormals(v, &ru, &rv);
  255. -       to_unit_disk(&randu, &randv);
  256. -
  257. -       return ru*randu + rv*randv;
  258. -}
  259. -
  260. -ccl_device float3 distant_light_sample(float3 D, float radius, float randu, float randv)
  261. -{
  262. -       return normalize(D + disk_light_sample(D, randu, randv)*radius);
  263. -}
  264. -
  265. -ccl_device float3 sphere_light_sample(float3 P, float3 center, float radius, float randu, float randv)
  266. -{
  267. -       return disk_light_sample(normalize(P - center), randu, randv)*radius;
  268. -}
  269. +/* Area light sampling */
  270.  
  271.  /* Uses the following paper:
  272. - *
  273. - * Carlos Urena et al.
  274. - * An Area-Preserving Parametrization for Spherical Rectangles.
  275. - *
  276. - * https://www.solidangle.com/research/egsr2013_spherical_rectangle.pdf
  277. - */
  278. +*
  279. +* Carlos Urena et al.
  280. +* An Area-Preserving Parametrization for Spherical Rectangles.
  281. +*
  282. +* https://www.solidangle.com/research/egsr2013_spherical_rectangle.pdf
  283. +*/
  284.  ccl_device float3 area_light_sample(float3 P,
  285. -                                    float3 light_p,
  286. -                                    float3 axisu, float3 axisv,
  287. -                                    float randu, float randv,
  288. -                                    float *pdf)
  289. +       float3 light_p,
  290. +       float3 axisu, float3 axisv,
  291. +       float randu, float randv,
  292. +       float *pdf)
  293.  {
  294.         /* In our name system we're using P for the center,
  295. -        * which is o in the paper.
  296. -        */
  297. +       * which is o in the paper.
  298. +       */
  299.  
  300.         float3 corner = light_p - axisu * 0.5f - axisv * 0.5f;
  301.         float axisu_len, axisv_len;
  302. @@ -253,15 +121,15 @@ ccl_device float3 area_light_sample(float3 P,
  303.  }
  304.  
  305.  /* TODO(sergey): This is actually a duplicated code from above, but how to avoid
  306. - * this without having some nasty function with loads of parameters?
  307. - */
  308. +* this without having some nasty function with loads of parameters?
  309. +*/
  310.  ccl_device float area_light_pdf(float3 P,
  311. -                                float3 light_p,
  312. -                                float3 axisu, float3 axisv)
  313. +       float3 light_p,
  314. +       float3 axisu, float3 axisv)
  315.  {
  316.         /* In our name system we're using P for the center,
  317. -        * which is o in the paper.
  318. -        */
  319. +       * which is o in the paper.
  320. +       */
  321.  
  322.         float3 corner = light_p - axisu * 0.5f - axisv * 0.5f;
  323.         float axisu_len, axisv_len;
  324. @@ -306,6 +174,239 @@ ccl_device float area_light_pdf(float3 P,
  325.                 return 0.0f;
  326.  }
  327.  
  328. +/* Background Light */
  329. +
  330. +#ifdef __BACKGROUND_MIS__
  331. +
  332. +ccl_device float3 background_sample_cdf(KernelGlobals *kg, float randu, float randv, float *pdf) {
  333. +       /* for the following, the CDF values are actually a pair of floats, with the
  334. +       * function value as X and the actual CDF as Y.  The last entry's function
  335. +       * value is the CDF total. */
  336. +       int res = kernel_data.integrator.pdf_background_res;
  337. +       int cdf_count = res + 1;
  338. +
  339. +       /* this is basically std::lower_bound as used by pbrt */
  340. +       int first = 0;
  341. +       int count = res;
  342. +
  343. +       while (count > 0) {
  344. +               int step = count >> 1;
  345. +               int middle = first + step;
  346. +
  347. +               if (kernel_tex_fetch(__light_background_marginal_cdf, middle).y < randv) {
  348. +                       first = middle + 1;
  349. +                       count -= step + 1;
  350. +               }
  351. +               else
  352. +                       count = step;
  353. +       }
  354. +
  355. +       int index_v = max(0, first - 1);
  356. +       kernel_assert(index_v >= 0 && index_v < res);
  357. +
  358. +       float2 cdf_v = kernel_tex_fetch(__light_background_marginal_cdf, index_v);
  359. +       float2 cdf_next_v = kernel_tex_fetch(__light_background_marginal_cdf, index_v + 1);
  360. +       float2 cdf_last_v = kernel_tex_fetch(__light_background_marginal_cdf, res);
  361. +
  362. +       /* importance-sampled V direction */
  363. +       float dv = (randv - cdf_v.y) / (cdf_next_v.y - cdf_v.y);
  364. +       float v = (index_v + dv) / res;
  365. +
  366. +       /* this is basically std::lower_bound as used by pbrt */
  367. +       first = 0;
  368. +       count = res;
  369. +       while (count > 0) {
  370. +               int step = count >> 1;
  371. +               int middle = first + step;
  372. +
  373. +               if (kernel_tex_fetch(__light_background_conditional_cdf, index_v * cdf_count + middle).y < randu) {
  374. +                       first = middle + 1;
  375. +                       count -= step + 1;
  376. +               }
  377. +               else
  378. +                       count = step;
  379. +       }
  380. +
  381. +       int index_u = max(0, first - 1);
  382. +       kernel_assert(index_u >= 0 && index_u < res);
  383. +
  384. +       float2 cdf_u = kernel_tex_fetch(__light_background_conditional_cdf, index_v * cdf_count + index_u);
  385. +       float2 cdf_next_u = kernel_tex_fetch(__light_background_conditional_cdf, index_v * cdf_count + index_u + 1);
  386. +       float2 cdf_last_u = kernel_tex_fetch(__light_background_conditional_cdf, index_v * cdf_count + res);
  387. +
  388. +       /* importance-sampled U direction */
  389. +       float du = (randu - cdf_u.y) / (cdf_next_u.y - cdf_u.y);
  390. +       float u = (index_u + du) / res;
  391. +
  392. +       /* compute pdf */
  393. +       float denom = cdf_last_u.x * cdf_last_v.x;
  394. +       float sin_theta = sinf(M_PI_F * v);
  395. +
  396. +       if (sin_theta == 0.0f || denom == 0.0f)
  397. +               *pdf = 0.0f;
  398. +       else
  399. +               *pdf = (cdf_u.x * cdf_v.x) / (M_2PI_F * M_PI_F * sin_theta * denom);
  400. +
  401. +       *pdf *= kernel_data.integrator.pdf_lights;
  402. +
  403. +       /* compute direction */
  404. +       return equirectangular_to_direction(u, v);
  405. +}
  406. +
  407. +ccl_device float background_pdf_cdf(KernelGlobals *kg, float3 direction) {
  408. +       float2 uv = direction_to_equirectangular(direction);
  409. +       int res = kernel_data.integrator.pdf_background_res;
  410. +
  411. +       float sin_theta = sinf(uv.y * M_PI_F);
  412. +
  413. +       if(sin_theta == 0.0f)
  414. +               return 0.0f;
  415. +
  416. +       int index_u = clamp(float_to_int(uv.x * res), 0, res - 1);
  417. +       int index_v = clamp(float_to_int(uv.y * res), 0, res - 1);
  418. +
  419. +       /* pdfs in V direction */
  420. +       float2 cdf_last_u = kernel_tex_fetch(__light_background_conditional_cdf, index_v * (res + 1) + res);
  421. +       float2 cdf_last_v = kernel_tex_fetch(__light_background_marginal_cdf, res);
  422. +
  423. +       float denom = cdf_last_u.x * cdf_last_v.x;
  424. +
  425. +       if(denom == 0.0f)
  426. +               return 0.0f;
  427. +
  428. +       /* pdfs in U direction */
  429. +       float2 cdf_u = kernel_tex_fetch(__light_background_conditional_cdf, index_v * (res + 1) + index_u);
  430. +       float2 cdf_v = kernel_tex_fetch(__light_background_marginal_cdf, index_v);
  431. +
  432. +       return (cdf_u.x * cdf_v.x)/(M_2PI_F * M_PI_F * sin_theta * denom) * kernel_data.integrator.pdf_lights;
  433. +}
  434. +
  435. +ccl_device float3 background_sample_portal(KernelGlobals *kg, float3 P, float randu, float randv, float *pdf) {
  436. +       randv *= kernel_data.integrator.num_portals;
  437. +       int portal = (int)randv;
  438. +       randv -= portal;
  439. +
  440. +       portal += kernel_data.integrator.portal_offset;
  441. +
  442. +       float4 data0 = kernel_tex_fetch(__light_data, portal*LIGHT_SIZE + 0);
  443. +       float4 data1 = kernel_tex_fetch(__light_data, portal*LIGHT_SIZE + 1);
  444. +       float4 data2 = kernel_tex_fetch(__light_data, portal*LIGHT_SIZE + 2);
  445. +
  446. +       float3 lightpos = make_float3(data0.y, data0.z, data0.w);
  447. +       float3 axisu = make_float3(data1.y, data1.z, data1.w);
  448. +       float3 axisv = make_float3(data2.y, data2.z, data2.w);
  449. +
  450. +       float3 lightPoint = area_light_sample(P, lightpos,
  451. +               axisu, axisv,
  452. +               randu, randv,
  453. +               pdf);
  454. +
  455. +       *pdf /= kernel_data.integrator.num_portals;
  456. +
  457. +       return normalize(lightPoint - P);
  458. +}
  459. +
  460. +ccl_device float background_pdf_portal(KernelGlobals *kg, float3 P, float3 direction) {
  461. +       float portal_pdf = 0.0f;
  462. +       for (int p = 0; p < kernel_data.integrator.num_portals; p++) {
  463. +               float4 data0 = kernel_tex_fetch(__light_data, (p + kernel_data.integrator.portal_offset)*LIGHT_SIZE + 0);
  464. +               float4 data1 = kernel_tex_fetch(__light_data, (p + kernel_data.integrator.portal_offset)*LIGHT_SIZE + 1);
  465. +               float4 data2 = kernel_tex_fetch(__light_data, (p + kernel_data.integrator.portal_offset)*LIGHT_SIZE + 2);
  466. +               float4 data3 = kernel_tex_fetch(__light_data, (p + kernel_data.integrator.portal_offset)*LIGHT_SIZE + 3);
  467. +
  468. +               float3 lightpos = make_float3(data0.y, data0.z, data0.w);
  469. +               float3 axisu = make_float3(data1.y, data1.z, data1.w);
  470. +               float3 axisv = make_float3(data2.y, data2.z, data2.w);
  471. +               float3 dir = make_float3(data3.y, data3.z, data3.w);
  472. +
  473. +               //Hits portal?
  474. +               float t = -(dot(P, dir) - dot(lightpos, dir)) / dot(direction, dir);
  475. +               if (t <= 0) continue;
  476. +               float3 hit = P + t*direction;
  477. +               float3 inplane = hit - lightpos;
  478. +               if (fabsf(dot(inplane, axisu) / dot(axisu, axisu)) > 1.0f) continue;
  479. +               if (fabsf(dot(inplane, axisv) / dot(axisv, axisv)) > 1.0f) continue;
  480. +
  481. +               portal_pdf += area_light_pdf(P, lightpos, axisu, axisv);
  482. +       }
  483. +       return portal_pdf / kernel_data.integrator.num_portals;
  484. +}
  485. +
  486. +ccl_device float3 background_light_sample(KernelGlobals *kg, float3 P, float randu, float randv, float *pdf)
  487. +{
  488. +       bool sample_portal;
  489. +       if (kernel_data.integrator.portal_pdf == 0.0f)
  490. +               sample_portal = false;
  491. +       else if (kernel_data.integrator.portal_pdf == 1.0f)
  492. +               sample_portal = true;
  493. +       else {
  494. +               if (randu < kernel_data.integrator.portal_pdf) {
  495. +                       sample_portal = true;
  496. +                       randu /= kernel_data.integrator.portal_pdf;
  497. +               }
  498. +               else {
  499. +                       sample_portal = false;
  500. +                       randu = (randu - kernel_data.integrator.portal_pdf) / (1.0f - kernel_data.integrator.portal_pdf);
  501. +               }
  502. +       }
  503. +
  504. +       if (sample_portal) {
  505. +               float3 D = background_sample_portal(kg, P, randu, randv, pdf);
  506. +
  507. +               /* Could the CDF be sampled? If yes, use MIS! */
  508. +               if (kernel_data.integrator.portal_pdf < 1.0f) {
  509. +                       float cdf_pdf = background_pdf_cdf(kg, D);
  510. +                       *pdf = (kernel_data.integrator.portal_pdf * (*pdf) + (1.0f - kernel_data.integrator.portal_pdf) * cdf_pdf);
  511. +               }
  512. +               return D;
  513. +       }
  514. +       else {
  515. +               float3 D = background_sample_cdf(kg, randu, randv, pdf);
  516. +               /* Could light portals be sampled? If yes, use MIS! */
  517. +               if (kernel_data.integrator.portal_pdf > 0.0f) {
  518. +                       float portal_pdf = background_pdf_portal(kg, P, D);
  519. +                       *pdf = (kernel_data.integrator.portal_pdf * portal_pdf + (1.0f - kernel_data.integrator.portal_pdf) * (*pdf));
  520. +               }
  521. +               return D;
  522. +       }
  523. +}
  524. +
  525. +ccl_device float background_light_pdf(KernelGlobals *kg, float3 P, float3 direction)
  526. +{
  527. +       /* Only CDF? */
  528. +       if (kernel_data.integrator.portal_pdf == 0.0f) return background_pdf_cdf(kg, direction);
  529. +
  530. +       /* Only Portal? */
  531. +       if (kernel_data.integrator.portal_pdf == 1.0f) return background_pdf_portal(kg, P, direction);
  532. +
  533. +       /* Both, so combine them by MIS */
  534. +       return background_pdf_cdf(kg, direction)       * (1.0f - kernel_data.integrator.portal_pdf)
  535. +                + background_pdf_portal(kg, P, direction) * kernel_data.integrator.portal_pdf;
  536. +}
  537. +#endif
  538. +
  539. +/* Regular Light */
  540. +
  541. +ccl_device float3 disk_light_sample(float3 v, float randu, float randv)
  542. +{
  543. +       float3 ru, rv;
  544. +
  545. +       make_orthonormals(v, &ru, &rv);
  546. +       to_unit_disk(&randu, &randv);
  547. +
  548. +       return ru*randu + rv*randv;
  549. +}
  550. +
  551. +ccl_device float3 distant_light_sample(float3 D, float radius, float randu, float randv)
  552. +{
  553. +       return normalize(D + disk_light_sample(D, randu, randv)*radius);
  554. +}
  555. +
  556. +ccl_device float3 sphere_light_sample(float3 P, float3 center, float radius, float randu, float randv)
  557. +{
  558. +       return disk_light_sample(normalize(P - center), randu, randv)*radius;
  559. +}
  560. +
  561.  ccl_device float spot_light_attenuation(float4 data1, float4 data2, LightSample *ls)
  562.  {
  563.         float3 dir = make_float3(data2.y, data2.z, data2.w);
  564. @@ -376,7 +477,7 @@ ccl_device void lamp_light_sample(KernelGlobals *kg, int lamp,
  565.  #ifdef __BACKGROUND_MIS__
  566.         else if(type == LIGHT_BACKGROUND) {
  567.                 /* infinite area light (e.g. light dome or env light) */
  568. -               float3 D = background_light_sample(kg, randu, randv, &ls->pdf);
  569. +               float3 D = -background_light_sample(kg, P, randu, randv, &ls->pdf);
  570.  
  571.                 ls->P = D;
  572.                 ls->Ng = D;
  573. diff --git a/intern/cycles/kernel/kernel_types.h b/intern/cycles/kernel/kernel_types.h
  574. index 77d3ea8..cc1512c 100644
  575. --- a/intern/cycles/kernel/kernel_types.h
  576. +++ b/intern/cycles/kernel/kernel_types.h
  577. @@ -895,6 +895,11 @@ typedef struct KernelIntegrator {
  578.         float inv_pdf_lights;
  579.         int pdf_background_res;
  580.  
  581. +       /* light portals */
  582. +       float portal_pdf;
  583. +       int num_portals;
  584. +       int portal_offset;
  585. +
  586.         /* bounces */
  587.         int min_bounce;
  588.         int max_bounce;
  589. diff --git a/intern/cycles/render/light.cpp b/intern/cycles/render/light.cpp
  590. index ca6853e..b8ac51b 100644
  591. --- a/intern/cycles/render/light.cpp
  592. +++ b/intern/cycles/render/light.cpp
  593. @@ -126,6 +126,8 @@ Light::Light()
  594.         shader = 0;
  595.         samples = 1;
  596.         max_bounces = 1024;
  597. +
  598. +       portal = false;
  599.  }
  600.  
  601.  void Light::tag_update(Scene *scene)
  602. @@ -150,10 +152,16 @@ void LightManager::device_update_distribution(Device *device, DeviceScene *dscen
  603.         progress.set_status("Updating Lights", "Computing distribution");
  604.  
  605.         /* count */
  606. -       size_t num_lights = scene->lights.size();
  607. +       size_t num_lights = 0;
  608.         size_t num_background_lights = 0;
  609. +       bool background_mis = false;
  610.         size_t num_triangles = 0;
  611.  
  612. +       foreach(Light *light, scene->lights) {
  613. +               if (!light->portal)
  614. +                       num_lights++;
  615. +       }
  616. +
  617.         foreach(Object *object, scene->objects) {
  618.                 Mesh *mesh = object->mesh;
  619.                 bool have_emission = false;
  620. @@ -284,22 +292,28 @@ void LightManager::device_update_distribution(Device *device, DeviceScene *dscen
  621.         float trianglearea = totarea;
  622.  
  623.         /* point lights */
  624. -       float lightarea = (totarea > 0.0f)? totarea/scene->lights.size(): 1.0f;
  625. +       float lightarea = (totarea > 0.0f) ? totarea / num_lights : 1.0f;
  626.         bool use_lamp_mis = false;
  627.  
  628. -       for(int i = 0; i < scene->lights.size(); i++, offset++) {
  629. -               Light *light = scene->lights[i];
  630. +       int pos = 0;
  631. +       foreach(Light *light, scene->lights) {
  632. +               if (light->portal) continue;
  633.  
  634.                 distribution[offset].x = totarea;
  635. -               distribution[offset].y = __int_as_float(~(int)i);
  636. +               distribution[offset].y = __int_as_float(~(int)pos);
  637.                 distribution[offset].z = 1.0f;
  638.                 distribution[offset].w = light->size;
  639.                 totarea += lightarea;
  640.  
  641.                 if(light->size > 0.0f && light->use_mis)
  642.                         use_lamp_mis = true;
  643. -               if(light->type == LIGHT_BACKGROUND)
  644. +               if (light->type == LIGHT_BACKGROUND) {
  645.                         num_background_lights++;
  646. +                       background_mis = light->use_mis;
  647. +               }
  648. +
  649. +               pos++;
  650. +               offset++;
  651.         }
  652.  
  653.         /* normalize cumulative distribution functions */
  654. @@ -361,6 +375,17 @@ void LightManager::device_update_distribution(Device *device, DeviceScene *dscen
  655.  
  656.                 /* CDF */
  657.                 device->tex_alloc("__light_distribution", dscene->light_distribution);
  658. +
  659. +               if (num_background_lights > 0 && pos != scene->lights.size()) {
  660. +                       kintegrator->portal_offset = pos;
  661. +                       kintegrator->num_portals = scene->lights.size() - pos;
  662. +                       kintegrator->portal_pdf = background_mis? 0.5f: 1.0f;
  663. +               }
  664. +               else {
  665. +                       kintegrator->num_portals = 0;
  666. +                       kintegrator->portal_offset = 0;
  667. +                       kintegrator->portal_pdf = 0.0f;
  668. +               }
  669.         }
  670.         else {
  671.                 dscene->light_distribution.clear();
  672. @@ -372,6 +397,9 @@ void LightManager::device_update_distribution(Device *device, DeviceScene *dscen
  673.                 kintegrator->inv_pdf_lights = 0.0f;
  674.                 kintegrator->use_lamp_mis = false;
  675.                 kfilm->pass_shadow_scale = 1.0f;
  676. +               kintegrator->num_portals = 0;
  677. +               kintegrator->portal_offset = 0;
  678. +               kintegrator->portal_pdf = 0.0f;
  679.         }
  680.  }
  681.  
  682. @@ -470,25 +498,34 @@ void LightManager::device_update_background(Device *device, DeviceScene *dscene,
  683.  
  684.  void LightManager::device_update_points(Device *device, DeviceScene *dscene, Scene *scene)
  685.  {
  686. +       bool has_portals = false;
  687. +       foreach(Light *light, scene->lights) {
  688. +               if (light->portal) {
  689. +                       has_portals = true;
  690. +                       break;
  691. +               }
  692. +       }
  693. +
  694. +       /* remove background light? */
  695. +       foreach(Light *light, scene->lights) {
  696. +               if (light->type != LIGHT_BACKGROUND) continue;
  697. +               if (!(device->info.advanced_shading && (has_portals || light->use_mis)))
  698. +                       scene->lights.erase(std::remove(scene->lights.begin(), scene->lights.end(), light), scene->lights.end());
  699. +               break;
  700. +       }
  701. +
  702.         if(scene->lights.size() == 0)
  703.                 return;
  704.  
  705.         float4 *light_data = dscene->light_data.resize(scene->lights.size()*LIGHT_SIZE);
  706.  
  707. -       if(!device->info.advanced_shading) {
  708. -               /* remove unsupported light */
  709. -               foreach(Light *light, scene->lights) {
  710. -                       if(light->type == LIGHT_BACKGROUND) {
  711. -                               scene->lights.erase(std::remove(scene->lights.begin(), scene->lights.end(), light), scene->lights.end());
  712. -                               break;
  713. -                       }
  714. -               }
  715. -       }
  716. +       int pos = 0;
  717. +
  718. +       foreach(Light *light, scene->lights) {
  719. +               if (light->portal) continue;
  720.  
  721. -       for(size_t i = 0; i < scene->lights.size(); i++) {
  722. -               Light *light = scene->lights[i];
  723.                 float3 co = light->co;
  724. -               int shader_id = scene->shader_manager->get_shader_id(scene->lights[i]->shader);
  725. +               int shader_id = scene->shader_manager->get_shader_id(light->shader);
  726.                 float samples = __int_as_float(light->samples);
  727.                 float max_bounces = __int_as_float(light->max_bounces);
  728.  
  729. @@ -521,11 +558,11 @@ void LightManager::device_update_points(Device *device, DeviceScene *dscene, Sce
  730.                         if(light->use_mis && radius > 0.0f)
  731.                                 shader_id |= SHADER_USE_MIS;
  732.  
  733. -                       light_data[i*LIGHT_SIZE + 0] = make_float4(__int_as_float(light->type), co.x, co.y, co.z);
  734. -                       light_data[i*LIGHT_SIZE + 1] = make_float4(__int_as_float(shader_id), radius, invarea, 0.0f);
  735. -                       light_data[i*LIGHT_SIZE + 2] = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
  736. -                       light_data[i*LIGHT_SIZE + 3] = make_float4(samples, 0.0f, 0.0f, 0.0f);
  737. -                       light_data[i*LIGHT_SIZE + 4] = make_float4(max_bounces, 0.0f, 0.0f, 0.0f);
  738. +                       light_data[pos*LIGHT_SIZE + 0] = make_float4(__int_as_float(light->type), co.x, co.y, co.z);
  739. +                       light_data[pos*LIGHT_SIZE + 1] = make_float4(__int_as_float(shader_id), radius, invarea, 0.0f);
  740. +                       light_data[pos*LIGHT_SIZE + 2] = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
  741. +                       light_data[pos*LIGHT_SIZE + 3] = make_float4(samples, 0.0f, 0.0f, 0.0f);
  742. +                       light_data[pos*LIGHT_SIZE + 4] = make_float4(max_bounces, 0.0f, 0.0f, 0.0f);
  743.                 }
  744.                 else if(light->type == LIGHT_DISTANT) {
  745.                         shader_id &= ~SHADER_AREA_LIGHT;
  746. @@ -542,11 +579,11 @@ void LightManager::device_update_points(Device *device, DeviceScene *dscene, Sce
  747.                         if(light->use_mis && area > 0.0f)
  748.                                 shader_id |= SHADER_USE_MIS;
  749.  
  750. -                       light_data[i*LIGHT_SIZE + 0] = make_float4(__int_as_float(light->type), dir.x, dir.y, dir.z);
  751. -                       light_data[i*LIGHT_SIZE + 1] = make_float4(__int_as_float(shader_id), radius, cosangle, invarea);
  752. -                       light_data[i*LIGHT_SIZE + 2] = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
  753. -                       light_data[i*LIGHT_SIZE + 3] = make_float4(samples, 0.0f, 0.0f, 0.0f);
  754. -                       light_data[i*LIGHT_SIZE + 4] = make_float4(max_bounces, 0.0f, 0.0f, 0.0f);
  755. +                       light_data[pos*LIGHT_SIZE + 0] = make_float4(__int_as_float(light->type), dir.x, dir.y, dir.z);
  756. +                       light_data[pos*LIGHT_SIZE + 1] = make_float4(__int_as_float(shader_id), radius, cosangle, invarea);
  757. +                       light_data[pos*LIGHT_SIZE + 2] = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
  758. +                       light_data[pos*LIGHT_SIZE + 3] = make_float4(samples, 0.0f, 0.0f, 0.0f);
  759. +                       light_data[pos*LIGHT_SIZE + 4] = make_float4(max_bounces, 0.0f, 0.0f, 0.0f);
  760.                 }
  761.                 else if(light->type == LIGHT_BACKGROUND) {
  762.                         uint visibility = scene->background->visibility;
  763. @@ -571,11 +608,11 @@ void LightManager::device_update_points(Device *device, DeviceScene *dscene, Sce
  764.                                 use_light_visibility = true;
  765.                         }
  766.  
  767. -                       light_data[i*LIGHT_SIZE + 0] = make_float4(__int_as_float(light->type), 0.0f, 0.0f, 0.0f);
  768. -                       light_data[i*LIGHT_SIZE + 1] = make_float4(__int_as_float(shader_id), 0.0f, 0.0f, 0.0f);
  769. -                       light_data[i*LIGHT_SIZE + 2] = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
  770. -                       light_data[i*LIGHT_SIZE + 3] = make_float4(samples, 0.0f, 0.0f, 0.0f);
  771. -                       light_data[i*LIGHT_SIZE + 4] = make_float4(max_bounces, 0.0f, 0.0f, 0.0f);
  772. +                       light_data[pos*LIGHT_SIZE + 0] = make_float4(__int_as_float(light->type), 0.0f, 0.0f, 0.0f);
  773. +                       light_data[pos*LIGHT_SIZE + 1] = make_float4(__int_as_float(shader_id), 0.0f, 0.0f, 0.0f);
  774. +                       light_data[pos*LIGHT_SIZE + 2] = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
  775. +                       light_data[pos*LIGHT_SIZE + 3] = make_float4(samples, 0.0f, 0.0f, 0.0f);
  776. +                       light_data[pos*LIGHT_SIZE + 4] = make_float4(max_bounces, 0.0f, 0.0f, 0.0f);
  777.                 }
  778.                 else if(light->type == LIGHT_AREA) {
  779.                         float3 axisu = light->axisu*(light->sizeu*light->size);
  780. @@ -589,11 +626,11 @@ void LightManager::device_update_points(Device *device, DeviceScene *dscene, Sce
  781.                         if(light->use_mis && area > 0.0f)
  782.                                 shader_id |= SHADER_USE_MIS;
  783.  
  784. -                       light_data[i*LIGHT_SIZE + 0] = make_float4(__int_as_float(light->type), co.x, co.y, co.z);
  785. -                       light_data[i*LIGHT_SIZE + 1] = make_float4(__int_as_float(shader_id), axisu.x, axisu.y, axisu.z);
  786. -                       light_data[i*LIGHT_SIZE + 2] = make_float4(invarea, axisv.x, axisv.y, axisv.z);
  787. -                       light_data[i*LIGHT_SIZE + 3] = make_float4(samples, dir.x, dir.y, dir.z);
  788. -                       light_data[i*LIGHT_SIZE + 4] = make_float4(max_bounces, 0.0f, 0.0f, 0.0f);
  789. +                       light_data[pos*LIGHT_SIZE + 0] = make_float4(__int_as_float(light->type), co.x, co.y, co.z);
  790. +                       light_data[pos*LIGHT_SIZE + 1] = make_float4(__int_as_float(shader_id), axisu.x, axisu.y, axisu.z);
  791. +                       light_data[pos*LIGHT_SIZE + 2] = make_float4(invarea, axisv.x, axisv.y, axisv.z);
  792. +                       light_data[pos*LIGHT_SIZE + 3] = make_float4(samples, dir.x, dir.y, dir.z);
  793. +                       light_data[pos*LIGHT_SIZE + 4] = make_float4(max_bounces, 0.0f, 0.0f, 0.0f);
  794.                 }
  795.                 else if(light->type == LIGHT_SPOT) {
  796.                         shader_id &= ~SHADER_AREA_LIGHT;
  797. @@ -609,13 +646,39 @@ void LightManager::device_update_points(Device *device, DeviceScene *dscene, Sce
  798.                         if(light->use_mis && radius > 0.0f)
  799.                                 shader_id |= SHADER_USE_MIS;
  800.  
  801. -                       light_data[i*LIGHT_SIZE + 0] = make_float4(__int_as_float(light->type), co.x, co.y, co.z);
  802. -                       light_data[i*LIGHT_SIZE + 1] = make_float4(__int_as_float(shader_id), radius, invarea, spot_angle);
  803. -                       light_data[i*LIGHT_SIZE + 2] = make_float4(spot_smooth, dir.x, dir.y, dir.z);
  804. -                       light_data[i*LIGHT_SIZE + 3] = make_float4(samples, 0.0f, 0.0f, 0.0f);
  805. -                       light_data[i*LIGHT_SIZE + 4] = make_float4(max_bounces, 0.0f, 0.0f, 0.0f);
  806. +                       light_data[pos*LIGHT_SIZE + 0] = make_float4(__int_as_float(light->type), co.x, co.y, co.z);
  807. +                       light_data[pos*LIGHT_SIZE + 1] = make_float4(__int_as_float(shader_id), radius, invarea, spot_angle);
  808. +                       light_data[pos*LIGHT_SIZE + 2] = make_float4(spot_smooth, dir.x, dir.y, dir.z);
  809. +                       light_data[pos*LIGHT_SIZE + 3] = make_float4(samples, 0.0f, 0.0f, 0.0f);
  810. +                       light_data[pos*LIGHT_SIZE + 4] = make_float4(max_bounces, 0.0f, 0.0f, 0.0f);
  811.                 }
  812. +
  813. +               pos++;
  814.         }
  815. +
  816. +       foreach(Light *light, scene->lights) {
  817. +               if (!light->portal) continue;
  818. +               assert(light->type == LIGHT_AREA);
  819. +
  820. +               float3 co = light->co;
  821. +               float3 axisu = light->axisu*(light->sizeu*light->size);
  822. +               float3 axisv = light->axisv*(light->sizev*light->size);
  823. +               float area = len(axisu)*len(axisv);
  824. +               float invarea = (area > 0.0f) ? 1.0f / area : 1.0f;
  825. +               float3 dir = light->dir;
  826. +
  827. +               dir = safe_normalize(dir);
  828. +
  829. +               light_data[pos*LIGHT_SIZE + 0] = make_float4(__int_as_float(light->type), co.x, co.y, co.z);
  830. +               light_data[pos*LIGHT_SIZE + 1] = make_float4(area, axisu.x, axisu.y, axisu.z);
  831. +               light_data[pos*LIGHT_SIZE + 2] = make_float4(invarea, axisv.x, axisv.y, axisv.z);
  832. +               light_data[pos*LIGHT_SIZE + 3] = make_float4(-1, dir.x, dir.y, dir.z);
  833. +               light_data[pos*LIGHT_SIZE + 4] = make_float4(-1, 0.0f, 0.0f, 0.0f);
  834. +
  835. +               pos++;
  836. +       }
  837. +
  838. +       assert(pos == scene->lights.size());
  839.         
  840.         device->tex_alloc("__light_data", dscene->light_data);
  841.  }
  842. diff --git a/intern/cycles/render/light.h b/intern/cycles/render/light.h
  843. index 1f8eac6..cbb4290 100644
  844. --- a/intern/cycles/render/light.h
  845. +++ b/intern/cycles/render/light.h
  846. @@ -56,6 +56,8 @@ public:
  847.         bool use_transmission;
  848.         bool use_scatter;
  849.  
  850. +       bool portal;
  851. +
  852.         int shader;
  853.         int samples;
  854.         int max_bounces;
  855. --
  856. 1.9.1
  857.  
go to heaven