diff options
Diffstat (limited to 'source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl')
-rw-r--r-- | source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl | 312 |
1 files changed, 312 insertions, 0 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 new file mode 100644 index 00000000000..ef8af646ec1 --- /dev/null +++ b/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl @@ -0,0 +1,312 @@ + +#define M_PI 3.14159265358979323846 /* pi */ +#define M_PI_2 1.57079632679489661923 /* pi/2 */ +#define M_1_PI 0.318309886183790671538 /* 1/pi */ +#define M_1_2PI 0.159154943091895335768 /* 1/(2*pi) */ +#define M_1_PI2 0.101321183642337771443 /* 1/(pi^2) */ + +/* ------- Structures -------- */ + +struct LightData { + vec4 position_influence; /* w : InfluenceRadius */ + vec4 color_spec; /* w : Spec Intensity */ + vec4 spotdata_radius_shadow; /* x : spot size, y : spot blend, z : radius, w: shadow id */ + vec4 rightvec_sizex; /* xyz: Normalized up vector, w: area size X or spot scale X */ + vec4 upvec_sizey; /* xyz: Normalized right vector, w: area size Y or spot scale Y */ + vec4 forwardvec_type; /* xyz: Normalized forward vector, w: Lamp Type */ +}; + +/* convenience aliases */ +#define l_color color_spec.rgb +#define l_spec color_spec.a +#define l_position position_influence.xyz +#define l_influence position_influence.w +#define l_sizex rightvec_sizex.w +#define l_sizey upvec_sizey.w +#define l_right rightvec_sizex.xyz +#define l_up upvec_sizey.xyz +#define l_forward forwardvec_type.xyz +#define l_type forwardvec_type.w +#define l_spot_size spotdata_radius_shadow.x +#define l_spot_blend spotdata_radius_shadow.y +#define l_radius spotdata_radius_shadow.z +#define l_shadowid spotdata_radius_shadow.w + + +struct ShadowCubeData { + vec4 near_far_bias; +}; + +/* convenience aliases */ +#define sh_cube_near near_far_bias.x +#define sh_cube_far near_far_bias.y +#define sh_cube_bias near_far_bias.z + + +struct ShadowMapData { + mat4 shadowmat; + vec4 near_far_bias; +}; + +/* convenience aliases */ +#define sh_map_near near_far_bias.x +#define sh_map_far near_far_bias.y +#define sh_map_bias near_far_bias.z + +#ifndef MAX_CASCADE_NUM +#define MAX_CASCADE_NUM 4 +#endif + +struct ShadowCascadeData { + mat4 shadowmat[MAX_CASCADE_NUM]; + /* arrays of float are not aligned so use vec4 */ + vec4 split_distances; + 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 --------- */ + +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 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 line_aligned_plane_intersect_dist(vec3 lineorigin, vec3 linedirection, vec3 planeorigin) +{ + /* aligned plane normal */ + vec3 L = planeorigin - lineorigin; + float diskdist = length(L); + vec3 planenormal = -normalize(L); + return -diskdist / dot(planenormal, linedirection); +} + +vec3 line_aligned_plane_intersect(vec3 lineorigin, vec3 linedirection, vec3 planeorigin) +{ + float dist = line_aligned_plane_intersect_dist(lineorigin, linedirection, planeorigin); + if (dist < 0) { + /* if intersection is behind we fake the intersection to be + * really far and (hopefully) not inside the radius of interest */ + dist = 1e16; + } + return lineorigin + linedirection * dist; +} + +/* -- Tangent Space conversion -- */ +vec3 tangent_to_world(vec3 vector, vec3 N, vec3 T, vec3 B) +{ + return T * vector.x + B * vector.y + N * vector.z; +} + +vec3 world_to_tangent(vec3 vector, vec3 N, vec3 T, vec3 B) +{ + return vec3( dot(T, vector), dot(B, vector), dot(N, vector)); +} + +void make_orthonormal_basis(vec3 N, out vec3 T, out vec3 B) +{ + vec3 UpVector = abs(N.z) < 0.99999 ? vec3(0.0,0.0,1.0) : vec3(1.0,0.0,0.0); + T = normalize( cross(UpVector, N) ); + B = cross(N, T); +} + +/* ---- Opengl Depth conversion ---- */ +float linear_depth(bool is_persp, float z, float zf, float zn) +{ + if (is_persp) { + return (zn * zf) / (z * (zn - zf) + zf); + } + else { + return (z * 2.0 - 1.0) * zf; + } +} + +float buffer_depth(bool is_persp, float z, float zf, float zn) +{ + if (is_persp) { + return (zf * (zn - z)) / (z * (zn - zf)); + } + else { + return (z / (zf * 2.0)) + 0.5; + } +} + +#define spherical_harmonics spherical_harmonics_L2 + +/* http://seblagarde.wordpress.com/2012/01/08/pi-or-not-to-pi-in-game-lighting-equation/ */ +vec3 spherical_harmonics_L1(vec3 N, vec3 shcoefs[9]) +{ + vec3 sh = vec3(0.0); + + sh += 0.282095 * shcoefs[0]; + + sh += -0.488603 * N.z * shcoefs[1]; + sh += 0.488603 * N.y * shcoefs[2]; + sh += -0.488603 * N.x * shcoefs[3]; + + return sh; +} + +vec3 spherical_harmonics_L2(vec3 N, vec3 shcoefs[9]) +{ + vec3 sh = vec3(0.0); + + sh += 0.282095 * shcoefs[0]; + + sh += -0.488603 * N.z * shcoefs[1]; + sh += 0.488603 * N.y * shcoefs[2]; + sh += -0.488603 * N.x * shcoefs[3]; + + sh += 1.092548 * N.x * N.z * shcoefs[4]; + sh += -1.092548 * N.z * N.y * shcoefs[5]; + sh += 0.315392 * (3.0 * N.y * N.y - 1.0) * shcoefs[6]; + sh += -1.092548 * N.x * N.y * shcoefs[7]; + sh += 0.546274 * (N.x * N.x - N.z * N.z) * shcoefs[8]; + + 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; + float fac = smoothness * (sqrt(smoothness) + 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) +{ + float fac = pow(1.0 - cos_theta, 5); + return f0 + (1.0 - f0) * fac; +} + +/* 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 */ +} |