diff options
Diffstat (limited to 'source/blender/draw/engines/eevee_next/shaders/eevee_light_lib.glsl')
-rw-r--r-- | source/blender/draw/engines/eevee_next/shaders/eevee_light_lib.glsl | 209 |
1 files changed, 209 insertions, 0 deletions
diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_light_lib.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_light_lib.glsl new file mode 100644 index 00000000000..58608f6e1f0 --- /dev/null +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_light_lib.glsl @@ -0,0 +1,209 @@ + +#pragma BLENDER_REQUIRE(common_math_geom_lib.glsl) +#pragma BLENDER_REQUIRE(eevee_ltc_lib.glsl) +#pragma BLENDER_REQUIRE(eevee_light_iter_lib.glsl) + +/* ---------------------------------------------------------------------- */ +/** \name Light Functions + * \{ */ + +void light_vector_get(LightData ld, vec3 P, out vec3 L, out float dist) +{ + if (ld.type == LIGHT_SUN) { + L = ld._back; + dist = 1.0; + } + else { + L = ld._position - P; + dist = inversesqrt(len_squared(L)); + L *= dist; + dist = 1.0 / dist; + } +} + +/* Rotate vector to light's local space. Does not translate. */ +vec3 light_world_to_local(LightData ld, vec3 L) +{ + /* Avoid relying on compiler to optimize this. + * vec3 lL = transpose(mat3(ld.object_mat)) * L; */ + vec3 lL; + lL.x = dot(ld.object_mat[0].xyz, L); + lL.y = dot(ld.object_mat[1].xyz, L); + lL.z = dot(ld.object_mat[2].xyz, L); + return lL; +} + +/* From Frostbite PBR Course + * Distance based attenuation + * http://www.frostbite.com/wp-content/uploads/2014/11/course_notes_moving_frostbite_to_pbr.pdf */ +float light_influence_attenuation(float dist, float inv_sqr_influence) +{ + float factor = sqr(dist) * inv_sqr_influence; + float fac = saturate(1.0 - sqr(factor)); + return sqr(fac); +} + +float light_spot_attenuation(LightData ld, vec3 L) +{ + vec3 lL = light_world_to_local(ld, L); + float ellipse = inversesqrt(1.0 + len_squared(lL.xy * ld.spot_size_inv / lL.z)); + float spotmask = smoothstep(0.0, 1.0, ellipse * ld._spot_mul + ld._spot_bias); + return spotmask; +} + +float light_attenuation(LightData ld, vec3 L, float dist) +{ + float vis = 1.0; + if (ld.type == LIGHT_SPOT) { + vis *= light_spot_attenuation(ld, L); + } + if (ld.type >= LIGHT_SPOT) { + vis *= step(0.0, -dot(L, -ld._back)); + } + if (ld.type != LIGHT_SUN) { +#ifdef VOLUME_LIGHTING + vis *= light_influence_attenuation(dist, ld.influence_radius_invsqr_volume); +#else + vis *= light_influence_attenuation(dist, ld.influence_radius_invsqr_surface); +#endif + } + return vis; +} + +/* Cheaper alternative than evaluating the LTC. + * The result needs to be multiplied by BSDF or Phase Function. */ +float light_point_light(LightData ld, const bool is_directional, vec3 L, float dist) +{ + if (is_directional) { + return 1.0; + } + /** + * Using "Point Light Attenuation Without Singularity" from Cem Yuksel + * http://www.cemyuksel.com/research/pointlightattenuation/pointlightattenuation.pdf + * http://www.cemyuksel.com/research/pointlightattenuation/ + **/ + float d_sqr = sqr(dist); + float r_sqr = ld.radius_squared; + /* Using reformulation that has better numerical percision. */ + float power = 2.0 / (d_sqr + r_sqr + dist * sqrt(d_sqr + r_sqr)); + + if (is_area_light(ld.type)) { + /* Modulate by light plane orientation / solid angle. */ + power *= saturate(dot(ld._back, L)); + } + return power; +} + +float light_diffuse(sampler2DArray utility_tx, + const bool is_directional, + LightData ld, + vec3 N, + vec3 V, + vec3 L, + float dist) +{ + if (is_directional || !is_area_light(ld.type)) { + float radius = ld._radius / dist; + return ltc_evaluate_disk_simple(utility_tx, radius, dot(N, L)); + } + else if (ld.type == LIGHT_RECT) { + vec3 corners[4]; + corners[0] = ld._right * ld._area_size_x + ld._up * -ld._area_size_y; + corners[1] = ld._right * ld._area_size_x + ld._up * ld._area_size_y; + corners[2] = -corners[0]; + corners[3] = -corners[1]; + + corners[0] = normalize(L * dist + corners[0]); + corners[1] = normalize(L * dist + corners[1]); + corners[2] = normalize(L * dist + corners[2]); + corners[3] = normalize(L * dist + corners[3]); + + return ltc_evaluate_quad(utility_tx, corners, N); + } + else /* (ld.type == LIGHT_ELLIPSE) */ { + vec3 points[3]; + points[0] = ld._right * -ld._area_size_x + ld._up * -ld._area_size_y; + points[1] = ld._right * ld._area_size_x + ld._up * -ld._area_size_y; + points[2] = -points[0]; + + points[0] += L * dist; + points[1] += L * dist; + points[2] += L * dist; + + return ltc_evaluate_disk(utility_tx, N, V, mat3(1.0), points); + } +} + +float light_ltc(sampler2DArray utility_tx, + const bool is_directional, + LightData ld, + vec3 N, + vec3 V, + vec3 L, + float dist, + vec4 ltc_mat) +{ + if (is_directional || ld.type != LIGHT_RECT) { + vec3 Px = ld._right; + vec3 Py = ld._up; + + if (is_directional || !is_area_light(ld.type)) { + make_orthonormal_basis(L, Px, Py); + } + + vec3 points[3]; + points[0] = Px * -ld._area_size_x + Py * -ld._area_size_y; + points[1] = Px * ld._area_size_x + Py * -ld._area_size_y; + points[2] = -points[0]; + + points[0] += L * dist; + points[1] += L * dist; + points[2] += L * dist; + + return ltc_evaluate_disk(utility_tx, N, V, ltc_matrix(ltc_mat), points); + } + else { + vec3 corners[4]; + corners[0] = ld._right * ld._area_size_x + ld._up * -ld._area_size_y; + corners[1] = ld._right * ld._area_size_x + ld._up * ld._area_size_y; + corners[2] = -corners[0]; + corners[3] = -corners[1]; + + corners[0] += L * dist; + corners[1] += L * dist; + corners[2] += L * dist; + corners[3] += L * dist; + + ltc_transform_quad(N, V, ltc_matrix(ltc_mat), corners); + + return ltc_evaluate_quad(utility_tx, corners, vec3(0.0, 0.0, 1.0)); + } +} + +vec3 light_translucent(sampler1D transmittance_tx, + const bool is_directional, + LightData ld, + vec3 N, + vec3 L, + float dist, + vec3 sss_radius, + float delta) +{ + /* TODO(fclem): We should compute the power at the entry point. */ + /* NOTE(fclem): we compute the light attenuation using the light vector but the transmittance + * using the shadow depth delta. */ + float power = light_point_light(ld, is_directional, L, dist); + /* Do not add more energy on front faces. Also apply lambertian BSDF. */ + power *= max(0.0, dot(-N, L)) * M_1_PI; + + sss_radius *= SSS_TRANSMIT_LUT_RADIUS; + vec3 channels_co = saturate(delta / sss_radius) * SSS_TRANSMIT_LUT_SCALE + SSS_TRANSMIT_LUT_BIAS; + + vec3 translucency; + translucency.x = (sss_radius.x > 0.0) ? texture(transmittance_tx, channels_co.x).r : 0.0; + translucency.y = (sss_radius.y > 0.0) ? texture(transmittance_tx, channels_co.y).r : 0.0; + translucency.z = (sss_radius.z > 0.0) ? texture(transmittance_tx, channels_co.z).r : 0.0; + return translucency * power; +} + +/** \} */ |