diff options
author | Clément Foucault <foucault.clem@gmail.com> | 2017-05-29 13:32:05 +0300 |
---|---|---|
committer | Clément Foucault <foucault.clem@gmail.com> | 2017-05-29 16:52:27 +0300 |
commit | dbed33479a9f55e42b70ea03fe796b10337a21c7 (patch) | |
tree | 63657d2bf0c63f7fd56a658db074386af616dd5b | |
parent | 932399612bdd444cdf7438ef04427864564b41b4 (diff) |
Eevee: Remove non-ltc area light code + optimisation.
Reduce size ShadingData struct leads to some improvement even with more computation.
4 files changed, 81 insertions, 206 deletions
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 feaddd3c0e3..a9be6ca5478 100644 --- a/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl @@ -66,21 +66,11 @@ struct ShadowCascadeData { vec4 bias; }; -struct AreaData { - vec3 corner[4]; - float solid_angle; -}; - struct ShadingData { vec3 V; /* View vector */ vec3 N; /* World Normal of the fragment */ vec3 W; /* World Position of the fragment */ - vec3 R; /* Reflection vector */ - vec3 L; /* Current Light vector (normalized) */ - vec3 spec_dominant_dir; /* dominant direction of the specular rays */ vec3 l_vector; /* Current Light vector */ - float l_distance; /* distance(l_position, W) */ - AreaData area_data; /* If current light is an area light */ }; /* ------- Convenience functions --------- */ @@ -213,21 +203,6 @@ vec3 spherical_harmonics_L2(vec3 N, vec3 shcoefs[9]) return sh; } -float rectangle_solid_angle(AreaData ad) -{ - vec3 n0 = normalize(cross(ad.corner[0], ad.corner[1])); - vec3 n1 = normalize(cross(ad.corner[1], ad.corner[2])); - vec3 n2 = normalize(cross(ad.corner[2], ad.corner[3])); - vec3 n3 = normalize(cross(ad.corner[3], ad.corner[0])); - - 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)); -} - vec3 get_specular_dominant_dir(vec3 N, vec3 R, float roughness) { float smoothness = 1.0 - roughness; @@ -235,52 +210,6 @@ vec3 get_specular_dominant_dir(vec3 N, vec3 R, float roughness) return normalize(mix(N, R, fac)); } -/* From UE4 paper */ -vec3 mrp_sphere(LightData ld, ShadingData sd, vec3 dir, inout float roughness, out float energy_conservation) -{ - roughness = max(3e-3, roughness); /* Artifacts appear with roughness below this threshold */ - - /* energy preservation */ - float sphere_angle = saturate(ld.l_radius / sd.l_distance); - energy_conservation = pow(roughness / saturate(roughness + 0.5 * sphere_angle), 2.0); - - /* sphere light */ - float inter_dist = dot(sd.l_vector, dir); - vec3 closest_point_on_ray = inter_dist * dir; - vec3 center_to_ray = closest_point_on_ray - sd.l_vector; - - /* closest point on sphere */ - vec3 closest_point_on_sphere = sd.l_vector + center_to_ray * saturate(ld.l_radius * inverse_distance(center_to_ray)); - - return normalize(closest_point_on_sphere); -} - -vec3 mrp_area(LightData ld, ShadingData sd, vec3 dir, inout float roughness, out float energy_conservation) -{ - roughness = max(3e-3, roughness); /* Artifacts appear with roughness below this threshold */ - - /* FIXME : This needs to be fixed */ - energy_conservation = pow(roughness / saturate(roughness + 0.5 * sd.area_data.solid_angle), 2.0); - - vec3 refproj = line_plane_intersect(sd.W, dir, ld.l_position, ld.l_forward); - - /* Project the point onto the light plane */ - vec3 refdir = refproj - ld.l_position; - vec2 mrp = vec2(dot(refdir, ld.l_right), dot(refdir, ld.l_up)); - - /* clamp to light shape bounds */ - vec2 area_half_size = vec2(ld.l_sizex, ld.l_sizey); - mrp = clamp(mrp, -area_half_size, area_half_size); - - /* go back in world space */ - vec3 closest_point_on_rectangle = sd.l_vector + mrp.x * ld.l_right + mrp.y * ld.l_up; - - float len = length(closest_point_on_rectangle); - energy_conservation /= len * len; - - return closest_point_on_rectangle / len; -} - /* Fresnel */ vec3 F_schlick(vec3 f0, float cos_theta) { 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 9097f4aca5a..07fff8ac2d2 100644 --- a/source/blender/draw/engines/eevee/shaders/bsdf_direct_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/bsdf_direct_lib.glsl @@ -13,8 +13,10 @@ float direct_diffuse_point(LightData ld, ShadingData sd) { - float bsdf = max(0.0, dot(sd.N, sd.L)); - bsdf /= sd.l_distance * sd.l_distance; + float dist = length(sd.l_vector); + vec3 L = sd.l_vector / dist; + float bsdf = max(0.0, dot(sd.N, L)); + bsdf /= dist * dist; return bsdf; } @@ -23,9 +25,11 @@ float direct_diffuse_point(LightData ld, ShadingData sd) * http://www.frostbite.com/wp-content/uploads/2014/11/course_notes_moving_frostbite_to_pbr.pdf */ float direct_diffuse_sphere(LightData ld, ShadingData sd) { + float dist = length(sd.l_vector); + vec3 L = sd.l_vector / dist; float radius = max(ld.l_sizex, 0.0001); - float costheta = clamp(dot(sd.N, sd.L), -0.999, 0.999); - float h = min(ld.l_radius / sd.l_distance , 0.9999); + float costheta = clamp(dot(sd.N, L), -0.999, 0.999); + float h = min(ld.l_radius / dist , 0.9999); float h2 = h*h; float costheta2 = costheta * costheta; float bsdf; @@ -51,26 +55,21 @@ float direct_diffuse_sphere(LightData ld, ShadingData sd) * http://www.frostbite.com/wp-content/uploads/2014/11/course_notes_moving_frostbite_to_pbr.pdf */ float direct_diffuse_rectangle(LightData ld, ShadingData sd) { -#ifdef USE_LTC - float bsdf = ltc_evaluate(sd.N, sd.V, mat3(1.0), sd.area_data.corner); + vec3 corners[4]; + corners[0] = sd.l_vector + ld.l_right * -ld.l_sizex + ld.l_up * ld.l_sizey; + corners[1] = sd.l_vector + ld.l_right * -ld.l_sizex + ld.l_up * -ld.l_sizey; + corners[2] = sd.l_vector + ld.l_right * ld.l_sizex + ld.l_up * -ld.l_sizey; + corners[3] = sd.l_vector + ld.l_right * ld.l_sizex + ld.l_up * ld.l_sizey; + + float bsdf = ltc_evaluate(sd.N, sd.V, mat3(1.0), corners); bsdf *= M_1_2PI; -#else - float bsdf = sd.area_data.solid_angle * 0.2 * ( - max(0.0, dot(normalize(sd.area_data.corner[0]), sd.N)) + - max(0.0, dot(normalize(sd.area_data.corner[1]), sd.N)) + - max(0.0, dot(normalize(sd.area_data.corner[2]), sd.N)) + - max(0.0, dot(normalize(sd.area_data.corner[3]), sd.N)) + - max(0.0, dot(sd.L, sd.N)) - ); - bsdf *= M_1_PI; -#endif return bsdf; } /* infinitly far away point source, no decay */ float direct_diffuse_sun(LightData ld, ShadingData sd) { - float bsdf = max(0.0, dot(sd.N, sd.L)); + float bsdf = max(0.0, dot(sd.N, -ld.l_forward)); bsdf *= M_1_PI; /* Normalize */ return bsdf; } @@ -85,25 +84,29 @@ float direct_diffuse_unit_disc(vec3 N, vec3 L) /* ----------- GGx ------------ */ vec3 direct_ggx_point(ShadingData sd, float roughness, vec3 f0) { - float bsdf = bsdf_ggx(sd.N, sd.L, sd.V, roughness); - bsdf /= sd.l_distance * sd.l_distance; + float dist = length(sd.l_vector); + vec3 L = sd.l_vector / dist; + float bsdf = bsdf_ggx(sd.N, L, sd.V, roughness); + bsdf /= dist * dist; /* Fresnel */ - float VH = max(dot(sd.V, normalize(sd.V + sd.L)), 0.0); + float VH = max(dot(sd.V, normalize(sd.V + L)), 0.0); return F_schlick(f0, VH) * bsdf; } vec3 direct_ggx_sphere(LightData ld, ShadingData sd, float roughness, vec3 f0) { -#ifdef USE_LTC - float NV = max(dot(sd.N, sd.V), 1e-8); - vec3 P = line_aligned_plane_intersect(vec3(0.0), sd.spec_dominant_dir, sd.l_vector); + vec3 L = normalize(sd.l_vector); + vec3 spec_dir = get_specular_dominant_dir(sd.N, reflect(-sd.V, sd.N), roughness); + vec3 P = line_aligned_plane_intersect(vec3(0.0), spec_dir, sd.l_vector); vec3 Px = normalize(P - sd.l_vector) * ld.l_radius; - vec3 Py = cross(Px, sd.L); + vec3 Py = cross(Px, L); - vec2 uv = lut_coords(NV, sqrt(roughness)); - mat3 ltcmat = ltc_matrix(uv); + vec2 uv = lut_coords(dot(sd.N, sd.V), sqrt(roughness)); + vec3 brdf_lut = texture(brdfLut, uv).rgb; + vec4 ltc_lut = texture(ltcMat, uv).rgba; + mat3 ltc_mat = ltc_matrix(ltc_lut); // #define HIGHEST_QUALITY #ifdef HIGHEST_QUALITY @@ -120,64 +123,44 @@ vec3 direct_ggx_sphere(LightData ld, ShadingData sd, float roughness, vec3 f0) points[5] = sd.l_vector + Pxy2; points[6] = sd.l_vector + Py; points[7] = sd.l_vector + Pxy1; - float bsdf = ltc_evaluate_circle(sd.N, sd.V, ltcmat, points); + float bsdf = ltc_evaluate_circle(sd.N, sd.V, ltc_mat, points); #else vec3 points[4]; points[0] = sd.l_vector + Px; points[1] = sd.l_vector - Py; points[2] = sd.l_vector - Px; points[3] = sd.l_vector + Py; - float bsdf = ltc_evaluate(sd.N, sd.V, ltcmat, points); + float bsdf = ltc_evaluate(sd.N, sd.V, ltc_mat, points); /* sqrt(pi/2) difference between square and disk area */ bsdf *= 1.25331413731; #endif - vec3 lut = texture(brdfLut, uv).rgb; - bsdf *= lut.b; /* Bsdf intensity */ - bsdf *= M_1_2PI * M_1_PI; - vec3 spec = F_area(f0, lut.xy) * bsdf; -#else - float energy_conservation; - vec3 L = mrp_sphere(ld, sd, sd.spec_dominant_dir, roughness, energy_conservation); - float bsdf = bsdf_ggx(sd.N, L, sd.V, roughness); + bsdf *= brdf_lut.b; /* Bsdf intensity */ + bsdf *= M_1_2PI * M_1_PI; - bsdf *= energy_conservation / (sd.l_distance * sd.l_distance); - bsdf *= max(ld.l_radius * ld.l_radius, 1e-16); /* radius is already inside energy_conservation */ + vec3 spec = F_area(f0, brdf_lut.xy) * bsdf; - /* Fresnel */ - float VH = max(dot(sd.V, normalize(sd.V + sd.L)), 0.0); - vec3 spec = F_schlick(f0, VH) * bsdf; -#endif return spec; } vec3 direct_ggx_rectangle(LightData ld, ShadingData sd, float roughness, vec3 f0) { -#ifdef USE_LTC - float NV = max(dot(sd.N, sd.V), 1e-8); - vec2 uv = lut_coords(NV, sqrt(roughness)); - mat3 ltcmat = ltc_matrix(uv); - - float bsdf = ltc_evaluate(sd.N, sd.V, ltcmat, sd.area_data.corner); - vec3 lut = texture(brdfLut, uv).rgb; - bsdf *= lut.b; /* Bsdf intensity */ + vec3 corners[4]; + corners[0] = sd.l_vector + ld.l_right * -ld.l_sizex + ld.l_up * ld.l_sizey; + corners[1] = sd.l_vector + ld.l_right * -ld.l_sizex + ld.l_up * -ld.l_sizey; + corners[2] = sd.l_vector + ld.l_right * ld.l_sizex + ld.l_up * -ld.l_sizey; + corners[3] = sd.l_vector + ld.l_right * ld.l_sizex + ld.l_up * ld.l_sizey; + + vec2 uv = lut_coords(dot(sd.N, sd.V), sqrt(roughness)); + vec3 brdf_lut = texture(brdfLut, uv).rgb; + vec4 ltc_lut = texture(ltcMat, uv).rgba; + mat3 ltc_mat = ltc_matrix(ltc_lut); + float bsdf = ltc_evaluate(sd.N, sd.V, ltc_mat, corners); + bsdf *= brdf_lut.b; /* Bsdf intensity */ bsdf *= M_1_2PI; - vec3 spec = F_area(f0, lut.xy) * bsdf; -#else - float energy_conservation; - vec3 L = mrp_area(ld, sd, sd.spec_dominant_dir, roughness, energy_conservation); - float bsdf = bsdf_ggx(sd.N, L, sd.V, roughness); + vec3 spec = F_area(f0, brdf_lut.xy) * bsdf; - bsdf *= energy_conservation; - /* fade mrp artifacts */ - bsdf *= max(0.0, dot(-sd.spec_dominant_dir, ld.l_forward)); - bsdf *= max(0.0, -dot(L, ld.l_forward)); - - /* Fresnel */ - float VH = max(dot(sd.V, normalize(sd.V + sd.L)), 0.0); - vec3 spec = F_schlick(f0, VH) * bsdf; -#endif return spec; } 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 ecfc670c0d6..bff7c05537a 100644 --- a/source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl @@ -42,36 +42,38 @@ in vec3 viewNormal; #define HEMI 3.0 #define AREA 4.0 -vec3 light_diffuse(LightData ld, ShadingData sd, vec3 albedo) +void light_shade( + LightData ld, ShadingData sd, vec3 albedo, float roughness, vec3 f0, + out vec3 diffuse, out vec3 specular) { +#ifdef USE_LTC if (ld.l_type == SUN) { - return direct_diffuse_sun(ld, sd) * albedo; + diffuse = direct_diffuse_sun(ld, sd) * albedo; + /* TODO disk area light */ + specular = direct_ggx_point(sd, roughness, f0); } else if (ld.l_type == AREA) { - return direct_diffuse_rectangle(ld, sd) * albedo; + diffuse = direct_diffuse_rectangle(ld, sd) * albedo; + specular = direct_ggx_rectangle(ld, sd, roughness, f0); } else { - return direct_diffuse_sphere(ld, sd) * albedo; + diffuse = direct_diffuse_sphere(ld, sd) * albedo; + specular = direct_ggx_sphere(ld, sd, roughness, f0); } -} - -vec3 light_specular(LightData ld, ShadingData sd, float roughness, vec3 f0) -{ +#else if (ld.l_type == SUN) { - return direct_ggx_point(sd, roughness, f0); - } - else if (ld.l_type == AREA) { - return direct_ggx_rectangle(ld, sd, roughness, f0); + diffuse = direct_diffuse_sun(ld, sd) * albedo; } else { - // return direct_ggx_point(sd, roughness, f0); - return direct_ggx_sphere(ld, sd, roughness, f0); + diffuse = direct_diffuse_point(ld, sd) * albedo; } + specular = direct_ggx_point(sd, roughness, f0); +#endif } -float light_visibility(LightData ld, ShadingData sd) +void light_visibility(LightData ld, ShadingData sd, out float vis) { - float vis = 1.0; + vis = 1.0; if (ld.l_type == SPOT) { float z = dot(ld.l_forward, sd.l_vector); @@ -84,10 +86,10 @@ float light_visibility(LightData ld, ShadingData sd) float spotmask = smoothstep(0.0, 1.0, (ellipse - ld.l_spot_size) / ld.l_spot_blend); vis *= spotmask; - vis *= step(0.0, -dot(sd.L, ld.l_forward)); + vis *= step(0.0, -dot(sd.l_vector, ld.l_forward)); } else if (ld.l_type == AREA) { - vis *= step(0.0, -dot(sd.L, ld.l_forward)); + vis *= step(0.0, -dot(sd.l_vector, ld.l_forward)); } /* shadowing */ @@ -157,41 +159,6 @@ float light_visibility(LightData ld, ShadingData sd) vis *= esm_test; } - - return vis; -} - -vec3 light_fresnel(LightData ld, ShadingData sd, vec3 f0) -{ - vec3 H = normalize(sd.L + sd.V); - float NH = max(dot(sd.N, H), 1e-8); - - return F_schlick(f0, NH); -} - -/* Calculation common to all bsdfs */ -float light_common(inout LightData ld, inout ShadingData sd) -{ - float vis = 1.0; - - if (ld.l_type == SUN) { - sd.L = -ld.l_forward; - } - else { - sd.L = sd.l_vector / sd.l_distance; - } - - if (ld.l_type == AREA) { - sd.area_data.corner[0] = sd.l_vector + ld.l_right * -ld.l_sizex + ld.l_up * ld.l_sizey; - sd.area_data.corner[1] = sd.l_vector + ld.l_right * -ld.l_sizex + ld.l_up * -ld.l_sizey; - sd.area_data.corner[2] = sd.l_vector + ld.l_right * ld.l_sizex + ld.l_up * -ld.l_sizey; - sd.area_data.corner[3] = sd.l_vector + ld.l_right * ld.l_sizex + ld.l_up * ld.l_sizey; -#ifndef USE_LTC - sd.area_data.solid_angle = rectangle_solid_angle(sd.area_data); -#endif - } - - return vis; } vec3 eevee_surface_lit(vec3 world_normal, vec3 albedo, vec3 f0, float roughness, float ao) @@ -204,8 +171,6 @@ vec3 eevee_surface_lit(vec3 world_normal, vec3 albedo, vec3 f0, float roughness, ? normalize(cameraPos - worldPosition) : normalize(eye); sd.W = worldPosition; - sd.R = reflect(-sd.V, sd.N); - sd.spec_dominant_dir = get_specular_dominant_dir(sd.N, sd.R, roughnessSquared); vec3 radiance = vec3(0.0); vec3 indirect_radiance = vec3(0.0); @@ -213,25 +178,24 @@ vec3 eevee_surface_lit(vec3 world_normal, vec3 albedo, vec3 f0, float roughness, /* Analitic Lights */ for (int i = 0; i < MAX_LIGHT && i < light_count; ++i) { LightData ld = lights_data[i]; + vec3 diff, spec; + float vis; sd.l_vector = ld.l_position - worldPosition; - sd.l_distance = length(sd.l_vector); - light_common(ld, sd); - - float vis = light_visibility(ld, sd); - vec3 spec = light_specular(ld, sd, roughnessSquared, f0); - vec3 diff = light_diffuse(ld, sd, albedo); + light_visibility(ld, sd, vis); + light_shade(ld, sd, albedo, roughnessSquared, f0, diff, spec); radiance += vis * (diff + spec) * ld.l_color; } - /* Envmaps */ - vec2 uv = lut_coords(dot(sd.N, sd.V), sqrt(roughness)); - vec2 brdf_lut = texture(brdfLut, uv).rg; - vec3 Li = textureLod(probeFiltered, sd.spec_dominant_dir, roughness * lodMax).rgb; - indirect_radiance += Li * F_ibl(f0, brdf_lut); + vec3 spec_dir = get_specular_dominant_dir(sd.N, reflect(-sd.V, sd.N), roughnessSquared); + /* Envmaps */ + vec2 uv = lut_coords(dot(sd.N, sd.V), roughness); + vec3 brdf_lut = texture(brdfLut, uv).rgb; + vec3 Li = textureLod(probeFiltered, spec_dir, roughness * lodMax).rgb; + indirect_radiance += Li * F_ibl(f0, brdf_lut.rg); indirect_radiance += spherical_harmonics(sd.N, shCoefs) * albedo; return radiance + indirect_radiance * ao; diff --git a/source/blender/draw/engines/eevee/shaders/ltc_lib.glsl b/source/blender/draw/engines/eevee/shaders/ltc_lib.glsl index 5ea13cab271..4b02e8c222f 100644 --- a/source/blender/draw/engines/eevee/shaders/ltc_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/ltc_lib.glsl @@ -145,14 +145,13 @@ int clip_quad_to_horizon(inout vec3 L[5]) return n; } -mat3 ltc_matrix(vec2 coord) +mat3 ltc_matrix(vec4 lut) { /* load inverse matrix */ - vec4 t = texture(ltcMat, coord); mat3 Minv = mat3( - vec3( 1, 0, t.y), - vec3( 0, t.z, 0), - vec3(t.w, 0, t.x) + vec3( 1, 0, lut.y), + vec3( 0, lut.z, 0), + vec3(lut.w, 0, lut.x) ); return Minv; |