Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--intern/cycles/blender/blender_object.cpp8
-rw-r--r--intern/cycles/kernel/kernel_camera.h1
-rw-r--r--intern/cycles/kernel/kernel_emission.h61
-rw-r--r--intern/cycles/kernel/kernel_light.h467
-rw-r--r--intern/cycles/kernel/kernel_path.h78
-rw-r--r--intern/cycles/kernel/kernel_types.h6
-rw-r--r--intern/cycles/kernel/osl/osl_services.cpp8
-rw-r--r--intern/cycles/kernel/osl/osl_shader.cpp6
-rw-r--r--intern/cycles/render/light.cpp27
-rw-r--r--intern/cycles/util/util_math.h124
10 files changed, 586 insertions, 200 deletions
diff --git a/intern/cycles/blender/blender_object.cpp b/intern/cycles/blender/blender_object.cpp
index ad701266c5b..e9bcea70ab6 100644
--- a/intern/cycles/blender/blender_object.cpp
+++ b/intern/cycles/blender/blender_object.cpp
@@ -127,8 +127,8 @@ void BlenderSync::sync_light(BL::Object b_parent, int persistent_id[OBJECT_PERSI
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 @@ void BlenderSync::sync_light(BL::Object b_parent, int persistent_id[OBJECT_PERSI
}
/* 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;
diff --git a/intern/cycles/kernel/kernel_camera.h b/intern/cycles/kernel/kernel_camera.h
index 97d37a8b3f4..cd896ffe133 100644
--- a/intern/cycles/kernel/kernel_camera.h
+++ b/intern/cycles/kernel/kernel_camera.h
@@ -199,7 +199,6 @@ __device void camera_sample_panorama(KernelGlobals *kg, float raster_x, float ra
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
}
diff --git a/intern/cycles/kernel/kernel_emission.h b/intern/cycles/kernel/kernel_emission.h
index d5506ad1dd0..54bc0717b60 100644
--- a/intern/cycles/kernel/kernel_emission.h
+++ b/intern/cycles/kernel/kernel_emission.h
@@ -66,6 +66,8 @@ __device float3 direct_emissive_eval(KernelGlobals *kg, float rando,
else
eval = make_float3(0.0f, 0.0f, 0.0f);
}
+
+ eval *= ls->eval_fac;
shader_release(kg, &sd);
@@ -74,29 +76,29 @@ __device float3 direct_emissive_eval(KernelGlobals *kg, float rando,
__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 @@ __device bool direct_emission(KernelGlobals *kg, ShaderData *sd, int lindex,
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 @@ __device bool direct_emission(KernelGlobals *kg, ShaderData *sd, int lindex,
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 @@ __device float3 indirect_emission(KernelGlobals *kg, ShaderData *sd, float t, in
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)
diff --git a/intern/cycles/kernel/kernel_light.h b/intern/cycles/kernel/kernel_light.h
index ea0e4d014fe..df5acca6e65 100644
--- a/intern/cycles/kernel/kernel_light.h
+++ b/intern/cycles/kernel/kernel_light.h
@@ -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 */
-
-__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;
-}
-
-__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;
-}
+/* Background Light */
#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 @@ __device float background_light_pdf(KernelGlobals *kg, float3 direction)
}
#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)
+{
+ 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)
{
- float4 data0 = kernel_tex_fetch(__light_data, point*LIGHT_SIZE + 0);
- float4 data1 = kernel_tex_fetch(__light_data, point*LIGHT_SIZE + 1);
+ 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 @@ __device void regular_light_sample(KernelGlobals *kg, int point,
else {
ls->P = make_float3(data0.y, data0.z, data0.w);
- if(type == LIGHT_POINT) {
- float size = data1.y;
-
- /* sphere light */
- if(size > 0.0f)
- ls->P += sphere_light_sample(P, ls->P, size, randu, randv);
-
- ls->Ng = normalize(P - ls->P);
- ls->eval_fac = 0.25f*M_1_PI_F;
- }
- else if(type == LIGHT_SPOT) {
- float4 data2 = kernel_tex_fetch(__light_data, point*LIGHT_SIZE + 2);
- float size = data1.y;
-
- /* spot light */
- if(size > 0.0f)
- ls->P += sphere_light_sample(P, ls->P, size, randu, randv);
-
- float3 dir = make_float3(data1.z, data1.w, data2.x);
- float3 I = normalize(P - ls->P);
+ if(type == LIGHT_POINT || type == LIGHT_SPOT) {
+ float radius = data1.y;
- float spot_angle = data2.y;
- float spot_smooth = data2.z;
+ if(radius > 0.0f)
+ /* sphere light */
+ ls->P += sphere_light_sample(P, ls->P, radius, randu, randv);
+ else
+ ls->use_mis = false;
- float eval_fac = dot(dir, I);
+ ls->D = normalize_len(ls->P - P, &ls->t);
+ ls->Ng = -ls->D;
- if(eval_fac <= spot_angle) {
- eval_fac = 0.0f;
- }
- else {
- float t = eval_fac - spot_angle;
+ float invarea = data1.z;
+ ls->eval_fac = (0.25f*M_1_PI_F)*invarea;
+ ls->pdf = invarea;
- if(t < spot_smooth && spot_smooth != 0.0f)
- eval_fac *= smoothstepf(t/spot_smooth);
+ if(type == LIGHT_SPOT) {
+ /* spot light attentuation */
+ float4 data2 = kernel_tex_fetch(__light_data, lamp*LIGHT_SIZE + 2);
+ ls->eval_fac *= spot_light_attenuation(data1, data2, ls);
}
-
- ls->Ng = I;
- ls->eval_fac = eval_fac*0.25f*M_1_PI_F;
}
else {
/* area light */
- float4 data2 = kernel_tex_fetch(__light_data, point*LIGHT_SIZE + 2);
- float4 data3 = kernel_tex_fetch(__light_data, point*LIGHT_SIZE + 3);
+ float4 data2 = kernel_tex_fetch(__light_data, lamp*LIGHT_SIZE + 2);
+ float4 data3 = kernel_tex_fetch(__light_data, lamp*LIGHT_SIZE + 3);
- float3 axisu = make_float3(data1.y, data1.z, data2.w);
+ float3 axisu = make_float3(data1.y, data1.z, data1.w);
float3 axisv = make_float3(data2.y, data2.z, data2.w);
float3 D = make_float3(data3.y, data3.z, data3.w);
ls->P += area_light_sample(axisu, axisv, randu, randv);
ls->Ng = D;
- ls->eval_fac = 0.25f;
- }
+ ls->D = normalize_len(ls->P - P, &ls->t);
+
+ float invarea = data2.x;
- ls->t = 0.0f;
+ if(invarea == 0.0f) {
+ ls->use_mis = false;
+ invarea = 1.0f;
+ }
+
+ ls->pdf = invarea;
+ ls->eval_fac = 0.25f*ls->pdf;
+ }
}
ls->shader = __float_as_int(data1.x);
ls->object = ~0;
ls->prim = ~0;
+ ls->lamp = lamp;
+
+ /* compute pdf */
+ if(ls->t != FLT_MAX)
+ ls->pdf *= lamp_light_pdf(kg, ls->Ng, -ls->D, ls->t);
+
+ /* this is a bit weak, but we don't want this as part of the pdf for
+ * multiple importance sampling */
+ ls->eval_fac *= kernel_data.integrator.inv_pdf_lights;
}
-__device float regular_light_pdf(KernelGlobals *kg,
- const float3 Ng, const float3 I, float t)
+__device bool lamp_light_eval(KernelGlobals *kg, int lamp, float3 P, float3 D, float t, LightSample *ls)
{
- float pdf = kernel_data.integrator.pdf_lights;
+ float4 data0 = kernel_tex_fetch(__light_data, lamp*LIGHT_SIZE + 0);
+ float4 data1 = kernel_tex_fetch(__light_data, lamp*LIGHT_SIZE + 1);
- if(t == FLT_MAX)
- return pdf;
+ LightType type = (LightType)__float_as_int(data0.x);
+ ls->type = type;
+ ls->shader = __float_as_int(data1.x);
+ ls->object = ~0;
+ ls->prim = ~0;
+ ls->lamp = lamp;
+ ls->use_mis = false; /* flag not used for eval */
- float cos_pi = dot(Ng, I);
+ if(type == LIGHT_DISTANT) {
+ /* distant light */
+ float radius = data1.y;
+
+ if(radius == 0.0f)
+ return false;
+ if(t != FLT_MAX)
+ return false;
+
+ /* a distant light is infinitely far away, but equivalent to a disk
+ * shaped light exactly 1 unit away from the current shading point.
+ *
+ * radius t^2/cos(theta)
+ * <----------> t = sqrt(1^2 + tan(theta)^2)
+ * tan(th) area = radius*radius*pi
+ * <----->
+ * \ | (1 + tan(theta)^2)/cos(theta)
+ * \ | (1 + tan(acos(cos(theta)))^2)/cos(theta)
+ * t \th| 1 simplifies to
+ * \-| 1/(cos(theta)^3)
+ * \| magic!
+ * P
+ */
+
+ float3 lightD = make_float3(data0.y, data0.z, data0.w);
+ float costheta = dot(-lightD, D);
+ float cosangle = data1.z;
+
+ if(costheta < cosangle)
+ return false;
+
+ ls->P = -D;
+ ls->Ng = -D;
+ ls->D = D;
+ ls->t = FLT_MAX;
- if(cos_pi <= 0.0f)
- return 0.0f;
+ float invarea = data1.w;
+ ls->pdf = invarea/(costheta*costheta*costheta);
+ ls->eval_fac = ls->pdf;
+ }
+ else if(type == LIGHT_POINT || type == LIGHT_SPOT) {
+ float3 lightP = make_float3(data0.y, data0.z, data0.w);
+ float radius = data1.y;
- return t*t*pdf/cos_pi;
+ /* sphere light */
+ if(radius == 0.0f)
+ return false;
+
+ if(!ray_aligned_disk_intersect(P, D, t,
+ lightP, radius, &ls->P, &ls->t))
+ return false;
+
+ ls->Ng = -D;
+ ls->D = D;
+
+ float invarea = data1.z;
+ ls->eval_fac = (0.25f*M_1_PI_F)*invarea;
+ ls->pdf = invarea;
+
+ if(type == LIGHT_SPOT) {
+ /* spot light attentuation */
+ float4 data2 = kernel_tex_fetch(__light_data, lamp*LIGHT_SIZE + 2);
+ ls->eval_fac *= spot_light_attenuation(data1, data2, ls);
+
+ if(ls->eval_fac == 0.0f)
+ return false;
+ }
+ }
+ else if(type == LIGHT_AREA) {
+ /* area light */
+ float4 data2 = kernel_tex_fetch(__light_data, lamp*LIGHT_SIZE + 2);
+ float4 data3 = kernel_tex_fetch(__light_data, lamp*LIGHT_SIZE + 3);
+
+ float invarea = data2.x;
+ if(invarea == 0.0f)
+ return false;
+
+ float3 axisu = make_float3(data1.y, data1.z, data1.w);
+ float3 axisv = make_float3(data2.y, data2.z, data2.w);
+ float3 Ng = make_float3(data3.y, data3.z, data3.w);
+
+ /* one sided */
+ if(dot(D, Ng) >= 0.0f)
+ return false;
+
+ ls->P = make_float3(data0.y, data0.z, data0.w);
+
+ if(!ray_quad_intersect(P, D, t,
+ ls->P, axisu, axisv, &ls->P, &ls->t))
+ return false;
+
+ ls->D = D;
+ ls->Ng = Ng;
+ ls->pdf = invarea;
+ ls->eval_fac = 0.25f*ls->pdf;
+ }
+ else
+ return false;
+
+ /* compute pdf */
+ if(ls->t != FLT_MAX)
+ ls->pdf *= lamp_light_pdf(kg, ls->Ng, -ls->D, ls->t);
+ ls->eval_fac *= kernel_data.integrator.inv_pdf_lights;
+
+ return true;
}
/* Triangle Light */
-__device void triangle_light_sample(KernelGlobals *kg, int prim, int object,
- float randu, float randv, float time, LightSample *ls)
+__device void object_transform_light_sample(KernelGlobals *kg, LightSample *ls, int object, float time)
{
- /* triangle, so get position, normal, shader */
- ls->P = triangle_sample_MT(kg, prim, randu, randv);
- ls->Ng = triangle_normal_MT(kg, prim, &ls->shader);
- ls->object = object;
- ls->prim = prim;
- ls->t = 0.0f;
- ls->type = LIGHT_AREA;
- ls->eval_fac = 1.0f;
-
#ifdef __INSTANCING__
/* instance transform */
- if(ls->object >= 0) {
+ if(object >= 0) {
#ifdef __OBJECT_MOTION__
Transform itfm;
Transform tfm = object_fetch_transform_motion_test(kg, object, time, &itfm);
#else
- Transform tfm = object_fetch_transform(kg, ls->object, OBJECT_TRANSFORM);
- Transform itfm = object_fetch_transform(kg, ls->object, OBJECT_INVERSE_TRANSFORM);
+ Transform tfm = object_fetch_transform(kg, object, OBJECT_TRANSFORM);
+ Transform itfm = object_fetch_transform(kg, object, OBJECT_INVERSE_TRANSFORM);
#endif
ls->P = transform_point(&tfm, ls->P);
- ls->Ng = normalize(transform_direction_transposed(&itfm, ls->Ng));
+ ls->Ng = normalize(transform_direction(&tfm, ls->Ng));
}
#endif
}
+__device void triangle_light_sample(KernelGlobals *kg, int prim, int object,
+ float randu, float randv, float time, LightSample *ls)
+{
+ /* triangle, so get position, normal, shader */
+ ls->P = triangle_sample_MT(kg, prim, randu, randv);
+ ls->Ng = triangle_normal_MT(kg, prim, &ls->shader);
+ ls->object = object;
+ ls->prim = prim;
+ ls->lamp = ~0;
+ ls->use_mis = true;
+ ls->t = 0.0f;
+ ls->type = LIGHT_AREA;
+ ls->eval_fac = 1.0f;
+
+ object_transform_light_sample(kg, ls, object, time);
+}
+
__device float triangle_light_pdf(KernelGlobals *kg,
const float3 Ng, const float3 I, float t)
{
+ float pdf = kernel_data.integrator.pdf_triangles;
float cos_pi = fabsf(dot(Ng, I));
if(cos_pi == 0.0f)
return 0.0f;
- return (t*t*kernel_data.integrator.pdf_triangles)/cos_pi;
+ return t*t*pdf/cos_pi;
}
+/* Curve Light */
+
#ifdef __HAIR__
-/* Strand Light */
__device void curve_segment_light_sample(KernelGlobals *kg, int prim, int object,
int segment, float randu, float randv, float time, LightSample *ls)
@@ -358,27 +524,16 @@ __device void curve_segment_light_sample(KernelGlobals *kg, int prim, int object
ls->P = randu * l * tg + (gd * l + r1) * ls->Ng;
ls->object = object;
ls->prim = prim;
+ ls->lamp = ~0;
+ ls->use_mis = true;
ls->t = 0.0f;
ls->type = LIGHT_STRAND;
ls->eval_fac = 1.0f;
ls->shader = __float_as_int(v00.z);
-#ifdef __INSTANCING__
- /* instance transform */
- if(ls->object >= 0) {
-#ifdef __OBJECT_MOTION__
- Transform itfm;
- Transform tfm = object_fetch_transform_motion_test(kg, object, time, &itfm);
-#else
- Transform tfm = object_fetch_transform(kg, ls->object, OBJECT_TRANSFORM);
- Transform itfm = object_fetch_transform(kg, ls->object, OBJECT_INVERSE_TRANSFORM);
-#endif
-
- ls->P = transform_point(&tfm, ls->P);
- ls->Ng = normalize(transform_direction(&tfm, ls->Ng));
- }
-#endif
+ object_transform_light_sample(kg, ls, object, time);
}
+
#endif
/* Light Distribution */
@@ -412,7 +567,7 @@ __device int light_distribution_sample(KernelGlobals *kg, float randt)
/* Generic Light */
-__device void light_sample(KernelGlobals *kg, float randt, float randu, float randv, float time, float3 P, LightSample *ls, float *pdf)
+__device void light_sample(KernelGlobals *kg, float randt, float randu, float randv, float time, float3 P, LightSample *ls)
{
/* sample index */
int index = light_distribution_sample(kg, randt);
@@ -420,12 +575,12 @@ __device void light_sample(KernelGlobals *kg, float randt, float randu, float ra
/* fetch light data */
float4 l = kernel_tex_fetch(__light_distribution, index);
int prim = __float_as_int(l.y);
-#ifdef __HAIR__
- int segment = __float_as_int(l.z);
-#endif
if(prim >= 0) {
int object = __float_as_int(l.w);
+#ifdef __HAIR__
+ int segment = __float_as_int(l.z);
+#endif
#ifdef __HAIR__
if (segment != ~0)
@@ -433,27 +588,15 @@ __device void light_sample(KernelGlobals *kg, float randt, float randu, float ra
else
#endif
triangle_light_sample(kg, prim, object, randu, randv, time, ls);
+
+ /* compute incoming direction, distance and pdf */
+ ls->D = normalize_len(ls->P - P, &ls->t);
+ ls->pdf = triangle_light_pdf(kg, ls->Ng, -ls->D, ls->t);
}
else {
- int point = -prim-1;
- regular_light_sample(kg, point, randu, randv, P, ls, pdf);
+ int lamp = -prim-1;
+ lamp_light_sample(kg, lamp, randu, randv, P, ls);
}
-
- /* compute incoming direction and distance */
- if(ls->t != FLT_MAX)
- ls->D = normalize_len(ls->P - P, &ls->t);
-}
-
-__device float light_sample_pdf(KernelGlobals *kg, LightSample *ls, float3 I, float t)
-{
- float pdf;
-
- if(ls->prim != ~0)
- pdf = triangle_light_pdf(kg, ls->Ng, I, t);
- else
- pdf = regular_light_pdf(kg, ls->Ng, I, t);
-
- return pdf;
}
__device int light_select_num_samples(KernelGlobals *kg, int index)
@@ -462,18 +605,26 @@ __device int light_select_num_samples(KernelGlobals *kg, int index)
return __float_as_int(data3.x);
}
-__device void light_select(KernelGlobals *kg, int index, float randu, float randv, float3 P, LightSample *ls, float *pdf)
+__device void light_select(KernelGlobals *kg, int index, float randu, float randv, float3 P, LightSample *ls)
{
- regular_light_sample(kg, index, randu, randv, P, ls, pdf);
-
- /* compute incoming direction and distance */
- if(ls->t != FLT_MAX)
- ls->D = normalize_len(ls->P - P, &ls->t);
+ lamp_light_sample(kg, index, randu, randv, P, ls);
}
-__device float light_select_pdf(KernelGlobals *kg, LightSample *ls, float3 I, float t)
+__device int lamp_light_eval_sample(KernelGlobals *kg, float randt)
{
- return regular_light_pdf(kg, ls->Ng, I, t);
+ /* sample index */
+ int index = light_distribution_sample(kg, randt);
+
+ /* fetch light data */
+ float4 l = kernel_tex_fetch(__light_distribution, index);
+ int prim = __float_as_int(l.y);
+
+ if(prim < 0) {
+ int lamp = -prim-1;
+ return lamp;
+ }
+ else
+ return ~0;
}
CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/kernel_path.h b/intern/cycles/kernel/kernel_path.h
index 20feaf50a2e..87a10e8bba7 100644
--- a/intern/cycles/kernel/kernel_path.h
+++ b/intern/cycles/kernel/kernel_path.h
@@ -238,6 +238,7 @@ __device float4 kernel_path_progressive(KernelGlobals *kg, RNG *rng, int sample,
float min_ray_pdf = FLT_MAX;
float ray_pdf = 0.0f;
+ float ray_t = 0.0f;
PathState state;
int rng_offset = PRNG_BASE_NUM;
@@ -248,8 +249,29 @@ __device float4 kernel_path_progressive(KernelGlobals *kg, RNG *rng, int sample,
/* intersect scene */
Intersection isect;
uint visibility = path_state_ray_visibility(kg, &state);
+ bool hit = scene_intersect(kg, &ray, visibility, &isect);
- if(!scene_intersect(kg, &ray, visibility, &isect)) {
+#ifdef __LAMP_MIS__
+ if(kernel_data.integrator.pdf_lights > 0.0f && !(state.flag & PATH_RAY_CAMERA)) {
+ /* ray starting from previous non-transparent bounce */
+ Ray light_ray;
+
+ light_ray.P = ray.P - ray_t*ray.D;
+ ray_t += isect.t;
+ light_ray.D = ray.D;
+ light_ray.t = ray_t;
+ light_ray.time = ray.time;
+
+ /* intersect with lamp */
+ float light_t = path_rng(kg, rng, sample, rng_offset + PRNG_LIGHT);
+ float3 emission;
+
+ if(indirect_lamp_emission(kg, &light_ray, state.flag, ray_pdf, light_t, &emission))
+ path_radiance_accum_emission(&L, throughput, emission, state.bounce);
+ }
+#endif
+
+ if(!hit) {
/* eval background shader if nothing hit */
if(kernel_data.background.transparent && (state.flag & PATH_RAY_CAMERA)) {
L_transparent += average(throughput);
@@ -313,7 +335,8 @@ __device float4 kernel_path_progressive(KernelGlobals *kg, RNG *rng, int sample,
#ifdef __EMISSION__
/* emission */
if(sd.flag & SD_EMISSION) {
- float3 emission = indirect_emission(kg, &sd, isect.t, state.flag, ray_pdf);
+ /* todo: is isect.t wrong here for transparent surfaces? */
+ float3 emission = indirect_primitive_emission(kg, &sd, isect.t, state.flag, ray_pdf);
path_radiance_accum_emission(&L, throughput, emission, state.bounce);
}
#endif
@@ -374,18 +397,19 @@ __device float4 kernel_path_progressive(KernelGlobals *kg, RNG *rng, int sample,
Ray light_ray;
BsdfEval L_light;
- bool is_lamp;
+ int lamp;
#ifdef __OBJECT_MOTION__
light_ray.time = sd.time;
#endif
- if(direct_emission(kg, &sd, -1, light_t, light_o, light_u, light_v, &light_ray, &L_light, &is_lamp)) {
+ if(direct_emission(kg, &sd, -1, light_t, light_o, light_u, light_v, &light_ray, &L_light, &lamp)) {
/* trace shadow ray */
float3 shadow;
if(!shadow_blocked(kg, &state, &light_ray, &shadow)) {
/* accumulate */
+ bool is_lamp = (lamp != ~0);
path_radiance_accum_light(&L, throughput, &L_light, shadow, state.bounce, is_lamp);
}
}
@@ -422,6 +446,7 @@ __device float4 kernel_path_progressive(KernelGlobals *kg, RNG *rng, int sample,
/* set labels */
if(!(label & LABEL_TRANSPARENT)) {
ray_pdf = bsdf_pdf;
+ ray_t = 0.0f;
min_ray_pdf = fminf(bsdf_pdf, min_ray_pdf);
}
@@ -459,13 +484,36 @@ __device float4 kernel_path_progressive(KernelGlobals *kg, RNG *rng, int sample,
__device void kernel_path_indirect(KernelGlobals *kg, RNG *rng, int sample, Ray ray, __global float *buffer,
float3 throughput, float min_ray_pdf, float ray_pdf, PathState state, int rng_offset, PathRadiance *L)
{
+ float ray_t = 0.0f;
+
/* path iteration */
for(;; rng_offset += PRNG_BOUNCE_NUM) {
/* intersect scene */
Intersection isect;
uint visibility = path_state_ray_visibility(kg, &state);
+ bool hit = scene_intersect(kg, &ray, visibility, &isect);
- if(!scene_intersect(kg, &ray, visibility, &isect)) {
+#ifdef __LAMP_MIS__
+ if(kernel_data.integrator.pdf_lights > 0.0f && !(state.flag & PATH_RAY_CAMERA)) {
+ /* ray starting from previous non-transparent bounce */
+ Ray light_ray;
+
+ light_ray.P = ray.P - ray_t*ray.D;
+ ray_t += isect.t;
+ light_ray.D = ray.D;
+ light_ray.t = ray_t;
+ light_ray.time = ray.time;
+
+ /* intersect with lamp */
+ float light_t = path_rng(kg, rng, sample, rng_offset + PRNG_LIGHT);
+ float3 emission;
+
+ if(indirect_lamp_emission(kg, &light_ray, state.flag, ray_pdf, light_t, &emission))
+ path_radiance_accum_emission(L, throughput, emission, state.bounce);
+ }
+#endif
+
+ if(!hit) {
#ifdef __BACKGROUND__
/* sample background shader */
float3 L_background = indirect_background(kg, &ray, state.flag, ray_pdf);
@@ -496,7 +544,7 @@ __device void kernel_path_indirect(KernelGlobals *kg, RNG *rng, int sample, Ray
#ifdef __EMISSION__
/* emission */
if(sd.flag & SD_EMISSION) {
- float3 emission = indirect_emission(kg, &sd, isect.t, state.flag, ray_pdf);
+ float3 emission = indirect_primitive_emission(kg, &sd, isect.t, state.flag, ray_pdf);
path_radiance_accum_emission(L, throughput, emission, state.bounce);
}
#endif
@@ -557,19 +605,20 @@ __device void kernel_path_indirect(KernelGlobals *kg, RNG *rng, int sample, Ray
Ray light_ray;
BsdfEval L_light;
- bool is_lamp;
+ int lamp;
#ifdef __OBJECT_MOTION__
light_ray.time = sd.time;
#endif
/* sample random light */
- if(direct_emission(kg, &sd, -1, light_t, light_o, light_u, light_v, &light_ray, &L_light, &is_lamp)) {
+ if(direct_emission(kg, &sd, -1, light_t, light_o, light_u, light_v, &light_ray, &L_light, &lamp)) {
/* trace shadow ray */
float3 shadow;
if(!shadow_blocked(kg, &state, &light_ray, &shadow)) {
/* accumulate */
+ bool is_lamp = (lamp != ~0);
path_radiance_accum_light(L, throughput, &L_light, shadow, state.bounce, is_lamp);
}
}
@@ -606,6 +655,7 @@ __device void kernel_path_indirect(KernelGlobals *kg, RNG *rng, int sample, Ray
/* set labels */
if(!(label & LABEL_TRANSPARENT)) {
ray_pdf = bsdf_pdf;
+ ray_t = 0.0f;
min_ray_pdf = fminf(bsdf_pdf, min_ray_pdf);
}
@@ -697,7 +747,7 @@ __device float4 kernel_path_non_progressive(KernelGlobals *kg, RNG *rng, int sam
#ifdef __EMISSION__
/* emission */
if(sd.flag & SD_EMISSION) {
- float3 emission = indirect_emission(kg, &sd, isect.t, state.flag, ray_pdf);
+ float3 emission = indirect_primitive_emission(kg, &sd, isect.t, state.flag, ray_pdf);
path_radiance_accum_emission(&L, throughput, emission, state.bounce);
}
#endif
@@ -760,7 +810,7 @@ __device float4 kernel_path_non_progressive(KernelGlobals *kg, RNG *rng, int sam
if(sd.flag & SD_BSDF_HAS_EVAL) {
Ray light_ray;
BsdfEval L_light;
- bool is_lamp;
+ int lamp;
#ifdef __OBJECT_MOTION__
light_ray.time = sd.time;
@@ -778,12 +828,13 @@ __device float4 kernel_path_non_progressive(KernelGlobals *kg, RNG *rng, int sam
float light_u = path_rng(kg, rng, sample*num_samples + j, rng_offset + PRNG_LIGHT_U);
float light_v = path_rng(kg, rng, sample*num_samples + j, rng_offset + PRNG_LIGHT_V);
- if(direct_emission(kg, &sd, i, 0.0f, 0.0f, light_u, light_v, &light_ray, &L_light, &is_lamp)) {
+ if(direct_emission(kg, &sd, i, 0.0f, 0.0f, light_u, light_v, &light_ray, &L_light, &lamp)) {
/* trace shadow ray */
float3 shadow;
if(!shadow_blocked(kg, &state, &light_ray, &shadow)) {
/* accumulate */
+ bool is_lamp = (lamp != ~0);
path_radiance_accum_light(&L, throughput*num_samples_inv, &L_light, shadow, state.bounce, is_lamp);
}
}
@@ -807,12 +858,13 @@ __device float4 kernel_path_non_progressive(KernelGlobals *kg, RNG *rng, int sam
if(kernel_data.integrator.num_all_lights)
light_t = 0.5f*light_t;
- if(direct_emission(kg, &sd, -1, light_t, 0.0f, light_u, light_v, &light_ray, &L_light, &is_lamp)) {
+ if(direct_emission(kg, &sd, -1, light_t, 0.0f, light_u, light_v, &light_ray, &L_light, &lamp)) {
/* trace shadow ray */
float3 shadow;
if(!shadow_blocked(kg, &state, &light_ray, &shadow)) {
/* accumulate */
+ bool is_lamp = (lamp != ~0);
path_radiance_accum_light(&L, throughput*num_samples_inv, &L_light, shadow, state.bounce, is_lamp);
}
}
@@ -885,7 +937,7 @@ __device float4 kernel_path_non_progressive(KernelGlobals *kg, RNG *rng, int sam
bsdf_ray.time = sd.time;
#endif
- kernel_path_indirect(kg, rng, sample*num_samples, bsdf_ray, buffer,
+ kernel_path_indirect(kg, rng, sample*num_samples + j, bsdf_ray, buffer,
tp*num_samples_inv, min_ray_pdf, bsdf_pdf, ps, rng_offset+PRNG_BOUNCE_NUM, &L);
}
}
diff --git a/intern/cycles/kernel/kernel_types.h b/intern/cycles/kernel/kernel_types.h
index 2bd6b5859f3..102be440978 100644
--- a/intern/cycles/kernel/kernel_types.h
+++ b/intern/cycles/kernel/kernel_types.h
@@ -48,6 +48,7 @@ CCL_NAMESPACE_BEGIN
#endif
#define __NON_PROGRESSIVE__
#define __HAIR__
+#define __LAMP_MIS__
#endif
#ifdef __KERNEL_CUDA__
@@ -384,7 +385,7 @@ typedef enum AttributeStandard {
/* Closure data */
-#define MAX_CLOSURE 8
+#define MAX_CLOSURE 16
typedef struct ShaderClosure {
ClosureType type;
@@ -636,6 +637,7 @@ typedef struct KernelIntegrator {
int num_all_lights;
float pdf_triangles;
float pdf_lights;
+ float inv_pdf_lights;
int pdf_background_res;
/* bounces */
@@ -671,7 +673,7 @@ typedef struct KernelIntegrator {
int transmission_samples;
int ao_samples;
int mesh_light_samples;
- int pad1, pad2;
+ int pad1;
} KernelIntegrator;
typedef struct KernelBVH {
diff --git a/intern/cycles/kernel/osl/osl_services.cpp b/intern/cycles/kernel/osl/osl_services.cpp
index 28742d56e3b..92a023bd765 100644
--- a/intern/cycles/kernel/osl/osl_services.cpp
+++ b/intern/cycles/kernel/osl/osl_services.cpp
@@ -605,7 +605,11 @@ bool OSLRenderServices::get_object_standard_attribute(KernelGlobals *kg, ShaderD
return set_attribute_int(3, type, derivatives, val);
}
else if ((name == u_geom_trianglevertices || name == u_geom_polyvertices)
+#ifdef __HAIR__
&& sd->segment == ~0) {
+#else
+ ) {
+#endif
float3 P[3];
triangle_vertices(kg, sd->prim, P);
@@ -675,7 +679,11 @@ bool OSLRenderServices::get_attribute(void *renderstate, bool derivatives, ustri
else {
object = sd->object;
prim = sd->prim;
+#ifdef __HAIR__
segment = sd->segment;
+#else
+ segment = ~0;
+#endif
if (object == ~0)
return get_background_attribute(kg, sd, name, type, derivatives, val);
diff --git a/intern/cycles/kernel/osl/osl_shader.cpp b/intern/cycles/kernel/osl/osl_shader.cpp
index 59e307bb408..a32c526a2be 100644
--- a/intern/cycles/kernel/osl/osl_shader.cpp
+++ b/intern/cycles/kernel/osl/osl_shader.cpp
@@ -457,7 +457,11 @@ float3 OSLShader::volume_eval_phase(const ShaderClosure *sc, const float3 omega_
int OSLShader::find_attribute(KernelGlobals *kg, const ShaderData *sd, uint id, AttributeElement *elem)
{
/* for OSL, a hash map is used to lookup the attribute by name. */
- int object = sd->object*ATTR_PRIM_TYPES + (sd->segment != ~0);
+ int object = sd->object*ATTR_PRIM_TYPES;
+#ifdef __HAIR__
+ if(sd->segment != ~0) object += ATTR_PRIM_CURVE;
+#endif
+
OSLGlobals::AttributeMap &attr_map = kg->osl->attribute_map[object];
ustring stdname(std::string("geom:") + std::string(Attribute::standard_name((AttributeStandard)id)));
OSLGlobals::AttributeMap::const_iterator it = attr_map.find(stdname);
diff --git a/intern/cycles/render/light.cpp b/intern/cycles/render/light.cpp
index c8e3e94ec98..1b94d603a26 100644
--- a/intern/cycles/render/light.cpp
+++ b/intern/cycles/render/light.cpp
@@ -323,6 +323,7 @@ void LightManager::device_update_distribution(Device *device, DeviceScene *dscen
/* precompute pdfs */
kintegrator->pdf_triangles = 0.0f;
kintegrator->pdf_lights = 0.0f;
+ kintegrator->inv_pdf_lights = 0.0f;
/* sample one, with 0.5 probability of light or triangle */
kintegrator->num_all_lights = num_lights;
@@ -337,6 +338,8 @@ void LightManager::device_update_distribution(Device *device, DeviceScene *dscen
kintegrator->pdf_lights = 1.0f/num_lights;
if(trianglearea > 0.0f)
kintegrator->pdf_lights *= 0.5f;
+
+ kintegrator->inv_pdf_lights = 1.0f/kintegrator->pdf_lights;
}
/* CDF */
@@ -349,6 +352,7 @@ void LightManager::device_update_distribution(Device *device, DeviceScene *dscen
kintegrator->num_all_lights = 0;
kintegrator->pdf_triangles = 0.0f;
kintegrator->pdf_lights = 0.0f;
+ kintegrator->inv_pdf_lights = 0.0f;
}
}
@@ -475,16 +479,25 @@ void LightManager::device_update_points(Device *device, DeviceScene *dscene, Sce
if(light->type == LIGHT_POINT) {
shader_id &= ~SHADER_AREA_LIGHT;
+ float radius = light->size;
+ float invarea = (radius > 0.0f)? 1.0f/(M_PI_F*radius*radius): 1.0f;
+
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), light->size, 0.0f, 0.0f);
+ light_data[i*LIGHT_SIZE + 1] = make_float4(__int_as_float(shader_id), radius, invarea, 0.0f);
light_data[i*LIGHT_SIZE + 2] = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
light_data[i*LIGHT_SIZE + 3] = make_float4(samples, 0.0f, 0.0f, 0.0f);
}
else if(light->type == LIGHT_DISTANT) {
shader_id &= ~SHADER_AREA_LIGHT;
+ float radius = light->size;
+ float angle = atanf(radius);
+ float cosangle = cosf(angle);
+ float area = M_PI_F*radius*radius;
+ float invarea = (area > 0.0f)? 1.0f/area: 1.0f;
+
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), light->size, 0.0f, 0.0f);
+ 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);
}
@@ -499,21 +512,25 @@ void LightManager::device_update_points(Device *device, DeviceScene *dscene, Sce
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);
+ float invarea = (area > 0.0f)? 1.0f/area: 0.0f;
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(0.0f, axisv.x, axisv.y, axisv.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);
}
else if(light->type == LIGHT_SPOT) {
shader_id &= ~SHADER_AREA_LIGHT;
+ float radius = light->size;
+ float invarea = (radius > 0.0f)? 1.0f/(M_PI_F*radius*radius): 1.0f;
float spot_angle = cosf(light->spot_angle*0.5f);
float spot_smooth = (1.0f - spot_angle)*light->spot_smooth;
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), light->size, dir.x, dir.y);
- light_data[i*LIGHT_SIZE + 2] = make_float4(dir.z, spot_angle, spot_smooth, 0.0f);
+ 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);
}
}
diff --git a/intern/cycles/util/util_math.h b/intern/cycles/util/util_math.h
index 8932c85db07..c37fa1a4dc6 100644
--- a/intern/cycles/util/util_math.h
+++ b/intern/cycles/util/util_math.h
@@ -1161,6 +1161,130 @@ __device float safe_divide(float a, float b)
return result;
}
+/* Ray Intersection */
+
+__device bool ray_sphere_intersect(
+ float3 ray_P, float3 ray_D, float ray_t,
+ float3 sphere_P, float sphere_radius,
+ float3 *isect_P, float *isect_t)
+{
+ float3 d = sphere_P - ray_P;
+ float radiussq = sphere_radius*sphere_radius;
+ float tsq = dot(d, d);
+
+ if(tsq > radiussq) { /* ray origin outside sphere */
+ float tp = dot(d, ray_D);
+
+ if(tp < 0.0f) /* dir points away from sphere */
+ return false;
+
+ float dsq = tsq - tp*tp; /* pythagoras */
+
+ if(dsq > radiussq) /* closest point on ray outside sphere */
+ return false;
+
+ float t = tp - sqrtf(radiussq - dsq); /* pythagoras */
+
+ if(t < ray_t) {
+ *isect_t = t;
+ *isect_P = ray_P + ray_D*t;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+__device bool ray_aligned_disk_intersect(
+ float3 ray_P, float3 ray_D, float ray_t,
+ float3 disk_P, float disk_radius,
+ float3 *isect_P, float *isect_t)
+{
+ /* aligned disk normal */
+ float disk_t;
+ float3 disk_N = normalize_len(ray_P - disk_P, &disk_t);
+ float div = dot(ray_D, disk_N);
+
+ if(div == 0.0f)
+ return false;
+
+ /* compute t to intersection point */
+ float t = -disk_t/div;
+ if(t < 0.0f || t > ray_t)
+ return false;
+
+ /* test if within radius */
+ float3 P = ray_P + ray_D*t;
+ if(len_squared(P - disk_P) > disk_radius*disk_radius)
+ return false;
+
+ *isect_P = P;
+ *isect_t = t;
+
+ return true;
+}
+
+__device bool ray_triangle_intersect(
+ float3 ray_P, float3 ray_D, float ray_t,
+ float3 v0, float3 v1, float3 v2,
+ float3 *isect_P, float *isect_t)
+{
+ /* Calculate intersection */
+ float3 e1 = v1 - v0;
+ float3 e2 = v2 - v0;
+ float3 s1 = cross(ray_D, e2);
+
+ const float divisor = dot(s1, e1);
+ if(divisor == 0.0f)
+ return false;
+
+ const float invdivisor = 1.0f/divisor;
+
+ /* compute first barycentric coordinate */
+ const float3 d = ray_P - v0;
+ const float u = dot(d, s1)*invdivisor;
+ if(u < 0.0f)
+ return false;
+
+ /* Compute second barycentric coordinate */
+ const float3 s2 = cross(d, e1);
+ const float v = dot(ray_D, s2)*invdivisor;
+ if(v < 0.0f)
+ return false;
+
+ const float b0 = 1.0f - u - v;
+ if(b0 < 0.0f)
+ return false;
+
+ /* compute t to intersection point */
+ const float t = dot(e2, s2)*invdivisor;
+ if(t < 0.0f || t > ray_t)
+ return false;
+
+ *isect_t = t;
+ *isect_P = ray_P + ray_D*t;
+
+ return true;
+}
+
+__device bool ray_quad_intersect(
+ float3 ray_P, float3 ray_D, float ray_t,
+ float3 quad_P, float3 quad_u, float3 quad_v,
+ float3 *isect_P, float *isect_t)
+{
+ float3 v0 = quad_P - quad_u*0.5f - quad_v*0.5f;
+ float3 v1 = quad_P + quad_u*0.5f - quad_v*0.5f;
+ float3 v2 = quad_P + quad_u*0.5f + quad_v*0.5f;
+ float3 v3 = quad_P - quad_u*0.5f + quad_v*0.5f;
+
+ if(ray_triangle_intersect(ray_P, ray_D, ray_t, v0, v1, v2, isect_P, isect_t))
+ return true;
+ else if(ray_triangle_intersect(ray_P, ray_D, ray_t, v0, v2, v3, isect_P, isect_t))
+ return true;
+
+ return false;
+}
+
CCL_NAMESPACE_END
#endif /* __UTIL_MATH_H__ */