Changeset View
Changeset View
Standalone View
Standalone View
intern/cycles/kernel/kernel_light.h
| Show All 39 Lines | typedef struct LightSample { | ||||
| int shader; /* shader id */ | int shader; /* shader id */ | ||||
| int lamp; /* lamp id */ | int lamp; /* lamp id */ | ||||
| LightType type; /* type of light */ | LightType type; /* type of light */ | ||||
| } LightSample; | } LightSample; | ||||
| /* Regular Light */ | /* Regular Light */ | ||||
| template<bool in_volume_segment> | template<bool in_volume_segment> | ||||
| ccl_device_inline bool light_sample(ccl_global const KernelGlobals *kg, | ccl_device_inline bool light_sample(KernelGlobals kg, | ||||
| const int lamp, | const int lamp, | ||||
| const float randu, | const float randu, | ||||
| const float randv, | const float randv, | ||||
| const float3 P, | const float3 P, | ||||
| const int path_flag, | const int path_flag, | ||||
| ccl_private LightSample *ls) | ccl_private LightSample *ls) | ||||
| { | { | ||||
| const ccl_global KernelLight *klight = &kernel_tex_fetch(__lights, lamp); | const ccl_global KernelLight *klight = &kernel_tex_fetch(__lights, lamp); | ||||
| ▲ Show 20 Lines • Show All 147 Lines • ▼ Show 20 Lines | else { | ||||
| } | } | ||||
| } | } | ||||
| ls->pdf *= kernel_data.integrator.pdf_lights; | ls->pdf *= kernel_data.integrator.pdf_lights; | ||||
| return (ls->pdf > 0.0f); | return (ls->pdf > 0.0f); | ||||
| } | } | ||||
| ccl_device bool lights_intersect(ccl_global const KernelGlobals *ccl_restrict kg, | ccl_device bool lights_intersect(KernelGlobals kg, | ||||
| ccl_private const Ray *ccl_restrict ray, | ccl_private const Ray *ccl_restrict ray, | ||||
| ccl_private Intersection *ccl_restrict isect, | ccl_private Intersection *ccl_restrict isect, | ||||
| const int last_prim, | const int last_prim, | ||||
| const int last_object, | const int last_object, | ||||
| const int last_type, | const int last_type, | ||||
| const int path_flag) | const int path_flag) | ||||
| { | { | ||||
| for (int lamp = 0; lamp < kernel_data.integrator.num_all_lights; lamp++) { | for (int lamp = 0; lamp < kernel_data.integrator.num_all_lights; lamp++) { | ||||
| ▲ Show 20 Lines • Show All 72 Lines • ▼ Show 20 Lines | if (t < isect->t && | ||||
| isect->prim = lamp; | isect->prim = lamp; | ||||
| isect->object = OBJECT_NONE; | isect->object = OBJECT_NONE; | ||||
| } | } | ||||
| } | } | ||||
| return isect->prim != PRIM_NONE; | return isect->prim != PRIM_NONE; | ||||
| } | } | ||||
| ccl_device bool light_sample_from_distant_ray(ccl_global const KernelGlobals *ccl_restrict kg, | ccl_device bool light_sample_from_distant_ray(KernelGlobals kg, | ||||
| const float3 ray_D, | const float3 ray_D, | ||||
| const int lamp, | const int lamp, | ||||
| ccl_private LightSample *ccl_restrict ls) | ccl_private LightSample *ccl_restrict ls) | ||||
| { | { | ||||
| ccl_global const KernelLight *klight = &kernel_tex_fetch(__lights, lamp); | ccl_global const KernelLight *klight = &kernel_tex_fetch(__lights, lamp); | ||||
| const int shader = klight->shader_id; | const int shader = klight->shader_id; | ||||
| const float radius = klight->distant.radius; | const float radius = klight->distant.radius; | ||||
| const LightType type = (LightType)klight->type; | const LightType type = (LightType)klight->type; | ||||
| ▲ Show 20 Lines • Show All 47 Lines • ▼ Show 20 Lines | ccl_device bool light_sample_from_distant_ray(KernelGlobals kg, | ||||
| float invarea = klight->distant.invarea; | float invarea = klight->distant.invarea; | ||||
| ls->pdf = invarea / (costheta * costheta * costheta); | ls->pdf = invarea / (costheta * costheta * costheta); | ||||
| ls->pdf *= kernel_data.integrator.pdf_lights; | ls->pdf *= kernel_data.integrator.pdf_lights; | ||||
| ls->eval_fac = ls->pdf; | ls->eval_fac = ls->pdf; | ||||
| return true; | return true; | ||||
| } | } | ||||
| ccl_device bool light_sample_from_intersection(ccl_global const KernelGlobals *ccl_restrict kg, | ccl_device bool light_sample_from_intersection(KernelGlobals kg, | ||||
| ccl_private const Intersection *ccl_restrict isect, | ccl_private const Intersection *ccl_restrict isect, | ||||
| const float3 ray_P, | const float3 ray_P, | ||||
| const float3 ray_D, | const float3 ray_D, | ||||
| ccl_private LightSample *ccl_restrict ls) | ccl_private LightSample *ccl_restrict ls) | ||||
| { | { | ||||
| const int lamp = isect->prim; | const int lamp = isect->prim; | ||||
| ccl_global const KernelLight *klight = &kernel_tex_fetch(__lights, lamp); | ccl_global const KernelLight *klight = &kernel_tex_fetch(__lights, lamp); | ||||
| LightType type = (LightType)klight->type; | LightType type = (LightType)klight->type; | ||||
| ▲ Show 20 Lines • Show All 85 Lines • ▼ Show 20 Lines | ccl_device bool light_sample_from_intersection(KernelGlobals kg, | ||||
| return true; | return true; | ||||
| } | } | ||||
| /* Triangle Light */ | /* Triangle Light */ | ||||
| /* returns true if the triangle is has motion blur or an instancing transform applied */ | /* returns true if the triangle is has motion blur or an instancing transform applied */ | ||||
| ccl_device_inline bool triangle_world_space_vertices( | ccl_device_inline bool triangle_world_space_vertices( | ||||
| ccl_global const KernelGlobals *kg, int object, int prim, float time, float3 V[3]) | KernelGlobals kg, int object, int prim, float time, float3 V[3]) | ||||
| { | { | ||||
| bool has_motion = false; | bool has_motion = false; | ||||
| const int object_flag = kernel_tex_fetch(__object_flag, object); | const int object_flag = kernel_tex_fetch(__object_flag, object); | ||||
| if (object_flag & SD_OBJECT_HAS_VERTEX_MOTION && time >= 0.0f) { | if (object_flag & SD_OBJECT_HAS_VERTEX_MOTION && time >= 0.0f) { | ||||
| motion_triangle_vertices(kg, object, prim, time, V); | motion_triangle_vertices(kg, object, prim, time, V); | ||||
| has_motion = true; | has_motion = true; | ||||
| } | } | ||||
| Show All 11 Lines | #endif | ||||
| V[0] = transform_point(&tfm, V[0]); | V[0] = transform_point(&tfm, V[0]); | ||||
| V[1] = transform_point(&tfm, V[1]); | V[1] = transform_point(&tfm, V[1]); | ||||
| V[2] = transform_point(&tfm, V[2]); | V[2] = transform_point(&tfm, V[2]); | ||||
| has_motion = true; | has_motion = true; | ||||
| } | } | ||||
| return has_motion; | return has_motion; | ||||
| } | } | ||||
| ccl_device_inline float triangle_light_pdf_area(ccl_global const KernelGlobals *kg, | ccl_device_inline float triangle_light_pdf_area(KernelGlobals kg, | ||||
| const float3 Ng, | const float3 Ng, | ||||
| const float3 I, | const float3 I, | ||||
| float t) | float t) | ||||
| { | { | ||||
| float pdf = kernel_data.integrator.pdf_triangles; | float pdf = kernel_data.integrator.pdf_triangles; | ||||
| float cos_pi = fabsf(dot(Ng, I)); | float cos_pi = fabsf(dot(Ng, I)); | ||||
| if (cos_pi == 0.0f) | if (cos_pi == 0.0f) | ||||
| return 0.0f; | return 0.0f; | ||||
| return t * t * pdf / cos_pi; | return t * t * pdf / cos_pi; | ||||
| } | } | ||||
| ccl_device_forceinline float triangle_light_pdf(ccl_global const KernelGlobals *kg, | ccl_device_forceinline float triangle_light_pdf(KernelGlobals kg, | ||||
| ccl_private const ShaderData *sd, | ccl_private const ShaderData *sd, | ||||
| float t) | float t) | ||||
| { | { | ||||
| /* A naive heuristic to decide between costly solid angle sampling | /* A naive heuristic to decide between costly solid angle sampling | ||||
| * and simple area sampling, comparing the distance to the triangle plane | * and simple area sampling, comparing the distance to the triangle plane | ||||
| * to the length of the edges of the triangle. */ | * to the length of the edges of the triangle. */ | ||||
| float3 V[3]; | float3 V[3]; | ||||
| ▲ Show 20 Lines • Show All 55 Lines • ▼ Show 20 Lines | if (has_motion) { | ||||
| const float area_pre = triangle_area(V[0], V[1], V[2]); | const float area_pre = triangle_area(V[0], V[1], V[2]); | ||||
| pdf = pdf * area_pre / area; | pdf = pdf * area_pre / area; | ||||
| } | } | ||||
| return pdf; | return pdf; | ||||
| } | } | ||||
| } | } | ||||
| template<bool in_volume_segment> | template<bool in_volume_segment> | ||||
| ccl_device_forceinline void triangle_light_sample(ccl_global const KernelGlobals *kg, | ccl_device_forceinline void triangle_light_sample(KernelGlobals kg, | ||||
| int prim, | int prim, | ||||
| int object, | int object, | ||||
| float randu, | float randu, | ||||
| float randv, | float randv, | ||||
| float time, | float time, | ||||
| ccl_private LightSample *ls, | ccl_private LightSample *ls, | ||||
| const float3 P) | const float3 P) | ||||
| { | { | ||||
| ▲ Show 20 Lines • Show All 152 Lines • ▼ Show 20 Lines | else { | ||||
| } | } | ||||
| ls->u = u; | ls->u = u; | ||||
| ls->v = v; | ls->v = v; | ||||
| } | } | ||||
| } | } | ||||
| /* Light Distribution */ | /* Light Distribution */ | ||||
| ccl_device int light_distribution_sample(ccl_global const KernelGlobals *kg, | ccl_device int light_distribution_sample(KernelGlobals kg, ccl_private float *randu) | ||||
| ccl_private float *randu) | |||||
| { | { | ||||
| /* This is basically std::upper_bound as used by PBRT, to find a point light or | /* 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 | * 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 | * also sample proportional to power, though it's not so well defined with | ||||
| * arbitrary shaders. */ | * arbitrary shaders. */ | ||||
| int first = 0; | int first = 0; | ||||
| int len = kernel_data.integrator.num_distribution + 1; | int len = kernel_data.integrator.num_distribution + 1; | ||||
| float r = *randu; | float r = *randu; | ||||
| Show All 21 Lines | ccl_device int light_distribution_sample(KernelGlobals kg, ccl_private float *randu) | ||||
| float distr_max = kernel_tex_fetch(__light_distribution, index + 1).totarea; | float distr_max = kernel_tex_fetch(__light_distribution, index + 1).totarea; | ||||
| *randu = (r - distr_min) / (distr_max - distr_min); | *randu = (r - distr_min) / (distr_max - distr_min); | ||||
| return index; | return index; | ||||
| } | } | ||||
| /* Generic Light */ | /* Generic Light */ | ||||
| ccl_device_inline bool light_select_reached_max_bounces(ccl_global const KernelGlobals *kg, | ccl_device_inline bool light_select_reached_max_bounces(KernelGlobals kg, int index, int bounce) | ||||
| int index, | |||||
| int bounce) | |||||
| { | { | ||||
| return (bounce > kernel_tex_fetch(__lights, index).max_bounces); | return (bounce > kernel_tex_fetch(__lights, index).max_bounces); | ||||
| } | } | ||||
| template<bool in_volume_segment> | template<bool in_volume_segment> | ||||
| ccl_device_noinline bool light_distribution_sample(ccl_global const KernelGlobals *kg, | ccl_device_noinline bool light_distribution_sample(KernelGlobals kg, | ||||
| float randu, | float randu, | ||||
| const float randv, | const float randv, | ||||
| const float time, | const float time, | ||||
| const float3 P, | const float3 P, | ||||
| const int bounce, | const int bounce, | ||||
| const int path_flag, | const int path_flag, | ||||
| ccl_private LightSample *ls) | ccl_private LightSample *ls) | ||||
| { | { | ||||
| Show All 23 Lines | ccl_device_noinline bool light_distribution_sample(KernelGlobals kg, | ||||
| if (UNLIKELY(light_select_reached_max_bounces(kg, lamp, bounce))) { | if (UNLIKELY(light_select_reached_max_bounces(kg, lamp, bounce))) { | ||||
| return false; | return false; | ||||
| } | } | ||||
| return light_sample<in_volume_segment>(kg, lamp, randu, randv, P, path_flag, ls); | return light_sample<in_volume_segment>(kg, lamp, randu, randv, P, path_flag, ls); | ||||
| } | } | ||||
| ccl_device_inline bool light_distribution_sample_from_volume_segment( | ccl_device_inline bool light_distribution_sample_from_volume_segment(KernelGlobals kg, | ||||
| ccl_global const KernelGlobals *kg, | |||||
| float randu, | float randu, | ||||
| const float randv, | const float randv, | ||||
| const float time, | const float time, | ||||
| const float3 P, | const float3 P, | ||||
| const int bounce, | const int bounce, | ||||
| const int path_flag, | const int path_flag, | ||||
| ccl_private LightSample *ls) | ccl_private LightSample *ls) | ||||
| { | { | ||||
| return light_distribution_sample<true>(kg, randu, randv, time, P, bounce, path_flag, ls); | return light_distribution_sample<true>(kg, randu, randv, time, P, bounce, path_flag, ls); | ||||
| } | } | ||||
| ccl_device_inline bool light_distribution_sample_from_position(ccl_global const KernelGlobals *kg, | ccl_device_inline bool light_distribution_sample_from_position(KernelGlobals kg, | ||||
| float randu, | float randu, | ||||
| const float randv, | const float randv, | ||||
| const float time, | const float time, | ||||
| const float3 P, | const float3 P, | ||||
| const int bounce, | const int bounce, | ||||
| const int path_flag, | const int path_flag, | ||||
| ccl_private LightSample *ls) | ccl_private LightSample *ls) | ||||
| { | { | ||||
| return light_distribution_sample<false>(kg, randu, randv, time, P, bounce, path_flag, ls); | return light_distribution_sample<false>(kg, randu, randv, time, P, bounce, path_flag, ls); | ||||
| } | } | ||||
| ccl_device_inline bool light_distribution_sample_new_position(ccl_global const KernelGlobals *kg, | ccl_device_inline bool light_distribution_sample_new_position(KernelGlobals kg, | ||||
| const float randu, | const float randu, | ||||
| const float randv, | const float randv, | ||||
| const float time, | const float time, | ||||
| const float3 P, | const float3 P, | ||||
| ccl_private LightSample *ls) | ccl_private LightSample *ls) | ||||
| { | { | ||||
| /* Sample a new position on the same light, for volume sampling. */ | /* Sample a new position on the same light, for volume sampling. */ | ||||
| if (ls->type == LIGHT_TRIANGLE) { | if (ls->type == LIGHT_TRIANGLE) { | ||||
| Show All 9 Lines | |||||