[Bf-blender-cvs] [df7f4d1e269] gsoc-2018-many-light-sampling: Cycles: Area lights support and better energy estimation

Erik Englesson noreply at git.blender.org
Fri Jun 15 12:34:06 CEST 2018


Commit: df7f4d1e2692c6c8ff3a32acd8863e349c260ac6
Author: Erik Englesson
Date:   Thu Jun 14 09:50:11 2018 +0200
Branches: gsoc-2018-many-light-sampling
https://developer.blender.org/rBdf7f4d1e2692c6c8ff3a32acd8863e349c260ac6

Cycles: Area lights support and better energy estimation

The light BVH now supports area lights. Also, the total emitted
energy of each light is now calculated by integrating luminance
over the sphere of directions and area.

===================================================================

M	intern/cycles/render/light_tree.cpp
M	intern/cycles/render/mesh.h

===================================================================

diff --git a/intern/cycles/render/light_tree.cpp b/intern/cycles/render/light_tree.cpp
index 38822201253..799349e9fc2 100644
--- a/intern/cycles/render/light_tree.cpp
+++ b/intern/cycles/render/light_tree.cpp
@@ -126,11 +126,31 @@ BoundBox LightTree::get_bbox(const Primitive& prim)
             float radius = lamp->size;
             bbox.grow(lamp->co + make_float3(radius));
             bbox.grow(lamp->co - make_float3(radius));
+        } else if(lamp->type == LIGHT_AREA){
+           /*     p2--------p3
+            *    /         /
+            *   /         /
+            *  p0--------p1
+            */
+            const float3& p0 = lamp->co;
+            const float3 axisu = lamp->axisu*(lamp->sizeu*lamp->size);
+            const float3 axisv = lamp->axisv*(lamp->sizev*lamp->size);
+            const float3 p1 = p0 + axisu;
+            const float3 p2 = p0 + axisv;
+            const float3 p3 = p0 + axisu + axisv;
+            bbox.grow(p0);
+            bbox.grow(p1);
+            bbox.grow(p2);
+            bbox.grow(p3);
+        } else if (lamp->type == LIGHT_BACKGROUND || lamp->type == LIGHT_DISTANT){
+            /* TODO: Can we support backgrounds and distant lights in the light
+             * tree? They do not have a bbox right?
+             */
+            return bbox;
+        } else {
+            assert(false);
         }
-        /* TODO: Handle all possible light sources here. */
-        bbox.grow(lamp->co);
     }
-
     return bbox;
 }
 
@@ -151,13 +171,16 @@ Orientation LightTree::get_bcone(const Primitive& prim){
         int lamp_id = -prim.prim_id-1;
         Light* lamp = lights[lamp_id];
         /* TODO: Make general. This is specific for point & spot lights */
-        bcone.axis = lamp->dir;
+        bcone.axis = lamp->dir / len(lamp->dir);
         if (lamp->type == LIGHT_POINT) {
             bcone.theta_o = M_PI_F;
             bcone.theta_e = M_PI_2_F;
         } else if (lamp->type == LIGHT_SPOT){
             bcone.theta_o = 0;
-            bcone.theta_e = lamp->spot_angle;
+            bcone.theta_e = lamp->spot_angle * 0.5f;
+        } else if (lamp->type == LIGHT_AREA){
+            bcone.theta_o = 0;
+            bcone.theta_e = M_PI_2_F;
         }
 
     }
@@ -170,7 +193,6 @@ float LightTree::get_energy(const Primitive &prim){
     float3 emission = make_float3(0.0f);
     Shader *shader = NULL;
 
-    /* extract shader for mesh light / normal light */
     if (prim.prim_id >= 0){
         /* extract bounding cone from emissive triangle */
         const Object* object = objects[prim.object_id];
@@ -179,22 +201,60 @@ float LightTree::get_energy(const Primitive &prim){
 
         int shader_index = mesh->shader[triangle_id];
         shader = mesh->used_shaders.at(shader_index);
+
+        /* get emission from shader */
+        bool is_constant_emission = shader->is_constant_emission(&emission);
+        if(!is_constant_emission){
+            return 1.0f;
+        }
+
+        const Transform& tfm = objects[prim.object_id]->tfm;
+        float area = mesh->compute_triangle_area(triangle_id, tfm);
+
+        emission *= area * M_PI_F;
+
     } else {
         assert(prim.object_id == -1);
         int lamp_id = -prim.prim_id-1;
-        shader = lights[lamp_id]->shader;
-    }
+        const Light* light = lights[lamp_id];
 
-    /* get emission from shader */
-    bool is_constant_emission = shader->is_constant_emission(&emission);
-    if(!is_constant_emission){
-        return 1.0f;
-    } else {
-        /* TODO: Convert float3 emission to float energy somehow.
-         * Convert to luminance? For now, do something stupid.
-         */
-        return emission[0] + emission[1] + emission[2];
+        /* get emission from shader */
+        shader = light->shader;
+        bool is_constant_emission = shader->is_constant_emission(&emission);
+        if(!is_constant_emission){
+            return 1.0f;
+        }
+
+        /* calculate the total emission by integrating the emission over the
+         * the entire sphere of directions. */
+        if (light->type == LIGHT_POINT){
+            emission *= M_4PI_F;
+        } else if (light->type == LIGHT_SPOT){
+            /* The emission is only non-zero within the cone and if spot_smooth
+             * is non-zero there will be a falloff. In this case, approximate
+             * the integral by considering a smaller cone without falloff. */
+            float spot_angle = light->spot_angle * 0.5f;
+            float spot_falloff_angle = spot_angle * (1.0f - light->spot_smooth);
+            float spot_middle_angle = (spot_angle + spot_falloff_angle) * 0.5f;
+            emission *= M_2PI_F * (1.0f - cosf(spot_middle_angle));
+        } else if (light->type == LIGHT_AREA){
+            float3 axisu = light->axisu*(light->sizeu*light->size);
+            float3 axisv = light->axisv*(light->sizev*light->size);
+            float area = len(axisu)*len(axisv);
+            emission *= area * M_PI_F;
+        } else {
+            // TODO: All light types are not supported yet
+            assert(false);
+        }
     }
+
+    /* convert RGB to luminance */
+    const float luminance = 0.212671f * emission[0] +
+                            0.715160f * emission[1] +
+                            0.072169f * emission[2];
+
+    return luminance;
+
 }
 
 Orientation LightTree::aggregate_bounding_cones(
diff --git a/intern/cycles/render/mesh.h b/intern/cycles/render/mesh.h
index e370f8a2021..eca18285323 100644
--- a/intern/cycles/render/mesh.h
+++ b/intern/cycles/render/mesh.h
@@ -84,6 +84,25 @@ public:
 		return tri;
 	}
 
+	float compute_triangle_area(size_t i, const Transform& tfm) const
+	{
+		Mesh::Triangle t = get_triangle(i);
+		if(!t.valid(&verts[0])) {
+			return 0.0f;
+		}
+		float3 p1 = verts[t.v[0]];
+		float3 p2 = verts[t.v[1]];
+		float3 p3 = verts[t.v[2]];
+
+		if(!transform_applied) {
+			p1 = transform_point(&tfm, p1);
+			p2 = transform_point(&tfm, p2);
+			p3 = transform_point(&tfm, p3);
+		}
+
+		return triangle_area(p1, p2, p3);
+	}
+
 	size_t num_triangles() const
 	{
 		return triangles.size() / 3;



More information about the Bf-blender-cvs mailing list