[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [53688] trunk/blender/intern/cycles: Cycles: multiple importance sampling for lamps, which helps reduce noise for

Brecht Van Lommel brechtvanlommel at pandora.be
Wed Jan 9 22:09:20 CET 2013


Revision: 53688
          http://projects.blender.org/scm/viewvc.php?view=rev&root=bf-blender&revision=53688
Author:   blendix
Date:     2013-01-09 21:09:20 +0000 (Wed, 09 Jan 2013)
Log Message:
-----------
Cycles: multiple importance sampling for lamps, which helps reduce noise for
big lamps and sharp glossy reflections. This was already supported for mesh
lights and the background, so lamps should do it too.

This is not for free and it's a bit slower than I hoped even though there is
no extra BVH ray intersection. I'll try to optimize it more later.

* Area lights look a bit different now, they had the wrong shape before.
* Also fixes a sampling issue in the non-progressive integrator.
* Only enabled for the CPU, will test on the GPU later.
* An option to disable this will be added for situations where it does not help.

Same time comparison before/after:
http://www.pasteall.org/pic/show.php?id=43313
http://www.pasteall.org/pic/show.php?id=43314

Modified Paths:
--------------
    trunk/blender/intern/cycles/blender/blender_object.cpp
    trunk/blender/intern/cycles/kernel/kernel_camera.h
    trunk/blender/intern/cycles/kernel/kernel_emission.h
    trunk/blender/intern/cycles/kernel/kernel_light.h
    trunk/blender/intern/cycles/kernel/kernel_path.h
    trunk/blender/intern/cycles/kernel/kernel_types.h
    trunk/blender/intern/cycles/kernel/osl/osl_services.cpp
    trunk/blender/intern/cycles/kernel/osl/osl_shader.cpp
    trunk/blender/intern/cycles/render/light.cpp
    trunk/blender/intern/cycles/util/util_math.h

Modified: trunk/blender/intern/cycles/blender/blender_object.cpp
===================================================================
--- trunk/blender/intern/cycles/blender/blender_object.cpp	2013-01-09 18:20:11 UTC (rev 53687)
+++ trunk/blender/intern/cycles/blender/blender_object.cpp	2013-01-09 21:09:20 UTC (rev 53688)
@@ -127,8 +127,8 @@
 		case BL::Lamp::type_AREA: {
 			BL::AreaLamp b_area_lamp(b_lamp);
 			light->size = 1.0f;
-			light->axisu = make_float3(tfm.x.x, tfm.y.x, tfm.z.x);
-			light->axisv = make_float3(tfm.x.y, tfm.y.y, tfm.z.y);
+			light->axisu = transform_get_column(&tfm, 0);
+			light->axisv = transform_get_column(&tfm, 1);
 			light->sizeu = b_area_lamp.size();
 			if(b_area_lamp.shape() == BL::AreaLamp::shape_RECTANGLE)
 				light->sizev = b_area_lamp.size_y();
@@ -140,8 +140,8 @@
 	}
 
 	/* location and (inverted!) direction */
-	light->co = make_float3(tfm.x.w, tfm.y.w, tfm.z.w);
-	light->dir = -make_float3(tfm.x.z, tfm.y.z, tfm.z.z);
+	light->co = transform_get_column(&tfm, 3);
+	light->dir = -transform_get_column(&tfm, 2);
 
 	/* shader */
 	vector<uint> used_shaders;

Modified: trunk/blender/intern/cycles/kernel/kernel_camera.h
===================================================================
--- trunk/blender/intern/cycles/kernel/kernel_camera.h	2013-01-09 18:20:11 UTC (rev 53687)
+++ trunk/blender/intern/cycles/kernel/kernel_camera.h	2013-01-09 21:09:20 UTC (rev 53688)
@@ -199,7 +199,6 @@
 
 	Pcamera = transform_perspective(&rastertocamera, make_float3(raster_x, raster_y + 1.0f, 0.0f));
 	ray->dD.dy = normalize(transform_direction(&cameratoworld, panorama_to_direction(kg, Pcamera.x, Pcamera.y))) - ray->D;
-
 #endif
 }
 

Modified: trunk/blender/intern/cycles/kernel/kernel_emission.h
===================================================================
--- trunk/blender/intern/cycles/kernel/kernel_emission.h	2013-01-09 18:20:11 UTC (rev 53687)
+++ trunk/blender/intern/cycles/kernel/kernel_emission.h	2013-01-09 21:09:20 UTC (rev 53688)
@@ -66,6 +66,8 @@
 		else
 			eval = make_float3(0.0f, 0.0f, 0.0f);
 	}
+	
+	eval *= ls->eval_fac;
 
 	shader_release(kg, &sd);
 
@@ -74,29 +76,29 @@
 
 __device bool direct_emission(KernelGlobals *kg, ShaderData *sd, int lindex,
 	float randt, float rando, float randu, float randv, Ray *ray, BsdfEval *eval,
-	bool *is_lamp)
+	int *lamp)
 {
 	LightSample ls;
 
-	float pdf = -1.0f;
-
 #ifdef __NON_PROGRESSIVE__
 	if(lindex != -1) {
 		/* sample position on a specified light */
-		light_select(kg, lindex, randu, randv, sd->P, &ls, &pdf);
+		light_select(kg, lindex, randu, randv, sd->P, &ls);
 	}
 	else
 #endif
 	{
 		/* sample a light and position on int */
-		light_sample(kg, randt, randu, randv, sd->time, sd->P, &ls, &pdf);
+		light_sample(kg, randt, randu, randv, sd->time, sd->P, &ls);
 	}
 
-	/* compute pdf */
-	if(pdf < 0.0f)
-		pdf = light_sample_pdf(kg, &ls, -ls.D, ls.t);
+	/* return lamp index for MIS */
+	if(ls.use_mis)
+		*lamp = ls.lamp;
+	else
+		*lamp= ~0;
 
-	if(pdf == 0.0f)
+	if(ls.pdf == 0.0f)
 		return false;
 
 	/* evaluate closure */
@@ -112,13 +114,13 @@
 
 	shader_bsdf_eval(kg, sd, ls.D, eval, &bsdf_pdf);
 
-	if(ls.prim != ~0 || ls.type == LIGHT_BACKGROUND) {
+	if(ls.use_mis) {
 		/* multiple importance sampling */
-		float mis_weight = power_heuristic(pdf, bsdf_pdf);
+		float mis_weight = power_heuristic(ls.pdf, bsdf_pdf);
 		light_eval *= mis_weight;
 	}
 	
-	bsdf_eval_mul(eval, light_eval*(ls.eval_fac/pdf));
+	bsdf_eval_mul(eval, light_eval/ls.pdf);
 
 	if(bsdf_eval_is_zero(eval))
 		return false;
@@ -144,14 +146,12 @@
 		ray->t = 0.0f;
 	}
 
-	*is_lamp = (ls.prim == ~0);
-
 	return true;
 }
 
-/* Indirect Emission */
+/* Indirect Primitive Emission */
 
-__device float3 indirect_emission(KernelGlobals *kg, ShaderData *sd, float t, int path_flag, float bsdf_pdf)
+__device float3 indirect_primitive_emission(KernelGlobals *kg, ShaderData *sd, float t, int path_flag, float bsdf_pdf)
 {
 	/* evaluate emissive closure */
 	float3 L = shader_emissive_eval(kg, sd);
@@ -172,6 +172,35 @@
 	return L;
 }
 
+/* Indirect Lamp Emission */
+
+__device bool indirect_lamp_emission(KernelGlobals *kg, Ray *ray, int path_flag, float bsdf_pdf, float randt, float3 *emission)
+{
+	LightSample ls;
+	int lamp = lamp_light_eval_sample(kg, randt);
+
+	if(lamp == ~0)
+		return false;
+
+	if(!lamp_light_eval(kg, lamp, ray->P, ray->D, ray->t, &ls))
+		return false;
+	
+	/* todo: missing texture coordinates */
+	float u = 0.0f;
+	float v = 0.0f;
+	float3 L = direct_emissive_eval(kg, 0.0f, &ls, u, v, -ray->D, ls.t, ray->time);
+
+	if(!(path_flag & PATH_RAY_MIS_SKIP)) {
+		/* multiple importance sampling, get regular light pdf,
+		 * and compute weight with respect to BSDF pdf */
+		float mis_weight = power_heuristic(bsdf_pdf, ls.pdf);
+		L *= mis_weight;
+	}
+
+	*emission = L;
+	return true;
+}
+
 /* Indirect Background */
 
 __device float3 indirect_background(KernelGlobals *kg, Ray *ray, int path_flag, float bsdf_pdf)

Modified: trunk/blender/intern/cycles/kernel/kernel_light.h
===================================================================
--- trunk/blender/intern/cycles/kernel/kernel_light.h	2013-01-09 18:20:11 UTC (rev 53687)
+++ trunk/blender/intern/cycles/kernel/kernel_light.h	2013-01-09 21:09:20 UTC (rev 53688)
@@ -18,49 +18,27 @@
 
 CCL_NAMESPACE_BEGIN
 
+/* Light Sample result */
+
 typedef struct LightSample {
-	float3 P;
-	float3 D;
-	float3 Ng;
-	float t;
-	float eval_fac;
-	int object;
-	int prim;
-	int shader;
-	LightType type;
+	float3 P;			/* position on light, or direction for distant light */
+	float3 Ng;			/* normal on light */
+	float3 D;			/* direction from shading point to light */
+	float t;			/* distance to light (FLT_MAX for distant light) */
+	float pdf;			/* light sampling probability density function */
+	float eval_fac;		/* intensity multiplier */
+	int object;			/* object id for triangle/curve lights */
+	int prim;			/* primitive id for triangle/curve ligths */
+	int shader;			/* shader id */
+	int lamp;			/* lamp id */
+	int use_mis;		/* for lamps with size zero */
+	LightType type;		/* type of light */
 } LightSample;
 
-/* Regular Light */
+/* Background Light */
 
-__device float3 disk_light_sample(float3 v, float randu, float randv)
-{
-	float3 ru, rv;
+#ifdef __BACKGROUND_MIS__
 
-	make_orthonormals(v, &ru, &rv);
-	to_unit_disk(&randu, &randv);
-
-	return ru*randu + rv*randv;
-}
-
-__device float3 distant_light_sample(float3 D, float size, float randu, float randv)
-{
-	return normalize(D + disk_light_sample(D, randu, randv)*size);
-}
-
-__device float3 sphere_light_sample(float3 P, float3 center, float size, float randu, float randv)
-{
-	return disk_light_sample(normalize(P - center), randu, randv)*size;
-}
-
-__device float3 area_light_sample(float3 axisu, float3 axisv, float randu, float randv)
-{
-	randu = randu - 0.5f;
-	randv = randv - 0.5f;
-
-	return axisu*randu + axisv*randv;
-}
-
-#ifdef __BACKGROUND_MIS__
 __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
@@ -169,33 +147,108 @@
 }
 #endif
 
-__device void regular_light_sample(KernelGlobals *kg, int point,
-	float randu, float randv, float3 P, LightSample *ls, float *pdf)
+/* Regular Light */
+
+__device float3 disk_light_sample(float3 v, float randu, float randv)
 {
-	float4 data0 = kernel_tex_fetch(__light_data, point*LIGHT_SIZE + 0);
-	float4 data1 = kernel_tex_fetch(__light_data, point*LIGHT_SIZE + 1);
+	float3 ru, rv;
 
+	make_orthonormals(v, &ru, &rv);
+	to_unit_disk(&randu, &randv);
+
+	return ru*randu + rv*randv;
+}
+
+__device float3 distant_light_sample(float3 D, float radius, float randu, float randv)
+{
+	return normalize(D + disk_light_sample(D, randu, randv)*radius);
+}
+
+__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;
+}
+
+__device float3 area_light_sample(float3 axisu, float3 axisv, float randu, float randv)
+{
+	randu = randu - 0.5f;
+	randv = randv - 0.5f;
+
+	return axisu*randu + axisv*randv;
+}
+
+__device float spot_light_attenuation(float4 data1, float4 data2, LightSample *ls)
+{
+	float3 dir = make_float3(data2.y, data2.z, data2.w);
+	float3 I = ls->Ng;
+
+	float spot_angle = data1.w;
+	float spot_smooth = data2.x;
+
+	float attenuation = dot(dir, I);
+
+	if(attenuation <= spot_angle) {
+		attenuation = 0.0f;
+	}
+	else {
+		float t = attenuation - spot_angle;
+
+		if(t < spot_smooth && spot_smooth != 0.0f)
+			attenuation *= smoothstepf(t/spot_smooth);
+	}
+
+	return attenuation;
+}
+
+__device float lamp_light_pdf(KernelGlobals *kg, const float3 Ng, const float3 I, float t)
+{
+	float cos_pi = dot(Ng, I);
+
+	if(cos_pi <= 0.0f)
+		return 0.0f;
+	
+	return t*t/cos_pi;
+}
+
+__device void lamp_light_sample(KernelGlobals *kg, int lamp,
+	float randu, float randv, float3 P, LightSample *ls)
+{
+	float4 data0 = kernel_tex_fetch(__light_data, lamp*LIGHT_SIZE + 0);
+	float4 data1 = kernel_tex_fetch(__light_data, lamp*LIGHT_SIZE + 1);
+
 	LightType type = (LightType)__float_as_int(data0.x);
 	ls->type = type;
+#ifdef __LAMP_MIS__
+	ls->use_mis = true;
+#else
+	ls->use_mis = false;
+#endif
 
 	if(type == LIGHT_DISTANT) {
 		/* distant light */
-		float3 D = make_float3(data0.y, data0.z, data0.w);
-		float size = data1.y;
+		float3 lightD = make_float3(data0.y, data0.z, data0.w);
+		float3 D = lightD;
+		float radius = data1.y;
+		float invarea = data1.w;
 
-		if(size > 0.0f)
-			D = distant_light_sample(D, size, randu, randv);
+		if(radius > 0.0f)
+			D = distant_light_sample(D, radius, randu, randv);
+		else
+			ls->use_mis = false;
 
 		ls->P = D;
 		ls->Ng = D;
 		ls->D = -D;
 		ls->t = FLT_MAX;
-		ls->eval_fac = 1.0f;
+
+		float costheta = dot(lightD, D);
+		ls->pdf = invarea/(costheta*costheta*costheta);
+		ls->eval_fac = ls->pdf;
 	}
 #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, pdf);
+		float3 D = background_light_sample(kg, randu, randv, &ls->pdf);
 
 		ls->P = D;
 		ls->Ng = D;
@@ -207,127 +260,240 @@
 	else {
 		ls->P = make_float3(data0.y, data0.z, data0.w);
 
-		if(type == LIGHT_POINT) {
-			float size = data1.y;
+		if(type == LIGHT_POINT || type == LIGHT_SPOT) {
+			float radius = data1.y;
 
-			/* sphere light */
-			if(size > 0.0f)
-				ls->P += sphere_light_sample(P, ls->P, size, randu, randv);
+			if(radius > 0.0f)

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list