diff options
Diffstat (limited to 'intern/cycles/kernel/kernel_light.h')
-rw-r--r-- | intern/cycles/kernel/kernel_light.h | 49 |
1 files changed, 44 insertions, 5 deletions
diff --git a/intern/cycles/kernel/kernel_light.h b/intern/cycles/kernel/kernel_light.h index e9e7fbd4ca1..edc302cd6e3 100644 --- a/intern/cycles/kernel/kernel_light.h +++ b/intern/cycles/kernel/kernel_light.h @@ -23,6 +23,7 @@ typedef struct LightSample { float3 D; float3 Ng; float t; + float eval_fac; int object; int prim; int shader; @@ -63,8 +64,8 @@ __device float3 area_light_sample(float3 axisu, float3 axisv, float randu, float __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. */ + * 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; @@ -189,6 +190,7 @@ __device void regular_light_sample(KernelGlobals *kg, int point, ls->Ng = D; ls->D = -D; ls->t = FLT_MAX; + ls->eval_fac = 1.0f; } #ifdef __BACKGROUND_MIS__ else if(type == LIGHT_BACKGROUND) { @@ -199,6 +201,7 @@ __device void regular_light_sample(KernelGlobals *kg, int point, ls->Ng = D; ls->D = -D; ls->t = FLT_MAX; + ls->eval_fac = 1.0f; } #endif else { @@ -212,6 +215,36 @@ __device void regular_light_sample(KernelGlobals *kg, int point, 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); + + float spot_angle = data2.y; + float spot_smooth = data2.z; + + float eval_fac = dot(dir, I); + + if(eval_fac <= spot_angle) { + eval_fac = 0.0f; + } + else { + float t = eval_fac - spot_angle; + + if(t < spot_smooth && spot_smooth != 0.0f) + eval_fac *= smoothstepf(t/spot_smooth); + } + + ls->Ng = I; + ls->eval_fac = eval_fac*0.25f*M_1_PI_F; } else { /* area light */ @@ -224,6 +257,7 @@ __device void regular_light_sample(KernelGlobals *kg, int point, ls->P += area_light_sample(axisu, axisv, randu, randv); ls->Ng = D; + ls->eval_fac = 0.25f; } ls->t = 0.0f; @@ -262,6 +296,7 @@ __device void triangle_light_sample(KernelGlobals *kg, int prim, int object, ls->prim = prim; ls->t = 0.0f; ls->type = LIGHT_AREA; + ls->eval_fac = 1.0f; #ifdef __INSTANCING__ /* instance transform */ @@ -291,9 +326,9 @@ __device float triangle_light_pdf(KernelGlobals *kg, __device int light_distribution_sample(KernelGlobals *kg, float randt) { /* this is basically std::upper_bound as used by pbrt, to find a point light or - triangle to emit from, proportional to area. a good improvement would be to - also sample proportional to power, though it's not so well defined with - OSL shaders. */ + * triangle to emit from, proportional to area. a good improvement would be to + * also sample proportional to power, though it's not so well defined with + * OSL shaders. */ int first = 0; int len = kernel_data.integrator.num_distribution + 1; @@ -356,6 +391,10 @@ __device float light_sample_pdf(KernelGlobals *kg, LightSample *ls, float3 I, fl __device void light_select(KernelGlobals *kg, int index, float randu, float randv, float3 P, LightSample *ls, float *pdf) { 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); } __device float light_select_pdf(KernelGlobals *kg, LightSample *ls, float3 I, float t) |