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/addon/ui.py4
-rw-r--r--intern/cycles/blender/blender_object.cpp22
-rw-r--r--intern/cycles/kernel/kernel_light.h180
-rw-r--r--intern/cycles/render/light.cpp13
-rw-r--r--intern/cycles/render/light.h1
-rw-r--r--intern/cycles/util/util_math_intersect.h22
-rw-r--r--release/scripts/startup/bl_ui/properties_data_lamp.py8
-rw-r--r--release/scripts/startup/bl_ui/space_view3d.py2
-rw-r--r--source/blender/draw/engines/eevee/eevee_lights.c13
-rw-r--r--source/blender/draw/engines/eevee/eevee_private.h3
-rw-r--r--source/blender/draw/engines/eevee/shaders/bsdf_direct_lib.glsl30
-rw-r--r--source/blender/draw/engines/eevee/shaders/lamps_lib.glsl31
-rw-r--r--source/blender/draw/engines/eevee/shaders/volumetric_lib.glsl5
-rw-r--r--source/blender/draw/intern/draw_cache.c42
-rw-r--r--source/blender/draw/intern/draw_cache.h3
-rw-r--r--source/blender/draw/modes/object_mode.c19
-rw-r--r--source/blender/editors/object/object_transform.c4
-rw-r--r--source/blender/editors/space_view3d/view3d_manipulator_lamp.c12
-rw-r--r--source/blender/makesdna/DNA_lamp_types.h2
-rw-r--r--source/blender/makesrna/intern/rna_lamp.c2
20 files changed, 298 insertions, 120 deletions
diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py
index eeb059f79f1..ff8ca0adc18 100644
--- a/intern/cycles/blender/addon/ui.py
+++ b/intern/cycles/blender/addon/ui.py
@@ -909,9 +909,9 @@ class CYCLES_LAMP_PT_lamp(CyclesButtonsPanel, Panel):
col.prop(lamp, "shape", text="")
sub = col.column(align=True)
- if lamp.shape == 'SQUARE':
+ if lamp.shape in {'SQUARE', 'DISK'}:
sub.prop(lamp, "size")
- elif lamp.shape == 'RECTANGLE':
+ elif lamp.shape in {'RECTANGLE', 'ELLIPSE'}:
sub.prop(lamp, "size", text="Size X")
sub.prop(lamp, "size_y", text="Size Y")
diff --git a/intern/cycles/blender/blender_object.cpp b/intern/cycles/blender/blender_object.cpp
index d0df8e1800f..090682c8e14 100644
--- a/intern/cycles/blender/blender_object.cpp
+++ b/intern/cycles/blender/blender_object.cpp
@@ -162,10 +162,24 @@ void BlenderSync::sync_light(BL::Object& b_parent,
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();
- else
- light->sizev = light->sizeu;
+ switch(b_area_lamp.shape()) {
+ case BL::AreaLamp::shape_SQUARE:
+ light->sizev = light->sizeu;
+ light->round = false;
+ break;
+ case BL::AreaLamp::shape_RECTANGLE:
+ light->sizev = b_area_lamp.size_y();
+ light->round = false;
+ break;
+ case BL::AreaLamp::shape_DISK:
+ light->sizev = light->sizeu;
+ light->round = true;
+ break;
+ case BL::AreaLamp::shape_ELLIPSE:
+ light->sizev = b_area_lamp.size_y();
+ light->round = true;
+ break;
+ }
light->type = LIGHT_AREA;
break;
}
diff --git a/intern/cycles/kernel/kernel_light.h b/intern/cycles/kernel/kernel_light.h
index efab69ee37d..cd879e27e72 100644
--- a/intern/cycles/kernel/kernel_light.h
+++ b/intern/cycles/kernel/kernel_light.h
@@ -44,7 +44,7 @@ typedef struct LightSample {
*
* Note: light_p is modified when sample_coord is true.
*/
-ccl_device_inline float area_light_sample(float3 P,
+ccl_device_inline float rect_light_sample(float3 P,
float3 *light_p,
float3 axisu, float3 axisv,
float randu, float randv,
@@ -125,6 +125,60 @@ ccl_device_inline float area_light_sample(float3 P,
return 0.0f;
}
+ccl_device_inline float3 ellipse_sample(float3 ru, float3 rv, float randu, float randv)
+{
+ to_unit_disk(&randu, &randv);
+ return ru*randu + rv*randv;
+}
+
+ccl_device float3 disk_light_sample(float3 v, float randu, float randv)
+{
+ float3 ru, rv;
+
+ make_orthonormals(v, &ru, &rv);
+
+ return ellipse_sample(ru, rv, randu, randv);
+}
+
+ccl_device float3 distant_light_sample(float3 D, float radius, float randu, float randv)
+{
+ return normalize(D + disk_light_sample(D, randu, randv)*radius);
+}
+
+ccl_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;
+}
+
+ccl_device float spot_light_attenuation(float3 dir, float spot_angle, float spot_smooth, LightSample *ls)
+{
+ float3 I = ls->Ng;
+
+ 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;
+}
+
+ccl_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;
+}
+
/* Background Light */
#ifdef __BACKGROUND_MIS__
@@ -295,11 +349,19 @@ ccl_device_inline float background_portal_pdf(KernelGlobals *kg,
const ccl_global KernelLight *klight = &kernel_tex_fetch(__lights, portal);
float3 axisu = make_float3(klight->area.axisu[0], klight->area.axisu[1], klight->area.axisu[2]);
float3 axisv = make_float3(klight->area.axisv[0], klight->area.axisv[1], klight->area.axisv[2]);
+ bool is_round = (klight->area.invarea < 0.0f);
- if(!ray_quad_intersect(P, direction, 1e-4f, FLT_MAX, lightpos, axisu, axisv, dir, NULL, NULL, NULL, NULL))
+ if(!ray_quad_intersect(P, direction, 1e-4f, FLT_MAX, lightpos, axisu, axisv, dir, NULL, NULL, NULL, NULL, is_round))
continue;
- portal_pdf += area_light_sample(P, &lightpos, axisu, axisv, 0.0f, 0.0f, false);
+ if(is_round) {
+ float t;
+ float3 D = normalize_len(lightpos - P, &t);
+ portal_pdf += fabsf(klight->area.invarea) * lamp_light_pdf(kg, dir, -D, t);
+ }
+ else {
+ portal_pdf += rect_light_sample(P, &lightpos, axisu, axisv, 0.0f, 0.0f, false);
+ }
}
if(ignore_portal >= 0) {
@@ -349,15 +411,26 @@ ccl_device float3 background_portal_sample(KernelGlobals *kg,
const ccl_global KernelLight *klight = &kernel_tex_fetch(__lights, portal);
float3 axisu = make_float3(klight->area.axisu[0], klight->area.axisu[1], klight->area.axisu[2]);
float3 axisv = make_float3(klight->area.axisv[0], klight->area.axisv[1], klight->area.axisv[2]);
-
- *pdf = area_light_sample(P, &lightpos,
- axisu, axisv,
- randu, randv,
- true);
+ bool is_round = (klight->area.invarea < 0.0f);
+
+ float3 D;
+ if(is_round) {
+ lightpos += ellipse_sample(axisu*0.5f, axisv*0.5f, randu, randv);
+ float t;
+ D = normalize_len(lightpos - P, &t);
+ *pdf = fabsf(klight->area.invarea) * lamp_light_pdf(kg, dir, -D, t);
+ }
+ else {
+ *pdf = rect_light_sample(P, &lightpos,
+ axisu, axisv,
+ randu, randv,
+ true);
+ D = normalize(lightpos - P);
+ }
*pdf /= num_possible;
*sampled_portal = p;
- return normalize(lightpos - P);
+ return D;
}
portal--;
@@ -458,55 +531,6 @@ ccl_device float background_light_pdf(KernelGlobals *kg, float3 P, float3 direct
/* Regular Light */
-ccl_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;
-}
-
-ccl_device float3 distant_light_sample(float3 D, float radius, float randu, float randv)
-{
- return normalize(D + disk_light_sample(D, randu, randv)*radius);
-}
-
-ccl_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;
-}
-
-ccl_device float spot_light_attenuation(float3 dir, float spot_angle, float spot_smooth, LightSample *ls)
-{
- float3 I = ls->Ng;
-
- 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;
-}
-
-ccl_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;
-}
-
ccl_device_inline bool lamp_light_sample(KernelGlobals *kg,
int lamp,
float randu, float randv,
@@ -601,26 +625,39 @@ ccl_device_inline bool lamp_light_sample(KernelGlobals *kg,
float3 D = make_float3(klight->area.dir[0],
klight->area.dir[1],
klight->area.dir[2]);
+ float invarea = fabsf(klight->area.invarea);
+ bool is_round = (klight->area.invarea < 0.0f);
if(dot(ls->P - P, D) > 0.0f) {
return false;
}
- float3 inplane = ls->P;
- ls->pdf = area_light_sample(P, &ls->P,
- axisu, axisv,
- randu, randv,
- true);
+ float3 inplane;
+
+ if(is_round) {
+ inplane = ellipse_sample(axisu*0.5f, axisv*0.5f, randu, randv);
+ ls->P += inplane;
+ ls->pdf = invarea;
+ }
+ else {
+ inplane = ls->P;
+ ls->pdf = rect_light_sample(P, &ls->P,
+ axisu, axisv,
+ randu, randv,
+ true);
+ inplane = ls->P - inplane;
+ }
- inplane = ls->P - inplane;
ls->u = dot(inplane, axisu) * (1.0f / dot(axisu, axisu)) + 0.5f;
ls->v = dot(inplane, axisv) * (1.0f / dot(axisv, axisv)) + 0.5f;
ls->Ng = D;
ls->D = normalize_len(ls->P - P, &ls->t);
- float invarea = klight->area.invarea;
ls->eval_fac = 0.25f*invarea;
+ if(is_round) {
+ ls->pdf *= lamp_light_pdf(kg, D, -ls->D, ls->t);
+ }
}
}
@@ -731,7 +768,8 @@ ccl_device bool lamp_light_eval(KernelGlobals *kg, int lamp, float3 P, float3 D,
}
else if(type == LIGHT_AREA) {
/* area light */
- float invarea = klight->area.invarea;
+ float invarea = fabsf(klight->area.invarea);
+ bool is_round = (klight->area.invarea < 0.0f);
if(invarea == 0.0f)
return false;
@@ -754,14 +792,20 @@ ccl_device bool lamp_light_eval(KernelGlobals *kg, int lamp, float3 P, float3 D,
if(!ray_quad_intersect(P, D, 0.0f, t, light_P,
axisu, axisv, Ng,
&ls->P, &ls->t,
- &ls->u, &ls->v))
+ &ls->u, &ls->v,
+ is_round))
{
return false;
}
ls->D = D;
ls->Ng = Ng;
- ls->pdf = area_light_sample(P, &light_P, axisu, axisv, 0, 0, false);
+ if(is_round) {
+ ls->pdf = invarea * lamp_light_pdf(kg, Ng, -D, ls->t);
+ }
+ else {
+ ls->pdf = rect_light_sample(P, &light_P, axisu, axisv, 0, 0, false);
+ }
ls->eval_fac = 0.25f*invarea;
}
else {
diff --git a/intern/cycles/render/light.cpp b/intern/cycles/render/light.cpp
index 8dec7e4ea64..01a8b50cb21 100644
--- a/intern/cycles/render/light.cpp
+++ b/intern/cycles/render/light.cpp
@@ -117,6 +117,7 @@ NODE_DEFINE(Light)
SOCKET_FLOAT(sizeu, "Size U", 1.0f);
SOCKET_VECTOR(axisv, "Axis V", make_float3(0.0f, 0.0f, 0.0f));
SOCKET_FLOAT(sizev, "Size V", 1.0f);
+ SOCKET_BOOLEAN(round, "Round", false);
SOCKET_INT(map_resolution, "Map Resolution", 512);
@@ -730,12 +731,15 @@ void LightManager::device_update_points(Device *,
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: 1.0f;
+ if(light->round) {
+ area *= -M_PI_4_F;
+ }
+ float invarea = (area != 0.0f)? 1.0f/area: 1.0f;
float3 dir = light->dir;
dir = safe_normalize(dir);
- if(light->use_mis && area > 0.0f)
+ if(light->use_mis && area != 0.0f)
shader_id |= SHADER_USE_MIS;
klights[light_index].co[0] = co.x;
@@ -803,7 +807,10 @@ void LightManager::device_update_points(Device *,
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: 1.0f;
+ if(light->round) {
+ area *= -M_PI_4_F;
+ }
+ float invarea = (area != 0.0f)? 1.0f/area: 1.0f;
float3 dir = light->dir;
dir = safe_normalize(dir);
diff --git a/intern/cycles/render/light.h b/intern/cycles/render/light.h
index 97b7b971c73..539a33f4e41 100644
--- a/intern/cycles/render/light.h
+++ b/intern/cycles/render/light.h
@@ -49,6 +49,7 @@ public:
float sizeu;
float3 axisv;
float sizev;
+ bool round;
Transform tfm;
diff --git a/intern/cycles/util/util_math_intersect.h b/intern/cycles/util/util_math_intersect.h
index 61ddcc38f50..5f15487df57 100644
--- a/intern/cycles/util/util_math_intersect.h
+++ b/intern/cycles/util/util_math_intersect.h
@@ -186,12 +186,17 @@ ccl_device_forceinline bool ray_triangle_intersect(
#undef dot3
}
+/* Tests for an intersection between a ray and a quad defined by
+ * its midpoint, normal and sides.
+ * If ellipse is true, hits outside the ellipse that's enclosed by the
+ * quad are rejected.
+ */
ccl_device bool ray_quad_intersect(float3 ray_P, float3 ray_D,
float ray_mint, float ray_maxt,
float3 quad_P,
float3 quad_u, float3 quad_v, float3 quad_n,
float3 *isect_P, float *isect_t,
- float *isect_u, float *isect_v)
+ float *isect_u, float *isect_v, bool ellipse)
{
/* Perform intersection test. */
float t = -(dot(ray_P, quad_n) - dot(quad_P, quad_n)) / dot(ray_D, quad_n);
@@ -200,20 +205,23 @@ ccl_device bool ray_quad_intersect(float3 ray_P, float3 ray_D,
}
const float3 hit = ray_P + t*ray_D;
const float3 inplane = hit - quad_P;
- const float u = dot(inplane, quad_u) / dot(quad_u, quad_u) + 0.5f;
- if(u < 0.0f || u > 1.0f) {
+ const float u = dot(inplane, quad_u) / dot(quad_u, quad_u);
+ if(u < -0.5f || u > 0.5f) {
+ return false;
+ }
+ const float v = dot(inplane, quad_v) / dot(quad_v, quad_v);
+ if(v < -0.5f || v > 0.5f) {
return false;
}
- const float v = dot(inplane, quad_v) / dot(quad_v, quad_v) + 0.5f;
- if(v < 0.0f || v > 1.0f) {
+ if(ellipse && (u*u + v*v > 0.25f)) {
return false;
}
/* Store the result. */
/* TODO(sergey): Check whether we can avoid some checks here. */
if(isect_P != NULL) *isect_P = hit;
if(isect_t != NULL) *isect_t = t;
- if(isect_u != NULL) *isect_u = u;
- if(isect_v != NULL) *isect_v = v;
+ if(isect_u != NULL) *isect_u = u + 0.5f;
+ if(isect_v != NULL) *isect_v = v + 0.5f;
return true;
}
diff --git a/release/scripts/startup/bl_ui/properties_data_lamp.py b/release/scripts/startup/bl_ui/properties_data_lamp.py
index 1d7e5807b34..2e3dae25197 100644
--- a/release/scripts/startup/bl_ui/properties_data_lamp.py
+++ b/release/scripts/startup/bl_ui/properties_data_lamp.py
@@ -136,9 +136,9 @@ class DATA_PT_EEVEE_lamp(DataButtonsPanel, Panel):
elif lamp.type == 'AREA':
sub = sub.column(align=True)
sub.prop(lamp, "shape", text="")
- if lamp.shape == 'SQUARE':
+ if lamp.shape in {'SQUARE', 'DISK'}:
sub.prop(lamp, "size")
- elif lamp.shape == 'RECTANGLE':
+ elif lamp.shape in {'RECTANGLE', 'ELLIPSE'}:
sub.prop(lamp, "size", text="Size X")
sub.prop(lamp, "size_y", text="Size Y")
@@ -228,9 +228,9 @@ class DATA_PT_area(DataButtonsPanel, Panel):
col.row().prop(lamp, "shape", expand=True)
sub = col.row(align=True)
- if lamp.shape == 'SQUARE':
+ if lamp.shape in {'SQUARE', 'DISK'}:
sub.prop(lamp, "size")
- elif lamp.shape == 'RECTANGLE':
+ elif lamp.shape in {'RECTANGLE', 'ELLIPSE'}:
sub.prop(lamp, "size", text="Size X")
sub.prop(lamp, "size_y", text="Size Y")
diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py
index 1edee555eb6..2ebea02ed21 100644
--- a/release/scripts/startup/bl_ui/space_view3d.py
+++ b/release/scripts/startup/bl_ui/space_view3d.py
@@ -1591,7 +1591,7 @@ class VIEW3D_MT_object_specials(Menu):
props.data_path_item = "data.size"
props.header_text = "Lamp Size X: %.3f"
- if lamp.shape == 'RECTANGLE':
+ if lamp.shape in {'RECTANGLE', 'ELLIPSE'}:
props = layout.operator("wm.context_modal_mouse", text="Size Y")
props.data_path_iter = "selected_editable_objects"
props.data_path_item = "data.size_y"
diff --git a/source/blender/draw/engines/eevee/eevee_lights.c b/source/blender/draw/engines/eevee/eevee_lights.c
index 123dabbe226..9f3295e7095 100644
--- a/source/blender/draw/engines/eevee/eevee_lights.c
+++ b/source/blender/draw/engines/eevee/eevee_lights.c
@@ -591,7 +591,7 @@ static void eevee_light_setup(Object *ob, EEVEE_Light *evli)
}
else if (la->type == LA_AREA) {
evli->sizex = max_ff(0.0001f, la->area_size * scale[0] * 0.5f);
- if (la->area_shape == LA_AREA_RECT) {
+ if (ELEM(la->area_shape, LA_AREA_RECT, LA_AREA_ELLIPSE)) {
evli->sizey = max_ff(0.0001f, la->area_sizey * scale[1] * 0.5f);
}
else {
@@ -602,10 +602,18 @@ static void eevee_light_setup(Object *ob, EEVEE_Light *evli)
evli->radius = max_ff(0.001f, la->area_size);
}
+ /* Lamp Type */
+ evli->lamptype = (float)la->type;
+
/* Make illumination power constant */
if (la->type == LA_AREA) {
power = 1.0f / (evli->sizex * evli->sizey * 4.0f * M_PI) * /* 1/(w*h*Pi) */
80.0f; /* XXX : Empirical, Fit cycles power */
+ if (ELEM(la->area_shape, LA_AREA_DISK, LA_AREA_ELLIPSE)) {
+ evli->lamptype = LAMPTYPE_AREA_ELLIPSE;
+ /* Scale power to account for the lower area of the ellipse compared to the surrouding rectangle. */
+ power *= 4.0f / M_PI;
+ }
}
else if (la->type == LA_SPOT || la->type == LA_LOCAL) {
power = 1.0f / (4.0f * evli->radius * evli->radius * M_PI * M_PI) * /* 1/(4*r²*Pi²) */
@@ -620,9 +628,6 @@ static void eevee_light_setup(Object *ob, EEVEE_Light *evli)
}
mul_v3_fl(evli->color, power * la->energy);
- /* Lamp Type */
- evli->lamptype = (float)la->type;
-
/* No shadow by default */
evli->shadowid = -1.0f;
}
diff --git a/source/blender/draw/engines/eevee/eevee_private.h b/source/blender/draw/engines/eevee/eevee_private.h
index c95e51548d0..a5f4f6d85a8 100644
--- a/source/blender/draw/engines/eevee/eevee_private.h
+++ b/source/blender/draw/engines/eevee/eevee_private.h
@@ -289,6 +289,9 @@ typedef struct EEVEE_Light {
float forwardvec[3], lamptype;
} EEVEE_Light;
+/* Special type for elliptic area lamps, matches lamps_lib.glsl */
+#define LAMPTYPE_AREA_ELLIPSE 100.0f
+
typedef struct EEVEE_Shadow {
float near, far, bias, exp;
float shadow_start, data_start, multi_shadow_count, shadow_blur;
diff --git a/source/blender/draw/engines/eevee/shaders/bsdf_direct_lib.glsl b/source/blender/draw/engines/eevee/shaders/bsdf_direct_lib.glsl
index d5b54097638..aad71b3e48e 100644
--- a/source/blender/draw/engines/eevee/shaders/bsdf_direct_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/bsdf_direct_lib.glsl
@@ -47,6 +47,16 @@ float direct_diffuse_rectangle(LightData ld, vec3 N, vec3 V, vec4 l_vector)
return ltc_evaluate_quad(corners, N);
}
+float direct_diffuse_ellipse(LightData ld, vec3 N, vec3 V, vec4 l_vector)
+{
+ vec3 points[3];
+ points[0] = l_vector.xyz + ld.l_right * -ld.l_sizex + ld.l_up * -ld.l_sizey;
+ points[1] = l_vector.xyz + ld.l_right * ld.l_sizex + ld.l_up * -ld.l_sizey;
+ points[2] = l_vector.xyz + ld.l_right * ld.l_sizex + ld.l_up * ld.l_sizey;
+
+ return ltc_evaluate_disk(N, V, mat3(1), points);
+}
+
float direct_diffuse_unit_disc(LightData ld, vec3 N, vec3 V)
{
float NL = dot(N, -ld.l_forward);
@@ -107,6 +117,26 @@ vec3 direct_ggx_sphere(LightData ld, vec3 N, vec3 V, vec4 l_vector, float roughn
return spec;
}
+vec3 direct_ggx_ellipse(LightData ld, vec3 N, vec3 V, vec4 l_vector, float roughness, vec3 f0)
+{
+ vec3 points[3];
+ points[0] = l_vector.xyz + ld.l_right * -ld.l_sizex + ld.l_up * -ld.l_sizey;
+ points[1] = l_vector.xyz + ld.l_right * ld.l_sizex + ld.l_up * -ld.l_sizey;
+ points[2] = l_vector.xyz + ld.l_right * ld.l_sizex + ld.l_up * ld.l_sizey;
+
+ vec2 uv = lut_coords(dot(N, V), sqrt(roughness));
+ vec3 brdf_lut = texture(utilTex, vec3(uv, 1.0)).rgb;
+ vec4 ltc_lut = texture(utilTex, vec3(uv, 0.0)).rgba;
+ mat3 ltc_mat = ltc_matrix(ltc_lut);
+
+ float bsdf = ltc_evaluate_disk(N, V, ltc_mat, points);
+ bsdf *= brdf_lut.b; /* Bsdf intensity */
+
+ vec3 spec = F_area(f0, brdf_lut.xy) * bsdf;
+
+ return spec;
+}
+
vec3 direct_ggx_rectangle(LightData ld, vec3 N, vec3 V, vec4 l_vector, float roughness, vec3 f0)
{
vec3 corners[4];
diff --git a/source/blender/draw/engines/eevee/shaders/lamps_lib.glsl b/source/blender/draw/engines/eevee/shaders/lamps_lib.glsl
index 198a05ccf97..0e6f976187a 100644
--- a/source/blender/draw/engines/eevee/shaders/lamps_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/lamps_lib.glsl
@@ -15,11 +15,13 @@ layout(std140) uniform light_block {
};
/* type */
-#define POINT 0.0
-#define SUN 1.0
-#define SPOT 2.0
-#define HEMI 3.0
-#define AREA 4.0
+#define POINT 0.0
+#define SUN 1.0
+#define SPOT 2.0
+#define HEMI 3.0
+#define AREA_RECT 4.0
+/* Used to define the area lamp shape, doesn't directly correspond to a Blender lamp type. */
+#define AREA_ELLIPSE 100.0
#if defined(SHADOW_VSM)
#define ShadowSample vec2
@@ -174,7 +176,7 @@ float light_visibility(LightData ld, vec3 W,
vis *= spotmask;
vis *= step(0.0, -dot(l_vector.xyz, ld.l_forward));
}
- else if (ld.l_type == AREA) {
+ else if (ld.l_type == AREA_RECT || ld.l_type == AREA_ELLIPSE) {
vis *= step(0.0, -dot(l_vector.xyz, ld.l_forward));
}
@@ -253,9 +255,12 @@ float light_diffuse(LightData ld, vec3 N, vec3 V, vec4 l_vector)
if (ld.l_type == SUN) {
return direct_diffuse_unit_disc(ld, N, V);
}
- else if (ld.l_type == AREA) {
+ else if (ld.l_type == AREA_RECT) {
return direct_diffuse_rectangle(ld, N, V, l_vector);
}
+ else if (ld.l_type == AREA_ELLIPSE) {
+ return direct_diffuse_ellipse(ld, N, V, l_vector);
+ }
else {
return direct_diffuse_sphere(ld, N, l_vector);
}
@@ -275,9 +280,12 @@ vec3 light_specular(LightData ld, vec3 N, vec3 V, vec4 l_vector, float roughness
if (ld.l_type == SUN) {
return direct_ggx_unit_disc(ld, N, V, roughness, f0);
}
- else if (ld.l_type == AREA) {
+ else if (ld.l_type == AREA_RECT) {
return direct_ggx_rectangle(ld, N, V, l_vector, roughness, f0);
}
+ else if (ld.l_type == AREA_ELLIPSE) {
+ return direct_ggx_ellipse(ld, N, V, l_vector, roughness, f0);
+ }
else {
return direct_ggx_sphere(ld, N, V, l_vector, roughness, f0);
}
@@ -373,8 +381,11 @@ vec3 light_translucent(LightData ld, vec3 W, vec3 N, vec4 l_vector, float scale)
/* XXX : Removing Area Power. */
/* TODO : put this out of the shader. */
float falloff;
- if (ld.l_type == AREA) {
+ if (ld.l_type == AREA_RECT || ld.l_type == AREA_ELLIPSE) {
vis *= (ld.l_sizex * ld.l_sizey * 4.0 * M_PI) * (1.0 / 80.0);
+ if (ld.l_type == AREA_ELLIPSE) {
+ vis *= M_PI * 0.25;
+ }
vis *= 0.3 * 20.0 * max(0.0, dot(-ld.l_forward, l_vector.xyz / l_vector.w)); /* XXX ad hoc, empirical */
vis /= (l_vector.w * l_vector.w);
falloff = dot(N, l_vector.xyz / l_vector.w);
@@ -412,7 +423,7 @@ vec3 light_translucent(LightData ld, vec3 W, vec3 N, vec4 l_vector, float scale)
vis *= spotmask;
vis *= step(0.0, -dot(l_vector.xyz, ld.l_forward));
}
- else if (ld.l_type == AREA) {
+ else if (ld.l_type == AREA_RECT || ld.l_type == AREA_ELLIPSE) {
vis *= step(0.0, -dot(l_vector.xyz, ld.l_forward));
}
}
diff --git a/source/blender/draw/engines/eevee/shaders/volumetric_lib.glsl b/source/blender/draw/engines/eevee/shaders/volumetric_lib.glsl
index 1a8167c2830..5f641c5d490 100644
--- a/source/blender/draw/engines/eevee/shaders/volumetric_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/volumetric_lib.glsl
@@ -66,8 +66,11 @@ vec3 light_volume(LightData ld, vec4 l_vector)
/* XXX : Removing Area Power. */
/* TODO : put this out of the shader. */
/* See eevee_light_setup(). */
- if (ld.l_type == AREA) {
+ if (ld.l_type == AREA_RECT || ld.l_type == AREA_ELLIPSE) {
power = (ld.l_sizex * ld.l_sizey * 4.0 * M_PI) * (1.0 / 80.0);
+ if (ld.l_type == AREA_ELLIPSE) {
+ power *= M_PI * 0.25;
+ }
power *= 20.0 * max(0.0, dot(-ld.l_forward, l_vector.xyz / l_vector.w)); /* XXX ad hoc, empirical */
}
else if (ld.l_type == SUN) {
diff --git a/source/blender/draw/intern/draw_cache.c b/source/blender/draw/intern/draw_cache.c
index 6065e7f0fc5..96edb7cd429 100644
--- a/source/blender/draw/intern/draw_cache.c
+++ b/source/blender/draw/intern/draw_cache.c
@@ -72,7 +72,8 @@ static struct DRWShapeCache {
Gwn_Batch *drw_lamp;
Gwn_Batch *drw_lamp_shadows;
Gwn_Batch *drw_lamp_sunrays;
- Gwn_Batch *drw_lamp_area;
+ Gwn_Batch *drw_lamp_area_square;
+ Gwn_Batch *drw_lamp_area_disk;
Gwn_Batch *drw_lamp_hemi;
Gwn_Batch *drw_lamp_spot;
Gwn_Batch *drw_lamp_spot_square;
@@ -1122,9 +1123,9 @@ Gwn_Batch *DRW_cache_lamp_sunrays_get(void)
return SHC.drw_lamp_sunrays;
}
-Gwn_Batch *DRW_cache_lamp_area_get(void)
+Gwn_Batch *DRW_cache_lamp_area_square_get(void)
{
- if (!SHC.drw_lamp_area) {
+ if (!SHC.drw_lamp_area_square) {
float v1[3] = {0.0f, 0.0f, 0.0f};
/* Position Only 3D format */
@@ -1151,9 +1152,40 @@ Gwn_Batch *DRW_cache_lamp_area_get(void)
v1[1] = 0.5f;
GWN_vertbuf_attr_set(vbo, attr_id.pos, 7, v1);
- SHC.drw_lamp_area = GWN_batch_create_ex(GWN_PRIM_LINES, vbo, NULL, GWN_BATCH_OWNS_VBO);
+ SHC.drw_lamp_area_square = GWN_batch_create_ex(GWN_PRIM_LINES, vbo, NULL, GWN_BATCH_OWNS_VBO);
}
- return SHC.drw_lamp_area;
+ return SHC.drw_lamp_area_square;
+}
+
+Gwn_Batch *DRW_cache_lamp_area_disk_get(void)
+{
+#define NSEGMENTS 32
+ if (!SHC.drw_lamp_area_disk) {
+ /* Position Only 3D format */
+ static Gwn_VertFormat format = { 0 };
+ static struct { uint pos; } attr_id;
+ if (format.attrib_ct == 0) {
+ attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+ }
+
+ Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
+ GWN_vertbuf_data_alloc(vbo, 2*NSEGMENTS);
+
+ float v[3] = {0.0f, 0.5f, 0.0f};
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, 0, v);
+ for (int a = 1; a < NSEGMENTS; a++) {
+ v[0] = 0.5f*sinf(2.f * (float)M_PI * a / NSEGMENTS);
+ v[1] = 0.5f*cosf(2.f * (float)M_PI * a / NSEGMENTS);
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, 2*a-1, v);
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, 2*a, v);
+ }
+ copy_v3_fl3(v, 0.0f, 0.5f, 0.0f);
+ GWN_vertbuf_attr_set(vbo, attr_id.pos, 2*NSEGMENTS-1, v);
+
+ SHC.drw_lamp_area_disk = GWN_batch_create_ex(GWN_PRIM_LINES, vbo, NULL, GWN_BATCH_OWNS_VBO);
+ }
+ return SHC.drw_lamp_area_disk;
+#undef NSEGMENTS
}
Gwn_Batch *DRW_cache_lamp_hemi_get(void)
diff --git a/source/blender/draw/intern/draw_cache.h b/source/blender/draw/intern/draw_cache.h
index 8bc609ffe1f..8cf38cdd123 100644
--- a/source/blender/draw/intern/draw_cache.h
+++ b/source/blender/draw/intern/draw_cache.h
@@ -78,7 +78,8 @@ struct Gwn_Batch *DRW_cache_field_cone_limit_get(void);
struct Gwn_Batch *DRW_cache_lamp_get(void);
struct Gwn_Batch *DRW_cache_lamp_shadows_get(void);
struct Gwn_Batch *DRW_cache_lamp_sunrays_get(void);
-struct Gwn_Batch *DRW_cache_lamp_area_get(void);
+struct Gwn_Batch *DRW_cache_lamp_area_square_get(void);
+struct Gwn_Batch *DRW_cache_lamp_area_disk_get(void);
struct Gwn_Batch *DRW_cache_lamp_hemi_get(void);
struct Gwn_Batch *DRW_cache_lamp_spot_get(void);
struct Gwn_Batch *DRW_cache_lamp_spot_square_get(void);
diff --git a/source/blender/draw/modes/object_mode.c b/source/blender/draw/modes/object_mode.c
index 58cdfd4e413..40c721e64de 100644
--- a/source/blender/draw/modes/object_mode.c
+++ b/source/blender/draw/modes/object_mode.c
@@ -175,7 +175,8 @@ typedef struct OBJECT_PrivateData {
DRWShadingGroup *lamp_distance;
DRWShadingGroup *lamp_buflimit;
DRWShadingGroup *lamp_buflimit_points;
- DRWShadingGroup *lamp_area;
+ DRWShadingGroup *lamp_area_square;
+ DRWShadingGroup *lamp_area_disk;
DRWShadingGroup *lamp_hemi;
DRWShadingGroup *lamp_spot_cone;
DRWShadingGroup *lamp_spot_blend;
@@ -1164,8 +1165,11 @@ static void OBJECT_cache_init(void *vedata)
stl->g_data->lamp_groundline = shgroup_groundlines_uniform_color(psl->non_meshes, ts.colorLamp);
stl->g_data->lamp_groundpoint = shgroup_groundpoints_uniform_color(psl->non_meshes, ts.colorLamp);
- geom = DRW_cache_lamp_area_get();
- stl->g_data->lamp_area = shgroup_instance(psl->non_meshes, geom);
+ geom = DRW_cache_lamp_area_square_get();
+ stl->g_data->lamp_area_square = shgroup_instance(psl->non_meshes, geom);
+
+ geom = DRW_cache_lamp_area_disk_get();
+ stl->g_data->lamp_area_disk = shgroup_instance(psl->non_meshes, geom);
geom = DRW_cache_lamp_hemi_get();
stl->g_data->lamp_hemi = shgroup_instance(psl->non_meshes, geom);
@@ -1398,13 +1402,18 @@ static void DRW_shgroup_lamp(OBJECT_StorageList *stl, Object *ob, ViewLayer *vie
else if (la->type == LA_AREA) {
float size[3] = {1.0f, 1.0f, 1.0f}, sizemat[4][4];
- if (la->area_shape == LA_AREA_RECT) {
+ if (ELEM(la->area_shape, LA_AREA_RECT, LA_AREA_ELLIPSE)) {
size[1] = la->area_sizey / la->area_size;
size_to_mat4(sizemat, size);
mul_m4_m4m4(shapemat, shapemat, sizemat);
}
- DRW_shgroup_call_dynamic_add(stl->g_data->lamp_area, color, &la->area_size, shapemat);
+ if (ELEM(la->area_shape, LA_AREA_DISK, LA_AREA_ELLIPSE)) {
+ DRW_shgroup_call_dynamic_add(stl->g_data->lamp_area_disk, color, &la->area_size, shapemat);
+ }
+ else {
+ DRW_shgroup_call_dynamic_add(stl->g_data->lamp_area_square, color, &la->area_size, shapemat);
+ }
}
/* Line and point going to the ground */
diff --git a/source/blender/editors/object/object_transform.c b/source/blender/editors/object/object_transform.c
index 6b22521eedd..77514ca1e8e 100644
--- a/source/blender/editors/object/object_transform.c
+++ b/source/blender/editors/object/object_transform.c
@@ -631,6 +631,10 @@ static int apply_objects_internal(
la->area_shape = LA_AREA_RECT;
la->area_sizey = la->area_size;
}
+ else if ((la->area_shape == LA_AREA_DISK) && !keeps_aspect_ratio) {
+ la->area_shape = LA_AREA_ELLIPSE;
+ la->area_sizey = la->area_size;
+ }
la->area_size *= rsmat[0][0];
la->area_sizey *= rsmat[1][1];
diff --git a/source/blender/editors/space_view3d/view3d_manipulator_lamp.c b/source/blender/editors/space_view3d/view3d_manipulator_lamp.c
index 93b6b69a105..88c36fc2c0b 100644
--- a/source/blender/editors/space_view3d/view3d_manipulator_lamp.c
+++ b/source/blender/editors/space_view3d/view3d_manipulator_lamp.c
@@ -129,7 +129,7 @@ static void manipulator_area_lamp_prop_matrix_get(
const Lamp *la = mpr_prop->custom_func.user_data;
matrix[0][0] = la->area_size;
- matrix[1][1] = (la->area_shape == LA_AREA_RECT) ? la->area_sizey : la->area_size;
+ matrix[1][1] = ELEM(la->area_shape, LA_AREA_RECT, LA_AREA_ELLIPSE) ? la->area_sizey : la->area_size;
}
static void manipulator_area_lamp_prop_matrix_set(
@@ -140,7 +140,7 @@ static void manipulator_area_lamp_prop_matrix_set(
BLI_assert(mpr_prop->type->array_length == 16);
Lamp *la = mpr_prop->custom_func.user_data;
- if (la->area_shape == LA_AREA_RECT) {
+ if (ELEM(la->area_shape, LA_AREA_RECT, LA_AREA_ELLIPSE)) {
la->area_size = len_v3(matrix[0]);
la->area_sizey = len_v3(matrix[1]);
}
@@ -185,9 +185,11 @@ static void WIDGETGROUP_lamp_area_refresh(const bContext *C, wmManipulatorGroup
copy_m4_m4(mpr->matrix_basis, ob->obmat);
- RNA_enum_set(mpr->ptr, "transform",
- ED_MANIPULATOR_CAGE2D_XFORM_FLAG_SCALE |
- ((la->area_shape == LA_AREA_SQUARE) ? ED_MANIPULATOR_CAGE2D_XFORM_FLAG_SCALE_UNIFORM : 0));
+ int flag = ED_MANIPULATOR_CAGE2D_XFORM_FLAG_SCALE;
+ if (ELEM(la->area_shape, LA_AREA_SQUARE, LA_AREA_DISK)) {
+ flag |= ED_MANIPULATOR_CAGE2D_XFORM_FLAG_SCALE_UNIFORM;
+ }
+ RNA_enum_set(mpr->ptr, "transform", flag);
/* need to set property here for undo. TODO would prefer to do this in _init */
WM_manipulator_target_property_def_func(
diff --git a/source/blender/makesdna/DNA_lamp_types.h b/source/blender/makesdna/DNA_lamp_types.h
index 6294afe00e7..3a4b07cc791 100644
--- a/source/blender/makesdna/DNA_lamp_types.h
+++ b/source/blender/makesdna/DNA_lamp_types.h
@@ -148,6 +148,8 @@ typedef struct Lamp {
#define LA_AREA_RECT 1
#define LA_AREA_CUBE 2
#define LA_AREA_BOX 3
+#define LA_AREA_DISK 4
+#define LA_AREA_ELLIPSE 5
#endif /* __DNA_LAMP_TYPES_H__ */
diff --git a/source/blender/makesrna/intern/rna_lamp.c b/source/blender/makesrna/intern/rna_lamp.c
index 5bb24f0270d..d123cdb9773 100644
--- a/source/blender/makesrna/intern/rna_lamp.c
+++ b/source/blender/makesrna/intern/rna_lamp.c
@@ -394,6 +394,8 @@ static void rna_def_area_lamp(BlenderRNA *brna)
static const EnumPropertyItem prop_areashape_items[] = {
{LA_AREA_SQUARE, "SQUARE", 0, "Square", ""},
{LA_AREA_RECT, "RECTANGLE", 0, "Rectangle", ""},
+ {LA_AREA_DISK, "DISK", 0, "Disk", ""},
+ {LA_AREA_ELLIPSE, "ELLIPSE", 0, "Ellipse", ""},
{0, NULL, 0, NULL, NULL}
};