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:
authorClément Foucault <foucault.clem@gmail.com>2017-03-30 00:45:07 +0300
committerClément Foucault <foucault.clem@gmail.com>2017-03-30 00:45:44 +0300
commit4743fa52ac9545cdd6b815671761081cda10f807 (patch)
tree27a3faa193432d516793402a1723bd6657df038b
parentccb9f683e52ced60ba055545637f9775f761aa98 (diff)
Eevee: Diffuse Light (2/2) and GGX low quality lights
GGX is missing sun lamps area.
-rw-r--r--release/scripts/startup/bl_ui/properties_data_lamp.py1
-rw-r--r--source/blender/draw/engines/eevee/eevee.c8
-rw-r--r--source/blender/draw/engines/eevee/eevee_lights.c10
-rw-r--r--source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl143
-rw-r--r--source/blender/draw/engines/eevee/shaders/bsdf_direct_lib.glsl102
-rw-r--r--source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl87
6 files changed, 318 insertions, 33 deletions
diff --git a/release/scripts/startup/bl_ui/properties_data_lamp.py b/release/scripts/startup/bl_ui/properties_data_lamp.py
index ab84eb8dd60..31ad299f924 100644
--- a/release/scripts/startup/bl_ui/properties_data_lamp.py
+++ b/release/scripts/startup/bl_ui/properties_data_lamp.py
@@ -96,6 +96,7 @@ class DATA_PT_lamp(DataButtonsPanel, Panel):
sub.label(text="Falloff:")
sub.prop(lamp, "falloff_type", text="")
sub.prop(lamp, "distance")
+ sub.prop(lamp, "shadow_soft_size", text="Radius")
if lamp.falloff_type == 'LINEAR_QUADRATIC_WEIGHTED':
col.label(text="Attenuation Factors:")
diff --git a/source/blender/draw/engines/eevee/eevee.c b/source/blender/draw/engines/eevee/eevee.c
index 5ab14537919..f5c4f2385af 100644
--- a/source/blender/draw/engines/eevee/eevee.c
+++ b/source/blender/draw/engines/eevee/eevee.c
@@ -37,6 +37,7 @@ static struct {
struct GPUShader *default_lit;
struct GPUShader *depth_sh;
struct GPUShader *tonemap;
+ float camera_pos[3];
} e_data = {NULL}; /* Engine data */
extern char datatoc_bsdf_common_lib_glsl[];
@@ -86,6 +87,12 @@ static void EEVEE_engine_init(void *vedata)
EEVEE_lights_init(stl);
// EEVEE_lights_update(stl);
+ {
+ float viewinvmat[4][4];
+ DRW_viewport_matrix_get(viewinvmat, DRW_MAT_VIEWINV);
+
+ copy_v3_v3(e_data.camera_pos, viewinvmat[3]);
+ }
}
static void EEVEE_cache_init(void *vedata)
@@ -126,6 +133,7 @@ static void EEVEE_cache_init(void *vedata)
stl->g_data->default_lit_grp = DRW_shgroup_create(e_data.default_lit, psl->pass);
DRW_shgroup_uniform_block(stl->g_data->default_lit_grp, "light_block", stl->lights_ubo, 0);
DRW_shgroup_uniform_int(stl->g_data->default_lit_grp, "light_count", &stl->lights_info->light_count, 1);
+ DRW_shgroup_uniform_vec3(stl->g_data->default_lit_grp, "cameraPos", e_data.camera_pos, 1);
}
{
diff --git a/source/blender/draw/engines/eevee/eevee_lights.c b/source/blender/draw/engines/eevee/eevee_lights.c
index c073175a0b2..3b781db90c2 100644
--- a/source/blender/draw/engines/eevee/eevee_lights.c
+++ b/source/blender/draw/engines/eevee/eevee_lights.c
@@ -123,9 +123,13 @@ void EEVEE_lights_update(EEVEE_StorageList *stl)
evli->spotsize = cosf(la->spotsize * 0.5f);
evli->spotblend = (1.0f - evli->spotsize) * la->spotblend;
}
- // else if (la->type == LA_SPOT) {
-
- // }
+ else if (la->type == LA_AREA) {
+ evli->sizex = la->area_size * scale[0] * 0.5f;
+ evli->sizey = la->area_sizey * scale[1] * 0.5f;
+ }
+ else {
+ evli->sizex = la->area_size * scale[0] * 0.5f;
+ }
/* Lamp Type */
evli->lamptype = (float)la->type;
diff --git a/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl b/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl
index 0ed35509061..b0b48e94809 100644
--- a/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl
@@ -1,3 +1,144 @@
#define M_PI 3.14159265358979323846 /* pi */
-#define M_1_PI 0.318309886183790671538 /* 1/pi */ \ No newline at end of file
+#define M_1_PI 0.318309886183790671538 /* 1/pi */
+
+/* ------- Convenience functions --------- */
+
+vec3 mul(mat3 m, vec3 v) { return m * v; }
+mat3 mul(mat3 m1, mat3 m2) { return m1 * m2; }
+
+float saturate(float a) { return clamp(a, 0.0, 1.0); }
+vec2 saturate(vec2 a) { return vec2(saturate(a.x), saturate(a.y)); }
+vec3 saturate(vec3 a) { return vec3(saturate(a.x), saturate(a.y), saturate(a.z)); }
+vec4 saturate(vec4 a) { return vec4(saturate(a.x), saturate(a.y), saturate(a.z), saturate(a.w)); }
+
+float distance_squared(vec2 a, vec2 b) { a -= b; return dot(a, a); }
+float distance_squared(vec3 a, vec3 b) { a -= b; return dot(a, a); }
+
+float hypot(float x, float y) { return sqrt(x*x + y*y); }
+
+float inverse_distance(vec3 V) { return max( 1 / length(V), 1e-8); }
+
+float line_plane_intersect_dist(vec3 lineorigin, vec3 linedirection, vec3 planeorigin, vec3 planenormal)
+{
+ return dot(planenormal, planeorigin - lineorigin) / dot(planenormal, linedirection);
+}
+
+vec3 line_plane_intersect(vec3 lineorigin, vec3 linedirection, vec3 planeorigin, vec3 planenormal)
+{
+ float dist = line_plane_intersect_dist(lineorigin, linedirection, planeorigin, planenormal);
+ return lineorigin + linedirection * dist;
+}
+
+float rectangle_solid_angle(vec3 p0, vec3 p1, vec3 p2, vec3 p3)
+{
+ vec3 n0 = normalize(cross(p0, p1));
+ vec3 n1 = normalize(cross(p1, p2));
+ vec3 n2 = normalize(cross(p2, p3));
+ vec3 n3 = normalize(cross(p3, p0));
+
+ float g0 = acos(dot(-n0, n1));
+ float g1 = acos(dot(-n1, n2));
+ float g2 = acos(dot(-n2, n3));
+ float g3 = acos(dot(-n3, n0));
+
+ return max(0.0, (g0 + g1 + g2 + g3 - 2.0 * M_PI));
+}
+
+
+/* ------- Energy Conversion for lights ------- */
+/* from Sebastien Lagarde
+ * course_notes_moving_frostbite_to_pbr.pdf */
+
+float sphere_energy(float radius)
+{
+ radius = max(radius, 1e-8);
+ return 0.25 / (radius*radius * M_PI * M_PI) /* 1/(4*r²*Pi²) */
+ * M_PI * M_PI * 10.0; /* XXX : Empirical, Fit cycles power */
+}
+
+float rectangle_energy(float width, float height)
+{
+ return M_1_PI / (width*height) /* 1/(w*h*Pi) */
+ * 20.0; /* XXX : Empirical, Fit cycles power */
+}
+
+/* From UE4 paper */
+void mrp_sphere(
+ float radius, float dist, vec3 R, inout vec3 L,
+ inout float roughness, inout float energy_conservation)
+{
+ L = dist * L;
+
+ /* Sphere Light */
+ roughness = max(3e-3, roughness); /* Artifacts appear with roughness below this threshold */
+
+ /* energy preservation */
+ float sphere_angle = saturate(radius / dist);
+ energy_conservation *= pow(roughness / saturate(roughness + 0.5 * sphere_angle), 2.0);
+
+ /* sphere light */
+ float inter_dist = dot(L, R);
+ vec3 closest_point_on_ray = inter_dist * R;
+ vec3 center_to_ray = closest_point_on_ray - L;
+
+ /* closest point on sphere */
+ L = L + center_to_ray * saturate(radius * inverse_distance(center_to_ray));
+
+ L = normalize(L);
+}
+
+void mrp_area(vec3 R, vec3 N, vec3 W, vec3 Lpos, vec3 Lx, vec3 Ly, vec3 Lz, float sizeX, float sizeY, float dist, inout vec3 L)
+{
+ vec3 refproj = line_plane_intersect(W, R, Lpos, Lz);
+ vec3 norproj = line_plane_intersect(W, N, Lpos, Lz);
+
+ vec2 area_half_size = vec2(sizeX, sizeY);
+
+ /* Find the closest point to the rectangular light shape */
+ vec3 refdir = refproj - Lpos;
+ vec2 mrp = vec2(dot(refdir, Lx), dot(refdir, Ly));
+
+ /* clamp to corners */
+ mrp = clamp(mrp, -area_half_size, area_half_size);
+
+ L = dist * L;
+ L = L + mrp.x * Lx + mrp.y * Ly ;
+
+ L = normalize(L);
+}
+
+/* GGX */
+float D_ggx_opti(float NH, float a2)
+{
+ float tmp = (NH * a2 - NH) * NH + 1.0;
+ return M_PI * tmp*tmp; /* Doing RCP and mul a2 at the end */
+}
+
+float G1_Smith_GGX(float NX, float a2)
+{
+ /* Using Brian Karis approach and refactoring by NX/NX
+ * this way the (2*NL)*(2*NV) in G = G1(V) * G1(L) gets canceled by the brdf denominator 4*NL*NV
+ * Rcp is done on the whole G later
+ * Note that this is not convenient for the transmition formula */
+ return NX + sqrt( NX * (NX - NX * a2) + a2 );
+ /* return 2 / (1 + sqrt(1 + a2 * (1 - NX*NX) / (NX*NX) ) ); /* Reference function */
+}
+
+float bsdf_ggx(vec3 N, vec3 L, vec3 V, float roughness)
+{
+ float a = roughness;
+ float a2 = a * a;
+
+ vec3 H = normalize(L + V);
+ float NH = max(dot(N, H), 1e-8);
+ float NL = max(dot(N, L), 1e-8);
+ float NV = max(dot(N, V), 1e-8);
+
+ float G = G1_Smith_GGX(NV, a2) * G1_Smith_GGX(NL, a2); /* Doing RCP at the end */
+ float D = D_ggx_opti(NH, a2);
+
+ /* Denominator is canceled by G1_Smith */
+ /* bsdf = D * G / (4.0 * NL * NV); /* Reference function */
+ return NL * a2 / (D * G); /* NL to Fit cycles Equation : line. 345 in bsdf_microfacet.h */
+}
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 4f66b79024d..953d4e0a551 100644
--- a/source/blender/draw/engines/eevee/shaders/bsdf_direct_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/bsdf_direct_lib.glsl
@@ -2,6 +2,7 @@
/* in other word, how materials react to scene lamps */
/* Naming convention
+ * V View vector (normalized)
* N World Normal (normalized)
* L Outgoing Light Vector (Surface to Light in World Space) (normalized)
* Ldist Distance from surface to the light
@@ -14,20 +15,69 @@ float direct_diffuse_point(vec3 N, vec3 L, float Ldist)
{
float bsdf = max(0.0, dot(N, L));
bsdf /= Ldist * Ldist;
- bsdf *= M_1_PI; /* Normalize */
+ bsdf *= M_PI / 2.0; /* Normalize */
return bsdf;
}
-#if 0
-float direct_diffuse_sphere(vec3 N, vec3 L)
+
+/* From Frostbite PBR Course
+ * Analitical irradiance from a sphere with correct horizon handling
+ * http://www.frostbite.com/wp-content/uploads/2014/11/course_notes_moving_frostbite_to_pbr.pdf */
+float direct_diffuse_sphere(vec3 N, vec3 L, float Ldist, float radius)
{
+ radius = max(radius, 0.0001);
+ float costheta = clamp(dot(N, L), -0.999, 0.999);
+ float h = min(radius / Ldist , 0.9999);
+ float h2 = h*h;
+ float costheta2 = costheta * costheta;
+ float bsdf;
+
+ if (costheta2 > h2) {
+ bsdf = M_PI * h2 * clamp(costheta, 0.0, 1.0);
+ }
+ else {
+ float sintheta = sqrt(1.0 - costheta2);
+ float x = sqrt(1.0 / h2 - 1.0);
+ float y = -x * (costheta / sintheta);
+ float sinthetasqrty = sintheta * sqrt(1.0 - y * y);
+ bsdf = (costheta * acos(y) - x * sinthetasqrty) * h2 + atan(sinthetasqrty / x);
+ }
+
+ /* Energy conservation + cycle matching */
+ bsdf = max(bsdf, 0.0);
+ bsdf *= M_1_PI;
+ bsdf *= sphere_energy(radius);
+ return bsdf;
}
-float direct_diffuse_rectangle(vec3 N, vec3 L)
+/* From Frostbite PBR Course
+ * http://www.frostbite.com/wp-content/uploads/2014/11/course_notes_moving_frostbite_to_pbr.pdf */
+float direct_diffuse_rectangle(
+ vec3 W, vec3 N, vec3 L,
+ float Ldist, vec3 Lx, vec3 Ly, vec3 Lz, float Lsizex, float Lsizey)
{
+ vec3 lco = L * Ldist;
+
+ /* Surface to corner vectors */
+ vec3 p0 = lco + Lx * -Lsizex + Ly * Lsizey;
+ vec3 p1 = lco + Lx * -Lsizex + Ly * -Lsizey;
+ vec3 p2 = lco + Lx * Lsizex + Ly * -Lsizey;
+ vec3 p3 = lco + Lx * Lsizex + Ly * Lsizey;
+
+ float solidAngle = rectangle_solid_angle(p0, p1, p2, p3);
+ float bsdf = solidAngle * 0.2 * (
+ max(0.0, dot(normalize(p0), N)) +
+ max(0.0, dot(normalize(p1), N)) +
+ max(0.0, dot(normalize(p2), N)) +
+ max(0.0, dot(normalize(p3), N)) +
+ max(0.0, dot(L, N))
+ );
+
+ bsdf *= rectangle_energy(Lsizex * 2.0, Lsizey * 2.0);
+
+ return bsdf;
}
-#endif
/* infinitly far away point source, no decay */
float direct_diffuse_sun(vec3 N, vec3 L)
@@ -42,25 +92,55 @@ float direct_diffuse_unit_disc(vec3 N, vec3 L)
{
}
+#endif
/* ----------- GGx ------------ */
-float direct_ggx_point(vec3 N, vec3 L)
+float direct_ggx_point(vec3 N, vec3 L, vec3 V, float roughness)
{
- float bsdf = max(0.0, dot(N, L));
- bsdf *= M_1_PI; /* Normalize */
- return bsdf;
+ return bsdf_ggx(N, L, V, roughness);
}
-float direct_ggx_sphere(vec3 N, vec3 L)
+float direct_ggx_sphere(vec3 N, vec3 L, vec3 V, float Ldist, float radius, float roughness)
{
+ vec3 R = reflect(V, N);
+
+ float energy_conservation = 1.0;
+ mrp_sphere(radius, Ldist, R, L, roughness, energy_conservation);
+ float bsdf = bsdf_ggx(N, L, V, roughness);
+ bsdf *= energy_conservation / (Ldist * Ldist);
+ bsdf *= sphere_energy(radius) * max(radius * radius, 1e-16); /* radius is already inside energy_conservation */
+ bsdf *= M_PI;
+
+ return bsdf;
}
-float direct_ggx_rectangle(vec3 N, vec3 L)
+float direct_ggx_rectangle(
+ vec3 W, vec3 N, vec3 L, vec3 V,
+ float Ldist, vec3 Lx, vec3 Ly, vec3 Lz, float Lsizex, float Lsizey, float roughness)
{
+ vec3 lco = L * Ldist;
+
+ /* Surface to corner vectors */
+ vec3 p0 = lco + Lx * -Lsizex + Ly * Lsizey;
+ vec3 p1 = lco + Lx * -Lsizex + Ly * -Lsizey;
+ vec3 p2 = lco + Lx * Lsizex + Ly * -Lsizey;
+ vec3 p3 = lco + Lx * Lsizex + Ly * Lsizey;
+ float solidAngle = rectangle_solid_angle(p0, p1, p2, p3);
+
+ vec3 R = reflect(V, N);
+ mrp_area(R, N, W, W + lco, Lx, Ly, Lz, Lsizex, Lsizey, Ldist, L);
+
+ float bsdf = bsdf_ggx(N, L, V, roughness) * solidAngle;
+
+ bsdf *= pow(max(0.0, dot(R, Lz)), 0.5); /* fade mrp artifacts */
+ bsdf *= rectangle_energy(Lsizex * 2.0, Lsizey * 2.0);
+
+ return bsdf;
}
+#if 0
float direct_ggx_disc(vec3 N, vec3 L)
{
diff --git a/source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl b/source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl
index 19498a611e8..f2c7b9579dd 100644
--- a/source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl
@@ -1,5 +1,8 @@
uniform int light_count;
+uniform vec3 cameraPos;
+uniform vec3 eye;
+uniform mat4 ProjectionMatrix;
struct LightData {
vec4 positionAndInfluence; /* w : InfluenceRadius */
@@ -40,18 +43,52 @@ out vec4 fragColor;
#define HEMI 3.0
#define AREA 4.0
-vec3 light_diffuse(LightData ld, vec3 N, vec3 W, vec3 color) {
- vec3 light, wL, L;
+vec3 light_diffuse(LightData ld, vec3 N, vec3 W, vec3 wL, vec3 L, float Ldist, vec3 color)
+{
+ vec3 light;
if (ld.lampType == SUN) {
L = -ld.lampForward;
light = color * direct_diffuse_sun(N, L) * ld.lampColor;
}
+ else if (ld.lampType == AREA) {
+ light = color * direct_diffuse_rectangle(W, N, L, Ldist,
+ ld.lampRight, ld.lampUp, ld.lampForward,
+ ld.lampSizeX, ld.lampSizeY) * ld.lampColor;
+ }
else {
- wL = ld.lampPosition - W;
- float dist = length(wL);
- light = color * direct_diffuse_point(N, wL / dist, dist) * ld.lampColor;
+ // light = color * direct_diffuse_point(N, L, Ldist) * ld.lampColor;
+ light = color * direct_diffuse_sphere(N, L, Ldist, ld.lampSizeX) * ld.lampColor;
+ }
+
+ return light;
+}
+
+vec3 light_specular(
+ LightData ld, vec3 V, vec3 N, vec3 W, vec3 wL,
+ vec3 L, float Ldist, vec3 spec, float roughness)
+{
+ vec3 light;
+
+ if (ld.lampType == SUN) {
+ L = -ld.lampForward;
+ light = spec * direct_ggx_point(N, L, V, roughness) * ld.lampColor;
+ }
+ else if (ld.lampType == AREA) {
+ light = spec * direct_ggx_rectangle(W, N, L, V, Ldist, ld.lampRight, ld.lampUp, ld.lampForward,
+ ld.lampSizeX, ld.lampSizeY, roughness) * ld.lampColor;
}
+ else {
+ light = spec * direct_ggx_sphere(N, L, V, Ldist, ld.lampSizeX, roughness) * ld.lampColor;
+ }
+
+ return light;
+}
+
+float light_visibility(
+ LightData ld, vec3 V, vec3 N, vec3 W, vec3 wL, vec3 L, float Ldist)
+{
+ float vis = 1.0;
if (ld.lampType == SPOT) {
float z = dot(ld.lampForward, wL);
@@ -63,28 +100,42 @@ vec3 light_diffuse(LightData ld, vec3 N, vec3 W, vec3 color) {
float spotmask = smoothstep(0.0, 1.0, (ellipse - ld.lampSpotSize) / ld.lampSpotBlend);
- light *= spotmask;
+ vis *= spotmask;
+ }
+ else if (ld.lampType == AREA) {
+ vis *= step(0.0, -dot(L, ld.lampForward));
}
- return light;
+ return vis;
}
-vec3 light_specular(LightData ld, vec3 V, vec3 N, vec3 T, vec3 B, vec3 spec, float roughness) {
- vec3 L = normalize(ld.lampPosition - worldPosition);
- vec3 light = L;
-
- return light;
-}
+void main()
+{
+ vec3 N = normalize(worldNormal);
-void main() {
- vec3 n = normalize(worldNormal);
- vec3 diffuse = vec3(0.0);
+ vec3 V;
+ if (ProjectionMatrix[3][3] == 0.0) {
+ V = normalize(cameraPos - worldPosition);
+ }
+ else {
+ V = normalize(eye);
+ }
+ vec3 radiance = vec3(0.0);
vec3 albedo = vec3(1.0, 1.0, 1.0);
+ vec3 specular = mix(vec3(0.03), vec3(1.0), pow(max(0.0, 1.0 - dot(N,V)), 5.0));
for (int i = 0; i < MAX_LIGHT && i < light_count; ++i) {
- diffuse += light_diffuse(lights_data[i], n, worldPosition, albedo);
+ vec3 wL = lights_data[i].lampPosition - worldPosition;
+ float dist = length(wL);
+ vec3 L = wL / dist;
+
+ float vis = light_visibility(lights_data[i], V, N, worldPosition, wL, L, dist);
+ vec3 spec = light_specular(lights_data[i], V, N, worldPosition, wL, L, dist, vec3(1.0), .2);
+ vec3 diff = light_diffuse(lights_data[i], N, worldPosition, wL, L, dist, albedo);
+
+ radiance += vis * (diff + spec);
}
- fragColor = vec4(diffuse,1.0);
+ fragColor = vec4(radiance, 1.0);
} \ No newline at end of file