Commit: b454416927f159f2397f1d4b0c12dab38e674a13 Author: Weizhen Huang Date: Thu Jan 26 16:17:08 2023 +0100 Branches: master https://developer.blender.org/rBb454416927f159f2397f1d4b0c12dab38e674a13
Cycles: add non-uniform scaling to spot light size Cycles ignores the size of spot lights, therefore the illuminated area doesn't match the gizmo. This patch resolves this discrepancy. | Before (Cycles) | After (Cycles) | Eevee |{F14200605}|{F14200595}|{F14200600}| This is done by scaling the ray direction by the size of the cone. The implementation of `spot_light_attenuation()` in `spot.h` matches `spot_attenuation()` in `lights_lib.glsl`. **Test file**: {F14200728} Differential Revision: https://developer.blender.org/D17129 =================================================================== M intern/cycles/blender/light.cpp M intern/cycles/kernel/light/spot.h M intern/cycles/kernel/svm/brick.h M intern/cycles/kernel/types.h M intern/cycles/scene/light.cpp M intern/cycles/scene/light_tree.cpp M intern/cycles/util/math.h =================================================================== diff --git a/intern/cycles/blender/light.cpp b/intern/cycles/blender/light.cpp index b8db4c24eb3..d5aba2041ad 100644 --- a/intern/cycles/blender/light.cpp +++ b/intern/cycles/blender/light.cpp @@ -48,6 +48,8 @@ void BlenderSync::sync_light(BL::Object &b_parent, case BL::Light::type_SPOT: { BL::SpotLight b_spot_light(b_light); light->set_size(b_spot_light.shadow_soft_size()); + light->set_axisu(transform_get_column(&tfm, 0)); + light->set_axisv(transform_get_column(&tfm, 1)); light->set_light_type(LIGHT_SPOT); light->set_spot_angle(b_spot_light.spot_size()); light->set_spot_smooth(b_spot_light.spot_blend()); diff --git a/intern/cycles/kernel/light/spot.h b/intern/cycles/kernel/light/spot.h index b1d652f13f9..1ffaebe7c17 100644 --- a/intern/cycles/kernel/light/spot.h +++ b/intern/cycles/kernel/light/spot.h @@ -7,24 +7,13 @@ CCL_NAMESPACE_BEGIN -ccl_device float spot_light_attenuation(float3 dir, - float cos_half_spot_angle, - float spot_smooth, - float3 N) +ccl_device float spot_light_attenuation(const ccl_global KernelSpotLight *spot, float3 ray) { - float attenuation = dot(dir, N); + const float3 scaled_ray = safe_normalize( + make_float3(dot(ray, spot->axis_u), dot(ray, spot->axis_v), dot(ray, spot->dir)) / + spot->len); - if (attenuation <= cos_half_spot_angle) { - attenuation = 0.0f; - } - else { - float t = attenuation - cos_half_spot_angle; - - if (t < spot_smooth && spot_smooth != 0.0f) - attenuation *= smoothstepf(t / spot_smooth); - } - - return attenuation; + return smoothstepf((scaled_ray.z - spot->cos_half_spot_angle) / spot->spot_smooth); } template<bool in_volume_segment> @@ -57,8 +46,7 @@ ccl_device_inline bool spot_light_sample(const ccl_global KernelLight *klight, ls->eval_fac = (0.25f * M_1_PI_F) * invarea; /* spot light attenuation */ - ls->eval_fac *= spot_light_attenuation( - klight->spot.dir, klight->spot.cos_half_spot_angle, klight->spot.spot_smooth, -ls->D); + ls->eval_fac *= spot_light_attenuation(&klight->spot, -ls->D); if (!in_volume_segment && ls->eval_fac == 0.0f) { return false; } @@ -87,8 +75,7 @@ ccl_device_forceinline void spot_light_update_position(const ccl_global KernelLi ls->pdf = invarea; /* spot light attenuation */ - ls->eval_fac *= spot_light_attenuation( - klight->spot.dir, klight->spot.cos_half_spot_angle, klight->spot.spot_smooth, ls->Ng); + ls->eval_fac *= spot_light_attenuation(&klight->spot, ls->Ng); } ccl_device_inline bool spot_light_intersect(const ccl_global KernelLight *klight, @@ -129,8 +116,7 @@ ccl_device_inline bool spot_light_sample_from_intersection( ls->pdf = invarea; /* spot light attenuation */ - ls->eval_fac *= spot_light_attenuation( - klight->spot.dir, klight->spot.cos_half_spot_angle, klight->spot.spot_smooth, -ls->D); + ls->eval_fac *= spot_light_attenuation(&klight->spot, -ls->D); if (ls->eval_fac == 0.0f) { return false; diff --git a/intern/cycles/kernel/svm/brick.h b/intern/cycles/kernel/svm/brick.h index f8fa4a4a84a..e64fc636334 100644 --- a/intern/cycles/kernel/svm/brick.h +++ b/intern/cycles/kernel/svm/brick.h @@ -46,17 +46,8 @@ ccl_device_noinline_cpu float2 svm_brick(float3 p, float tint = saturatef((brick_noise((rownum << 16) + (bricknum & 0xFFFF)) + bias)); float min_dist = min(min(x, y), min(brick_width - x, row_height - y)); - float mortar; - if (min_dist >= mortar_size) { - mortar = 0.0f; - } - else if (mortar_smooth == 0.0f) { - mortar = 1.0f; - } - else { - min_dist = 1.0f - min_dist / mortar_size; - mortar = (min_dist < mortar_smooth) ? smoothstepf(min_dist / mortar_smooth) : 1.0f; - } + min_dist = 1.0f - min_dist / mortar_size; + float mortar = smoothstepf(min_dist / mortar_smooth); return make_float2(tint, mortar); } diff --git a/intern/cycles/kernel/types.h b/intern/cycles/kernel/types.h index 4fad62d757d..cfbaba20ec1 100644 --- a/intern/cycles/kernel/types.h +++ b/intern/cycles/kernel/types.h @@ -1290,12 +1290,14 @@ typedef struct KernelCurveSegment { static_assert_align(KernelCurveSegment, 8); typedef struct KernelSpotLight { + packed_float3 axis_u; float radius; + packed_float3 axis_v; float invarea; + packed_float3 dir; float cos_half_spot_angle; + packed_float3 len; float spot_smooth; - packed_float3 dir; - float pad; } KernelSpotLight; /* PointLight is SpotLight with only radius and invarea being used. */ diff --git a/intern/cycles/scene/light.cpp b/intern/cycles/scene/light.cpp index fa710e8b250..3c5698b4218 100644 --- a/intern/cycles/scene/light.cpp +++ b/intern/cycles/scene/light.cpp @@ -1076,23 +1076,31 @@ void LightManager::device_update_lights(Device *device, DeviceScene *dscene, Sce else if (light->light_type == LIGHT_SPOT) { shader_id &= ~SHADER_AREA_LIGHT; + float3 len; + float3 axis_u = normalize_len(light->axisu, &len.x); + float3 axis_v = normalize_len(light->axisv, &len.y); + float3 dir = normalize_len(light->dir, &len.z); + if (len.z == 0.0f) { + dir = zero_float3(); + } + float radius = light->size; float invarea = (radius > 0.0f) ? 1.0f / (M_PI_F * radius * radius) : 1.0f; float cos_half_spot_angle = cosf(light->spot_angle * 0.5f); float spot_smooth = (1.0f - cos_half_spot_angle) * light->spot_smooth; - float3 dir = light->dir; - - dir = safe_normalize(dir); if (light->use_mis && radius > 0.0f) shader_id |= SHADER_USE_MIS; klights[light_index].co = co; + klights[light_index].spot.axis_u = axis_u; klights[light_index].spot.radius = radius; + klights[light_index].spot.axis_v = axis_v; klights[light_index].spot.invarea = invarea; + klights[light_index].spot.dir = dir; klights[light_index].spot.cos_half_spot_angle = cos_half_spot_angle; + klights[light_index].spot.len = len; klights[light_index].spot.spot_smooth = spot_smooth; - klights[light_index].spot.dir = dir; } klights[light_index].shader_id = shader_id; diff --git a/intern/cycles/scene/light_tree.cpp b/intern/cycles/scene/light_tree.cpp index 4fa4755479b..1261f09cda0 100644 --- a/intern/cycles/scene/light_tree.cpp +++ b/intern/cycles/scene/light_tree.cpp @@ -156,7 +156,13 @@ LightTreePrimitive::LightTreePrimitive(Scene *scene, int prim_id, int object_id) } else if (type == LIGHT_SPOT) { bcone.theta_o = 0; - bcone.theta_e = lamp->get_spot_angle() * 0.5f; + + const float unscaled_theta_e = lamp->get_spot_angle() * 0.5f; + const float len_u = len(lamp->get_axisu()); + const float len_v = len(lamp->get_axisv()); + const float len_w = len(lamp->get_dir()); + + bcone.theta_e = fast_atanf(fast_tanf(unscaled_theta_e) * fmaxf(len_u, len_v) / len_w); /* Point and spot lights can emit light from any point within its radius. */ const float3 radius = make_float3(size); diff --git a/intern/cycles/util/math.h b/intern/cycles/util/math.h index 3618daa4ccb..df75e7bf2b5 100644 --- a/intern/cycles/util/math.h +++ b/intern/cycles/util/math.h @@ -483,6 +483,12 @@ ccl_device_inline float compatible_signf(float f) ccl_device_inline float smoothstepf(float f) { + if (f <= 0.0f) { + return 0.0f; + } + if (f >= 1.0f) { + return 1.0f; + } float ff = f * f; return (3.0f * ff - 2.0f * ff * f); } _______________________________________________ Bf-blender-cvs mailing list Bf-blender-cvs@blender.org List details, subscription details or unsubscribe: https://lists.blender.org/mailman/listinfo/bf-blender-cvs