Eevee: Diffuse Light (2/2) and GGX low quality lights
GGX is missing sun lamps area.
This commit is contained in:
@@ -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:")
|
||||
|
@@ -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);
|
||||
}
|
||||
|
||||
{
|
||||
|
@@ -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;
|
||||
|
@@ -1,3 +1,144 @@
|
||||
|
||||
#define M_PI 3.14159265358979323846 /* pi */
|
||||
#define M_1_PI 0.318309886183790671538 /* 1/pi */
|
||||
#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 */
|
||||
}
|
||||
|
@@ -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_ggx(N, L, V, roughness);
|
||||
}
|
||||
|
||||
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_sphere(vec3 N, vec3 L)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
|
||||
|
@@ -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 {
|
||||
wL = ld.lampPosition - W;
|
||||
float dist = length(wL);
|
||||
light = color * direct_diffuse_point(N, wL / dist, dist) * 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 {
|
||||
// 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;
|
||||
void main()
|
||||
{
|
||||
vec3 N = normalize(worldNormal);
|
||||
|
||||
return light;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
Reference in New Issue
Block a user