diff options
author | Lukas Stockner <lukas.stockner@freenet.de> | 2018-05-24 04:50:16 +0300 |
---|---|---|
committer | Lukas Stockner <lukas.stockner@freenet.de> | 2018-05-24 17:43:47 +0300 |
commit | 5505ba8d4753ee6b3c0101ba3e4abf337546a1b0 (patch) | |
tree | 1c0fdbed36127f670e8aa0d49a53f72988cc34c5 /source/blender/draw/engines/eevee/shaders/lamps_lib.glsl | |
parent | e8c8ff4f86c276e4dca884ff1a411fcbbf003fed (diff) |
Cycles/Eevee: Implement disk and ellipse shapes for area lamps
The implementation is pretty straightforward.
In Cycles, sampling the shapes is currently done w.r.t. area instead of solid angle.
There is a paper on solid angle sampling for disks [1], but the described algorithm is based on
simply sampling the enclosing square and rejecting samples outside of the disk, which is not exactly
great for Cycles' RNG (we'd need to setup a LCG for the repeated sampling) and for GPU divergence.
Even worse, the algorithm is only defined for disks. For ellipses, the basic idea still works, but a
way to analytically calculate the solid angle is required. This is technically possible [2], but the
calculation is extremely complex and still requires a lookup table for the Heuman Lambda function.
Therefore, I've decided to not implement that for now, we could still look into it later on.
In Eevee, the code uses the existing ltc_evaluate_disk to implement the lighting calculations.
[1]: "Solid Angle Sampling of Disk and Cylinder Lights"
[2]: "Analytical solution for the solid angle subtended at any point by an ellipse via a point source radiation vector potential"
Reviewers: sergey, brecht, fclem
Differential Revision: https://developer.blender.org/D3171
Diffstat (limited to 'source/blender/draw/engines/eevee/shaders/lamps_lib.glsl')
-rw-r--r-- | source/blender/draw/engines/eevee/shaders/lamps_lib.glsl | 31 |
1 files changed, 21 insertions, 10 deletions
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)); } } |