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:
Diffstat (limited to 'intern/cycles/kernel/kernel_emission.h')
-rw-r--r--intern/cycles/kernel/kernel_emission.h374
1 files changed, 148 insertions, 226 deletions
diff --git a/intern/cycles/kernel/kernel_emission.h b/intern/cycles/kernel/kernel_emission.h
index aebf2ec8e28..d62285d173d 100644
--- a/intern/cycles/kernel/kernel_emission.h
+++ b/intern/cycles/kernel/kernel_emission.h
@@ -14,40 +14,36 @@
* limitations under the License.
*/
+#pragma once
+
+#include "kernel/kernel_light.h"
+#include "kernel/kernel_montecarlo.h"
+#include "kernel/kernel_path_state.h"
+#include "kernel/kernel_shader.h"
+
CCL_NAMESPACE_BEGIN
-/* Direction Emission */
-ccl_device_noinline_cpu float3 direct_emissive_eval(KernelGlobals *kg,
- ShaderData *emission_sd,
- LightSample *ls,
- ccl_addr_space PathState *state,
- float3 I,
- differential3 dI,
- float t,
- float time)
+/* Evaluate shader on light. */
+ccl_device_noinline_cpu float3 light_sample_shader_eval(INTEGRATOR_STATE_ARGS,
+ ShaderData *ccl_restrict emission_sd,
+ LightSample *ccl_restrict ls,
+ float time)
{
/* setup shading at emitter */
float3 eval = zero_float3();
if (shader_constant_emission_eval(kg, ls->shader, &eval)) {
- if ((ls->prim != PRIM_NONE) && dot(ls->Ng, I) < 0.0f) {
+ if ((ls->prim != PRIM_NONE) && dot(ls->Ng, ls->D) > 0.0f) {
ls->Ng = -ls->Ng;
}
}
else {
/* Setup shader data and call shader_eval_surface once, better
* for GPU coherence and compile times. */
+ PROFILING_INIT_FOR_SHADER(kg, PROFILING_SHADE_LIGHT_SETUP);
#ifdef __BACKGROUND_MIS__
if (ls->type == LIGHT_BACKGROUND) {
- Ray ray;
- ray.D = ls->D;
- ray.P = ls->P;
- ray.t = 1.0f;
- ray.time = time;
- ray.dP = differential3_zero();
- ray.dD = dI;
-
- shader_setup_from_background(kg, emission_sd, &ray);
+ shader_setup_from_background(kg, emission_sd, ls->P, ls->D, time);
}
else
#endif
@@ -56,13 +52,13 @@ ccl_device_noinline_cpu float3 direct_emissive_eval(KernelGlobals *kg,
emission_sd,
ls->P,
ls->Ng,
- I,
+ -ls->D,
ls->shader,
ls->object,
ls->prim,
ls->u,
ls->v,
- t,
+ ls->t,
time,
false,
ls->lamp);
@@ -70,11 +66,13 @@ ccl_device_noinline_cpu float3 direct_emissive_eval(KernelGlobals *kg,
ls->Ng = emission_sd->Ng;
}
+ PROFILING_SHADER(emission_sd->object, emission_sd->shader);
+ PROFILING_EVENT(PROFILING_SHADE_LIGHT_EVAL);
+
/* No proper path flag, we're evaluating this for all closures. that's
* weak but we'd have to do multiple evaluations otherwise. */
- path_state_modify_bounce(state, true);
- shader_eval_surface(kg, emission_sd, state, NULL, PATH_RAY_EMISSION);
- path_state_modify_bounce(state, false);
+ shader_eval_surface<KERNEL_FEATURE_NODE_MASK_SURFACE_LIGHT>(
+ INTEGRATOR_STATE_PASS, emission_sd, NULL, PATH_RAY_EMISSION);
/* Evaluate closures. */
#ifdef __BACKGROUND_MIS__
@@ -98,85 +96,129 @@ ccl_device_noinline_cpu float3 direct_emissive_eval(KernelGlobals *kg,
return eval;
}
-ccl_device_noinline_cpu bool direct_emission(KernelGlobals *kg,
- ShaderData *sd,
- ShaderData *emission_sd,
- LightSample *ls,
- ccl_addr_space PathState *state,
- Ray *ray,
- BsdfEval *eval,
- bool *is_lamp,
- float rand_terminate)
+/* Test if light sample is from a light or emission from geometry. */
+ccl_device_inline bool light_sample_is_light(const LightSample *ccl_restrict ls)
{
- if (ls->pdf == 0.0f)
- return false;
-
- /* todo: implement */
- differential3 dD = differential3_zero();
+ /* return if it's a lamp for shadow pass */
+ return (ls->prim == PRIM_NONE && ls->type != LIGHT_BACKGROUND);
+}
- /* evaluate closure */
+/* Early path termination of shadow rays. */
+ccl_device_inline bool light_sample_terminate(const KernelGlobals *ccl_restrict kg,
+ const LightSample *ccl_restrict ls,
+ BsdfEval *ccl_restrict eval,
+ const float rand_terminate)
+{
+ if (bsdf_eval_is_zero(eval)) {
+ return true;
+ }
- float3 light_eval = direct_emissive_eval(
- kg, emission_sd, ls, state, -ls->D, dD, ls->t, sd->time);
+ if (kernel_data.integrator.light_inv_rr_threshold > 0.0f) {
+ float probability = max3(fabs(bsdf_eval_sum(eval))) *
+ kernel_data.integrator.light_inv_rr_threshold;
+ if (probability < 1.0f) {
+ if (rand_terminate >= probability) {
+ return true;
+ }
+ bsdf_eval_mul(eval, 1.0f / probability);
+ }
+ }
- if (is_zero(light_eval))
- return false;
+ return false;
+}
- /* evaluate BSDF at shading point */
+/* This function should be used to compute a modified ray start position for
+ * rays leaving from a surface. The algorithm slightly distorts flat surface
+ * of a triangle. Surface is lifted by amount h along normal n in the incident
+ * point. */
-#ifdef __VOLUME__
- if (sd->prim != PRIM_NONE)
- shader_bsdf_eval(kg, sd, ls->D, eval, ls->pdf, ls->shader & SHADER_USE_MIS);
+ccl_device_inline float3 shadow_ray_smooth_surface_offset(const KernelGlobals *ccl_restrict kg,
+ const ShaderData *ccl_restrict sd,
+ float3 Ng)
+{
+ float3 V[3], N[3];
+ triangle_vertices_and_normals(kg, sd->prim, V, N);
+
+ const float u = sd->u, v = sd->v;
+ const float w = 1 - u - v;
+ float3 P = V[0] * u + V[1] * v + V[2] * w; /* Local space */
+ float3 n = N[0] * u + N[1] * v + N[2] * w; /* We get away without normalization */
+
+ object_normal_transform(kg, sd, &n); /* Normal x scale, world space */
+
+ /* Parabolic approximation */
+ float a = dot(N[2] - N[0], V[0] - V[2]);
+ float b = dot(N[2] - N[1], V[1] - V[2]);
+ float c = dot(N[1] - N[0], V[1] - V[0]);
+ float h = a * u * (u - 1) + (a + b + c) * u * v + b * v * (v - 1);
+
+ /* Check flipped normals */
+ if (dot(n, Ng) > 0) {
+ /* Local linear envelope */
+ float h0 = max(max(dot(V[1] - V[0], N[0]), dot(V[2] - V[0], N[0])), 0.0f);
+ float h1 = max(max(dot(V[0] - V[1], N[1]), dot(V[2] - V[1], N[1])), 0.0f);
+ float h2 = max(max(dot(V[0] - V[2], N[2]), dot(V[1] - V[2], N[2])), 0.0f);
+ h0 = max(dot(V[0] - P, N[0]) + h0, 0.0f);
+ h1 = max(dot(V[1] - P, N[1]) + h1, 0.0f);
+ h2 = max(dot(V[2] - P, N[2]) + h2, 0.0f);
+ h = max(min(min(h0, h1), h2), h * 0.5f);
+ }
else {
- float bsdf_pdf;
- shader_volume_phase_eval(kg, sd, ls->D, eval, &bsdf_pdf);
- if (ls->shader & SHADER_USE_MIS) {
- /* Multiple importance sampling. */
- float mis_weight = power_heuristic(ls->pdf, bsdf_pdf);
- light_eval *= mis_weight;
- }
+ float h0 = max(max(dot(V[0] - V[1], N[0]), dot(V[0] - V[2], N[0])), 0.0f);
+ float h1 = max(max(dot(V[1] - V[0], N[1]), dot(V[1] - V[2], N[1])), 0.0f);
+ float h2 = max(max(dot(V[2] - V[0], N[2]), dot(V[2] - V[1], N[2])), 0.0f);
+ h0 = max(dot(P - V[0], N[0]) + h0, 0.0f);
+ h1 = max(dot(P - V[1], N[1]) + h1, 0.0f);
+ h2 = max(dot(P - V[2], N[2]) + h2, 0.0f);
+ h = min(-min(min(h0, h1), h2), h * 0.5f);
}
-#else
- shader_bsdf_eval(kg, sd, ls->D, eval, ls->pdf, ls->shader & SHADER_USE_MIS);
-#endif
- bsdf_eval_mul3(eval, light_eval / ls->pdf);
-
-#ifdef __PASSES__
- /* use visibility flag to skip lights */
- if (ls->shader & SHADER_EXCLUDE_ANY) {
- if (ls->shader & SHADER_EXCLUDE_DIFFUSE)
- eval->diffuse = zero_float3();
- if (ls->shader & SHADER_EXCLUDE_GLOSSY)
- eval->glossy = zero_float3();
- if (ls->shader & SHADER_EXCLUDE_TRANSMIT)
- eval->transmission = zero_float3();
- if (ls->shader & SHADER_EXCLUDE_SCATTER)
- eval->volume = zero_float3();
- }
-#endif
+ return n * h;
+}
- if (bsdf_eval_is_zero(eval))
- return false;
+/* Ray offset to avoid shadow terminator artifact. */
- if (kernel_data.integrator.light_inv_rr_threshold > 0.0f
-#ifdef __SHADOW_TRICKS__
- && (state->flag & PATH_RAY_SHADOW_CATCHER) == 0
-#endif
- ) {
- float probability = max3(fabs(bsdf_eval_sum(eval))) *
- kernel_data.integrator.light_inv_rr_threshold;
- if (probability < 1.0f) {
- if (rand_terminate >= probability) {
- return false;
+ccl_device_inline float3 shadow_ray_offset(const KernelGlobals *ccl_restrict kg,
+ const ShaderData *ccl_restrict sd,
+ float3 L)
+{
+ float NL = dot(sd->N, L);
+ bool transmit = (NL < 0.0f);
+ float3 Ng = (transmit ? -sd->Ng : sd->Ng);
+ float3 P = ray_offset(sd->P, Ng);
+
+ if ((sd->type & PRIMITIVE_ALL_TRIANGLE) && (sd->shader & SHADER_SMOOTH_NORMAL)) {
+ const float offset_cutoff =
+ kernel_tex_fetch(__objects, sd->object).shadow_terminator_geometry_offset;
+ /* Do ray offset (heavy stuff) only for close to be terminated triangles:
+ * offset_cutoff = 0.1f means that 10-20% of rays will be affected. Also
+ * make a smooth transition near the threshold. */
+ if (offset_cutoff > 0.0f) {
+ float NgL = dot(Ng, L);
+ float offset_amount = 0.0f;
+ if (NL < offset_cutoff) {
+ offset_amount = clamp(2.0f - (NgL + NL) / offset_cutoff, 0.0f, 1.0f);
+ }
+ else {
+ offset_amount = clamp(1.0f - NgL / offset_cutoff, 0.0f, 1.0f);
+ }
+ if (offset_amount > 0.0f) {
+ P += shadow_ray_smooth_surface_offset(kg, sd, Ng) * offset_amount;
}
- bsdf_eval_mul(eval, 1.0f / probability);
}
}
+ return P;
+}
+
+ccl_device_inline void shadow_ray_setup(const ShaderData *ccl_restrict sd,
+ const LightSample *ccl_restrict ls,
+ const float3 P,
+ Ray *ray)
+{
if (ls->shader & SHADER_CAST_SHADOW) {
/* setup ray */
- ray->P = ray_offset_shadow(kg, sd, ls->D);
+ ray->P = P;
if (ls->t == FLT_MAX) {
/* distant light */
@@ -185,160 +227,40 @@ ccl_device_noinline_cpu bool direct_emission(KernelGlobals *kg,
}
else {
/* other lights, avoid self-intersection */
- ray->D = ray_offset(ls->P, ls->Ng) - ray->P;
+ ray->D = ray_offset(ls->P, ls->Ng) - P;
ray->D = normalize_len(ray->D, &ray->t);
}
-
- ray->dP = sd->dP;
- ray->dD = differential3_zero();
}
else {
/* signal to not cast shadow ray */
+ ray->P = zero_float3();
+ ray->D = zero_float3();
ray->t = 0.0f;
}
- /* return if it's a lamp for shadow pass */
- *is_lamp = (ls->prim == PRIM_NONE && ls->type != LIGHT_BACKGROUND);
-
- return true;
+ ray->dP = differential_make_compact(sd->dP);
+ ray->dD = differential_zero_compact();
+ ray->time = sd->time;
}
-/* Indirect Primitive Emission */
-
-ccl_device_noinline_cpu float3 indirect_primitive_emission(
- KernelGlobals *kg, ShaderData *sd, float t, int path_flag, float bsdf_pdf)
+/* Create shadow ray towards light sample. */
+ccl_device_inline void light_sample_to_surface_shadow_ray(const KernelGlobals *ccl_restrict kg,
+ const ShaderData *ccl_restrict sd,
+ const LightSample *ccl_restrict ls,
+ Ray *ray)
{
- /* evaluate emissive closure */
- float3 L = shader_emissive_eval(sd);
-
-#ifdef __HAIR__
- if (!(path_flag & PATH_RAY_MIS_SKIP) && (sd->flag & SD_USE_MIS) &&
- (sd->type & PRIMITIVE_ALL_TRIANGLE))
-#else
- if (!(path_flag & PATH_RAY_MIS_SKIP) && (sd->flag & SD_USE_MIS))
-#endif
- {
- /* multiple importance sampling, get triangle light pdf,
- * and compute weight with respect to BSDF pdf */
- float pdf = triangle_light_pdf(kg, sd, t);
- float mis_weight = power_heuristic(bsdf_pdf, pdf);
-
- return L * mis_weight;
- }
-
- return L;
+ const float3 P = shadow_ray_offset(kg, sd, ls->D);
+ shadow_ray_setup(sd, ls, P, ray);
}
-/* Indirect Lamp Emission */
-
-ccl_device_noinline_cpu void indirect_lamp_emission(KernelGlobals *kg,
- ShaderData *emission_sd,
- ccl_addr_space PathState *state,
- PathRadiance *L,
- Ray *ray,
- float3 throughput)
+/* Create shadow ray towards light sample. */
+ccl_device_inline void light_sample_to_volume_shadow_ray(const KernelGlobals *ccl_restrict kg,
+ const ShaderData *ccl_restrict sd,
+ const LightSample *ccl_restrict ls,
+ const float3 P,
+ Ray *ray)
{
- for (int lamp = 0; lamp < kernel_data.integrator.num_all_lights; lamp++) {
- LightSample ls ccl_optional_struct_init;
-
- if (!lamp_light_eval(kg, lamp, ray->P, ray->D, ray->t, &ls))
- continue;
-
-#ifdef __PASSES__
- /* use visibility flag to skip lights */
- if (ls.shader & SHADER_EXCLUDE_ANY) {
- if (((ls.shader & SHADER_EXCLUDE_DIFFUSE) && (state->flag & PATH_RAY_DIFFUSE)) ||
- ((ls.shader & SHADER_EXCLUDE_GLOSSY) &&
- ((state->flag & (PATH_RAY_GLOSSY | PATH_RAY_REFLECT)) ==
- (PATH_RAY_GLOSSY | PATH_RAY_REFLECT))) ||
- ((ls.shader & SHADER_EXCLUDE_TRANSMIT) && (state->flag & PATH_RAY_TRANSMIT)) ||
- ((ls.shader & SHADER_EXCLUDE_SCATTER) && (state->flag & PATH_RAY_VOLUME_SCATTER)))
- continue;
- }
-#endif
-
- float3 lamp_L = direct_emissive_eval(
- kg, emission_sd, &ls, state, -ray->D, ray->dD, ls.t, ray->time);
-
-#ifdef __VOLUME__
- if (state->volume_stack[0].shader != SHADER_NONE) {
- /* shadow attenuation */
- Ray volume_ray = *ray;
- volume_ray.t = ls.t;
- float3 volume_tp = one_float3();
- kernel_volume_shadow(kg, emission_sd, state, &volume_ray, &volume_tp);
- lamp_L *= volume_tp;
- }
-#endif
-
- if (!(state->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(state->ray_pdf, ls.pdf);
- lamp_L *= mis_weight;
- }
-
- path_radiance_accum_emission(kg, L, state, throughput, lamp_L);
- }
-}
-
-/* Indirect Background */
-
-ccl_device_noinline_cpu float3 indirect_background(KernelGlobals *kg,
- ShaderData *emission_sd,
- ccl_addr_space PathState *state,
- ccl_global float *buffer,
- ccl_addr_space Ray *ray)
-{
-#ifdef __BACKGROUND__
- int shader = kernel_data.background.surface_shader;
-
- /* Use visibility flag to skip lights. */
- if (shader & SHADER_EXCLUDE_ANY) {
- if (((shader & SHADER_EXCLUDE_DIFFUSE) && (state->flag & PATH_RAY_DIFFUSE)) ||
- ((shader & SHADER_EXCLUDE_GLOSSY) &&
- ((state->flag & (PATH_RAY_GLOSSY | PATH_RAY_REFLECT)) ==
- (PATH_RAY_GLOSSY | PATH_RAY_REFLECT))) ||
- ((shader & SHADER_EXCLUDE_TRANSMIT) && (state->flag & PATH_RAY_TRANSMIT)) ||
- ((shader & SHADER_EXCLUDE_CAMERA) && (state->flag & PATH_RAY_CAMERA)) ||
- ((shader & SHADER_EXCLUDE_SCATTER) && (state->flag & PATH_RAY_VOLUME_SCATTER)))
- return zero_float3();
- }
-
- /* Evaluate background shader. */
- float3 L = zero_float3();
- if (!shader_constant_emission_eval(kg, shader, &L)) {
-# ifdef __SPLIT_KERNEL__
- Ray priv_ray = *ray;
- shader_setup_from_background(kg, emission_sd, &priv_ray);
-# else
- shader_setup_from_background(kg, emission_sd, ray);
-# endif
-
- path_state_modify_bounce(state, true);
- shader_eval_surface(kg, emission_sd, state, buffer, state->flag | PATH_RAY_EMISSION);
- path_state_modify_bounce(state, false);
-
- L = shader_background_eval(emission_sd);
- }
-
- /* Background MIS weights. */
-# ifdef __BACKGROUND_MIS__
- /* Check if background light exists or if we should skip pdf. */
- if (!(state->flag & PATH_RAY_MIS_SKIP) && kernel_data.background.use_mis) {
- /* 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->P, ray->D);
- float mis_weight = power_heuristic(state->ray_pdf, pdf);
-
- return L * mis_weight;
- }
-# endif
-
- return L;
-#else
- return make_float3(0.8f, 0.8f, 0.8f);
-#endif
+ shadow_ray_setup(sd, ls, P, ray);
}
CCL_NAMESPACE_END