diff options
author | Julian Eisel <eiseljulian@gmail.com> | 2018-01-30 00:53:32 +0300 |
---|---|---|
committer | Julian Eisel <eiseljulian@gmail.com> | 2018-01-30 01:24:11 +0300 |
commit | 3f0871dfcfbb1dda15c176dba92d36639305385a (patch) | |
tree | de7ffeeef7a99fc6103d413ebfa564596811087d /source/blender/draw/engines/eevee/shaders | |
parent | 53d94dafc474380651fc529f9c03f84ce7142b13 (diff) | |
parent | 1fe2b4bf608b22ae4513051e01cf45e5012c2409 (diff) |
Merge branch 'blender2.8' into topbar
Diffstat (limited to 'source/blender/draw/engines/eevee/shaders')
26 files changed, 793 insertions, 716 deletions
diff --git a/source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl b/source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl index 5ec72833379..55f66f5500a 100644 --- a/source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl @@ -30,87 +30,18 @@ #ifndef UTIL_TEX #define UTIL_TEX uniform sampler2DArray utilTex; +#define texelfetch_noise_tex(coord) texelFetch(utilTex, ivec3(ivec2(coord) % LUT_SIZE, 2.0), 0) #endif /* UTIL_TEX */ -uniform vec4 aoParameters[2]; -uniform sampler2DArray horizonBuffer; - -/* Cannot use textureSize(horizonBuffer) when rendering to it */ -uniform ivec2 aoHorizonTexSize; - -#define aoDistance aoParameters[0].x -#define aoSamples aoParameters[0].y -#define aoFactor aoParameters[0].z -#define aoInvSamples aoParameters[0].w - -#define aoOffset aoParameters[1].x /* UNUSED */ -#define aoBounceFac aoParameters[1].y -#define aoQuality aoParameters[1].z -#define aoSettings aoParameters[1].w +uniform sampler2D horizonBuffer; +/* aoSettings flags */ #define USE_AO 1 #define USE_BENT_NORMAL 2 #define USE_DENOISE 4 -vec2 pack_horizons(vec2 v) { return v * 0.5 + 0.5; } -vec2 unpack_horizons(vec2 v) { return v * 2.0 - 1.0; } - -/* Returns the texel coordinate in horizonBuffer - * for a given fullscreen coord */ -ivec2 get_hr_co(ivec2 fs_co) -{ - bvec2 quarter = notEqual(fs_co & ivec2(1), ivec2(0)); - - ivec2 hr_co = fs_co / 2; - hr_co += ivec2(quarter) * (aoHorizonTexSize / 2); - - return hr_co; -} - -/* Returns the texel coordinate in fullscreen (depthBuffer) - * for a given horizonBuffer coord */ -ivec2 get_fs_co(ivec2 hr_co) -{ - hr_co *= 2; - bvec2 quarter = greaterThanEqual(hr_co, aoHorizonTexSize); - - hr_co -= ivec2(quarter) * (aoHorizonTexSize - 1); - - return hr_co; -} - -/* Returns the phi angle in horizonBuffer - * for a given horizonBuffer coord */ -float get_phi(ivec2 hr_co, ivec2 fs_co, float sample) -{ - bvec2 quarter = greaterThanEqual(hr_co, aoHorizonTexSize / 2); - ivec2 tex_co = ((int(aoSettings) & USE_DENOISE) != 0) ? hr_co - ivec2(quarter) * (aoHorizonTexSize / 2) : fs_co; - float blue_noise = texture(utilTex, vec3((vec2(tex_co) + 0.5) / LUT_SIZE, 2.0)).r; - - float phi = sample * aoInvSamples; - - if ((int(aoSettings) & USE_DENOISE) != 0) { - /* Interleaved jitter for spatial 2x2 denoising */ - phi += 0.25 * aoInvSamples * (float(quarter.x) + 2.0 * float(quarter.y)); - blue_noise *= 0.25; - } - /* Blue noise is scaled to cover the rest of the range. */ - phi += aoInvSamples * blue_noise; - phi *= M_PI; - - return phi; -} - -/* Returns direction jittered offset for a given fullscreen coord */ -float get_offset(ivec2 fs_co, float sample) -{ - float offset = sample * aoInvSamples; - - /* Interleaved jitter for spatial 2x2 denoising */ - offset += 0.25 * dot(vec2(1.0), vec2(fs_co & 1)); - offset += texture(utilTex, vec3((vec2(fs_co / 2) + 0.5 + 16.0) / LUT_SIZE, 2.0)).r; - return offset; -} +vec4 pack_horizons(vec4 v) { return v * 0.5 + 0.5; } +vec4 unpack_horizons(vec4 v) { return v * 2.0 - 1.0; } /* Returns maximum screen distance an AO ray can travel for a given view depth */ vec2 get_max_dir(float view_depth) @@ -120,6 +51,13 @@ vec2 get_max_dir(float view_depth) return vec2(ProjectionMatrix[0][0], ProjectionMatrix[1][1]) * max_dist; } +vec2 get_ao_dir(float jitter) +{ + /* Only half a turn because we integrate in slices. */ + jitter *= M_PI; + return vec2(cos(jitter), sin(jitter)); +} + void get_max_horizon_grouped(vec4 co1, vec4 co2, vec3 x, float lod, inout float h) { co1 *= mipRatio[int(lod + 1.0)].xyxy; /* +1 because we are using half res top level */ @@ -161,10 +99,8 @@ void get_max_horizon_grouped(vec4 co1, vec4 co2, vec3 x, float lod, inout float h = mix(h, max(h, s_h.w), blend.w); } -vec2 search_horizon_sweep(float phi, vec3 pos, vec2 uvs, float jitter, vec2 max_dir) +vec2 search_horizon_sweep(vec2 t_phi, vec3 pos, vec2 uvs, float jitter, vec2 max_dir) { - vec2 t_phi = vec2(cos(phi), sin(phi)); /* Screen space direction */ - max_dir *= max_v2(abs(t_phi)); /* Convert to pixel space. */ @@ -214,11 +150,8 @@ vec2 search_horizon_sweep(float phi, vec3 pos, vec2 uvs, float jitter, vec2 max_ return h; } -void integrate_slice(vec3 normal, float phi, vec2 horizons, inout float visibility, inout vec3 bent_normal) +void integrate_slice(vec3 normal, vec2 t_phi, vec2 horizons, inout float visibility, inout vec3 bent_normal) { - /* TODO OPTI Could be precomputed. */ - vec2 t_phi = vec2(cos(phi), sin(phi)); /* Screen space direction */ - /* Projecting Normal to Plane P defined by t_phi and omega_o */ vec3 np = vec3(t_phi.y, -t_phi.x, 0.0); /* Normal vector to Integration plane */ vec3 t = vec3(-t_phi, 0.0); @@ -251,71 +184,43 @@ void integrate_slice(vec3 normal, float phi, vec2 horizons, inout float visibili bent_normal += vec3(sin(b_angle) * -t_phi, cos(b_angle) * 0.5); } -void denoise_ao(vec3 normal, float frag_depth, inout float visibility, inout vec3 bent_normal) +void gtao_deferred(vec3 normal, vec3 position, vec4 noise, float frag_depth, out float visibility, out vec3 bent_normal) { - vec2 d_sign = vec2(ivec2(gl_FragCoord.xy) & 1) - 0.5; - - if ((int(aoSettings) & USE_DENOISE) == 0) { - d_sign *= 0.0; - } - - /* 2x2 Bilateral Filter using derivatives. */ - vec2 n_step = step(-0.2, -abs(vec2(length(dFdx(normal)), length(dFdy(normal))))); - vec2 z_step = step(-0.1, -abs(vec2(dFdx(frag_depth), dFdy(frag_depth)))); - - visibility -= dFdx(visibility) * d_sign.x * z_step.x * n_step.x; - visibility -= dFdy(visibility) * d_sign.y * z_step.y * n_step.y; + /* Fetch early, hide latency! */ + vec4 horizons = texelFetch(horizonBuffer, ivec2(gl_FragCoord.xy), 0); - bent_normal -= dFdx(bent_normal) * d_sign.x * z_step.x * n_step.x; - bent_normal -= dFdy(bent_normal) * d_sign.y * z_step.y * n_step.y; -} - -void gtao_deferred(vec3 normal, vec3 position, float frag_depth, out float visibility, out vec3 bent_normal) -{ + vec4 dirs; + dirs.xy = get_ao_dir(noise.x * 0.5); + dirs.zw = get_ao_dir(noise.x * 0.5 + 0.5); vec2 uvs = get_uvs_from_view(position); - vec4 texel_size = vec4(-1.0, -1.0, 1.0, 1.0) / vec2(textureSize(depthBuffer, 0)).xyxy; - - ivec2 fs_co = ivec2(gl_FragCoord.xy); - ivec2 hr_co = get_hr_co(fs_co); - bent_normal = vec3(0.0); visibility = 0.0; - for (float i = 0.0; i < MAX_PHI_STEP; i++) { - if (i >= aoSamples) break; + horizons = unpack_horizons(horizons); - vec2 horiz = unpack_horizons(texelFetch(horizonBuffer, ivec3(hr_co, int(i)), 0).rg); - float phi = get_phi(hr_co, fs_co, i); + integrate_slice(normal, dirs.xy, horizons.xy, visibility, bent_normal); + integrate_slice(normal, dirs.zw, horizons.zw, visibility, bent_normal); - integrate_slice(normal, phi, horiz.xy, visibility, bent_normal); - } + visibility *= 0.5; /* We integrated 2 slices. */ - visibility *= aoInvSamples; bent_normal = normalize(bent_normal); } -void gtao(vec3 normal, vec3 position, vec2 noise, out float visibility, out vec3 bent_normal) +void gtao(vec3 normal, vec3 position, vec4 noise, out float visibility, out vec3 bent_normal) { vec2 uvs = get_uvs_from_view(position); - - float homcco = ProjectionMatrix[2][3] * position.z + ProjectionMatrix[3][3]; - float max_dist = aoDistance / homcco; /* Search distance */ - vec2 max_dir = max_dist * vec2(ProjectionMatrix[0][0], ProjectionMatrix[1][1]); + vec2 max_dir = get_max_dir(position.z); + vec2 dir = get_ao_dir(noise.x); bent_normal = vec3(0.0); visibility = 0.0; - for (float i = 0.0; i < MAX_PHI_STEP; i++) { - if (i >= aoSamples) break; - - float phi = M_PI * (i + noise.x) * aoInvSamples; - vec2 horizons = search_horizon_sweep(phi, position, uvs, noise.g, max_dir); - - integrate_slice(normal, phi, horizons, visibility, bent_normal); - } + /* Only trace in 2 directions. May lead to a darker result but since it's mostly for + * alpha blended objects that will have overdraw, we limit the performance impact. */ + vec2 horizons = search_horizon_sweep(dir, position, uvs, noise.y, max_dir); + integrate_slice(normal, dir, horizons, visibility, bent_normal); - visibility *= aoInvSamples; bent_normal = normalize(bent_normal); } @@ -337,7 +242,7 @@ float gtao_multibounce(float visibility, vec3 albedo) } /* Use the right occlusion */ -float occlusion_compute(vec3 N, vec3 vpos, float user_occlusion, vec2 randuv, out vec3 bent_normal) +float occlusion_compute(vec3 N, vec3 vpos, float user_occlusion, vec4 rand, out vec3 bent_normal) { #ifndef USE_REFRACTION if ((int(aoSettings) & USE_AO) > 0) { @@ -345,11 +250,10 @@ float occlusion_compute(vec3 N, vec3 vpos, float user_occlusion, vec2 randuv, ou vec3 vnor = mat3(ViewMatrix) * N; #ifdef ENABLE_DEFERED_AO - gtao_deferred(vnor, vpos, gl_FragCoord.z, visibility, bent_normal); + gtao_deferred(vnor, vpos, rand, gl_FragCoord.z, visibility, bent_normal); #else - gtao(vnor, vpos, randuv, visibility, bent_normal); + gtao(vnor, vpos, rand, visibility, bent_normal); #endif - denoise_ao(vnor, gl_FragCoord.z, visibility, bent_normal); /* Prevent some problems down the road. */ visibility = max(1e-3, visibility); 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 37ed2235c6f..68299fe7546 100644 --- a/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl @@ -11,7 +11,6 @@ uniform mat4 ProjectionMatrix; uniform mat4 ViewProjectionMatrix; uniform mat4 ViewMatrixInverse; -uniform vec4 viewvecs[2]; #ifndef SHADOW_SHADER uniform mat4 ViewMatrix; #else @@ -31,8 +30,6 @@ flat in int shFace; /* Shadow layer we are rendering to. */ #define ViewMatrix FaceViewMatrix[shFace] #endif -uniform vec2 mipRatio[10]; - /* Buffers */ uniform sampler2D colorBuffer; uniform sampler2D depthBuffer; @@ -125,6 +122,10 @@ float min_v3(vec3 v) { return min(v.x, min(v.y, v.z)); } float max_v2(vec2 v) { return max(v.x, v.y); } float max_v3(vec3 v) { return max(v.x, max(v.y, v.z)); } +float sum(vec2 v) { return dot(vec2(1.0), v); } +float sum(vec3 v) { return dot(vec3(1.0), v); } +float sum(vec4 v) { return dot(vec4(1.0), v); } + float saturate(float a) { return clamp(a, 0.0, 1.0); } vec2 saturate(vec2 a) { return clamp(a, 0.0, 1.0); } vec3 saturate(vec3 a) { return clamp(a, 0.0, 1.0); } @@ -300,7 +301,7 @@ float get_view_z_from_depth(float depth) return -ProjectionMatrix[3][2] / (d + ProjectionMatrix[2][2]); } else { - return viewvecs[0].z + depth * viewvecs[1].z; + return viewVecs[0].z + depth * viewVecs[1].z; } } @@ -311,7 +312,7 @@ float get_depth_from_view_z(float z) return d * 0.5 + 0.5; } else { - return (z - viewvecs[0].z) / viewvecs[1].z; + return (z - viewVecs[0].z) / viewVecs[1].z; } } @@ -324,10 +325,10 @@ vec2 get_uvs_from_view(vec3 view) vec3 get_view_space_from_depth(vec2 uvcoords, float depth) { if (ProjectionMatrix[3][3] == 0.0) { - return (viewvecs[0].xyz + vec3(uvcoords, 0.0) * viewvecs[1].xyz) * get_view_z_from_depth(depth); + return (viewVecs[0].xyz + vec3(uvcoords, 0.0) * viewVecs[1].xyz) * get_view_z_from_depth(depth); } else { - return viewvecs[0].xyz + vec3(uvcoords, depth) * viewvecs[1].xyz; + return viewVecs[0].xyz + vec3(uvcoords, depth) * viewVecs[1].xyz; } } @@ -545,7 +546,7 @@ vec3 F_schlick(vec3 f0, float cos_theta) /* Fresnel approximation for LTC area lights (not MRP) */ vec3 F_area(vec3 f0, vec2 lut) { - vec2 fac = normalize(lut.xy); + vec2 fac = normalize(lut.xy); /* XXX FIXME this does not work!!! */ /* Unreal specular matching : if specular color is below 2% intensity, * treat as shadowning */ @@ -691,7 +692,6 @@ Closure closure_mix(Closure cl1, Closure cl2, float fac) } else { cl.ssr_data = mix(vec4(vec3(0.0), cl2.ssr_data.w), cl2.ssr_data.xyzw, fac); /* do not blend roughness */ - cl.ssr_data = mix(vec4(vec3(0.0), cl2.ssr_data.w), cl2.ssr_data.xyzw, fac); /* do not blend roughness */ cl.ssr_normal = cl2.ssr_normal; cl.ssr_id = cl2.ssr_id; } @@ -739,12 +739,10 @@ Closure closure_add(Closure cl1, Closure cl2) #endif #endif cl.radiance = cl1.radiance + cl2.radiance; - cl.opacity = cl1.opacity + cl2.opacity; + cl.opacity = saturate(cl1.opacity + cl2.opacity); return cl; } -uniform bool sssToggle; - #if defined(MESH_SHADER) && !defined(USE_ALPHA_HASH) && !defined(USE_ALPHA_CLIP) && !defined(SHADOW_SHADER) && !defined(USE_MULTIPLY) layout(location = 0) out vec4 fragColor; #ifdef USE_SSS @@ -774,6 +772,10 @@ vec4 volumetric_resolve(vec4 scene_color, vec2 frag_uvs, float frag_depth); void main() { Closure cl = nodetree_exec(); +#ifndef USE_ALPHA_BLEND + /* Prevent alpha hash material writing into alpha channel. */ + cl.opacity = 1.0; +#endif #if defined(USE_ALPHA_BLEND_VOLUMETRICS) /* XXX fragile, better use real viewport resolution */ 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 ae03f22ac14..ddc7327334c 100644 --- a/source/blender/draw/engines/eevee/shaders/bsdf_direct_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/bsdf_direct_lib.glsl @@ -28,56 +28,30 @@ float direct_diffuse_sun(LightData ld, vec3 N) return bsdf; } -/* From Frostbite PBR Course - * Analytical irradiance from a sphere with correct horizon handling - * http://www.frostbite.com/wp-content/uploads/2014/11/course_notes_moving_frostbite_to_pbr.pdf */ +#ifdef USE_LTC float direct_diffuse_sphere(LightData ld, vec3 N, vec4 l_vector) { - float dist = l_vector.w; - vec3 L = l_vector.xyz / dist; - float radius = max(ld.l_sizex, 0.0001); - float costheta = clamp(dot(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; - - 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); - } - - bsdf = max(bsdf, 0.0); - bsdf *= M_1_PI2; + float NL = dot(N, l_vector.xyz / l_vector.w); - return bsdf; + return ltc_evaluate_disk_simple(ld.l_radius / l_vector.w, NL); } -#ifdef USE_LTC float direct_diffuse_rectangle(LightData ld, vec3 N, vec3 V, vec4 l_vector) { vec3 corners[4]; - corners[0] = l_vector.xyz + ld.l_right * -ld.l_sizex + ld.l_up * ld.l_sizey; - corners[1] = l_vector.xyz + ld.l_right * -ld.l_sizex + ld.l_up * -ld.l_sizey; - corners[2] = l_vector.xyz + ld.l_right * ld.l_sizex + ld.l_up * -ld.l_sizey; - corners[3] = l_vector.xyz + ld.l_right * ld.l_sizex + ld.l_up * ld.l_sizey; + corners[0] = normalize(l_vector.xyz + ld.l_right * -ld.l_sizex + ld.l_up * ld.l_sizey); + corners[1] = normalize(l_vector.xyz + ld.l_right * -ld.l_sizex + ld.l_up * -ld.l_sizey); + corners[2] = normalize(l_vector.xyz + ld.l_right * ld.l_sizex + ld.l_up * -ld.l_sizey); + corners[3] = normalize(l_vector.xyz + ld.l_right * ld.l_sizex + ld.l_up * ld.l_sizey); - float bsdf = ltc_evaluate(N, V, mat3(1.0), corners); - bsdf *= M_1_2PI; - return bsdf; + return ltc_evaluate_quad(corners, N); } -#endif -#if 0 -float direct_diffuse_unit_disc(vec3 N, vec3 L) +float direct_diffuse_unit_disc(LightData ld, vec3 N, vec3 V) { + float NL = dot(N, -ld.l_forward); + return ltc_evaluate_disk_simple(ld.l_radius, NL); } #endif @@ -106,47 +80,27 @@ vec3 direct_ggx_sun(LightData ld, vec3 N, vec3 V, float roughness, vec3 f0) #ifdef USE_LTC vec3 direct_ggx_sphere(LightData ld, vec3 N, vec3 V, vec4 l_vector, float roughness, vec3 f0) { - vec3 L = l_vector.xyz / l_vector.w; - vec3 spec_dir = get_specular_reflection_dominant_dir(N, V, roughness); - vec3 P = line_aligned_plane_intersect(vec3(0.0), spec_dir, l_vector.xyz); - - vec3 Px = normalize(P - l_vector.xyz) * ld.l_radius; - vec3 Py = cross(Px, L); + roughness = clamp(roughness, 0.0008, 0.999); /* Fix low roughness artifacts. */ vec2 uv = lut_coords(dot(N, V), sqrt(roughness)); vec3 brdf_lut = texture(utilTex, vec3(uv, 1.0)).rgb; vec4 ltc_lut = texture(utilTex, vec3(uv, 0.0)).rgba; mat3 ltc_mat = ltc_matrix(ltc_lut); -// #define HIGHEST_QUALITY -#ifdef HIGHEST_QUALITY - vec3 Pxy1 = normalize( Px + Py) * ld.l_radius; - vec3 Pxy2 = normalize(-Px + Py) * ld.l_radius; - - /* counter clockwise */ - vec3 points[8]; - points[0] = l_vector.xyz + Px; - points[1] = l_vector.xyz - Pxy2; - points[2] = l_vector.xyz - Py; - points[3] = l_vector.xyz - Pxy1; - points[4] = l_vector.xyz - Px; - points[5] = l_vector.xyz + Pxy2; - points[6] = l_vector.xyz + Py; - points[7] = l_vector.xyz + Pxy1; - float bsdf = ltc_evaluate_circle(N, V, ltc_mat, points); -#else - vec3 points[4]; - points[0] = l_vector.xyz + Px; - points[1] = l_vector.xyz - Py; - points[2] = l_vector.xyz - Px; - points[3] = l_vector.xyz + Py; - float bsdf = ltc_evaluate(N, V, ltc_mat, points); - /* sqrt(pi/2) difference between square and disk area */ - bsdf *= 1.25331413731; -#endif + /* Make orthonormal basis. */ + vec3 L = l_vector.xyz / l_vector.w; + vec3 Px, Py; + make_orthonormal_basis(L, Px, Py); + Px *= ld.l_radius; + Py *= ld.l_radius; + vec3 points[3]; + points[0] = l_vector.xyz - Px - Py; + points[1] = l_vector.xyz + Px - Py; + points[2] = l_vector.xyz + Px + Py; + + float bsdf = ltc_evaluate_disk(N, V, ltc_mat, points); bsdf *= brdf_lut.b; /* Bsdf intensity */ - bsdf *= M_1_2PI * M_1_PI; vec3 spec = F_area(f0, brdf_lut.xy) * bsdf; @@ -165,19 +119,38 @@ vec3 direct_ggx_rectangle(LightData ld, vec3 N, vec3 V, vec4 l_vector, float rou vec3 brdf_lut = texture(utilTex, vec3(uv, 1.0)).rgb; vec4 ltc_lut = texture(utilTex, vec3(uv, 0.0)).rgba; mat3 ltc_mat = ltc_matrix(ltc_lut); - float bsdf = ltc_evaluate(N, V, ltc_mat, corners); + + ltc_transform_quad(N, V, ltc_mat, corners); + float bsdf = ltc_evaluate_quad(corners, vec3(0.0, 0.0, 1.0)); bsdf *= brdf_lut.b; /* Bsdf intensity */ - bsdf *= M_1_2PI; vec3 spec = F_area(f0, brdf_lut.xy) * bsdf; return spec; } -#endif -#if 0 -float direct_ggx_disc(vec3 N, vec3 L) +vec3 direct_ggx_unit_disc(LightData ld, vec3 N, vec3 V, float roughness, vec3 f0) { + roughness = clamp(roughness, 0.0004, 0.999); /* Fix low roughness artifacts. */ + + vec2 uv = lut_coords(dot(N, V), sqrt(roughness)); + vec3 brdf_lut = texture(utilTex, vec3(uv, 1.0)).rgb; + vec4 ltc_lut = texture(utilTex, vec3(uv, 0.0)).rgba; + mat3 ltc_mat = ltc_matrix(ltc_lut); + vec3 Px = ld.l_right * ld.l_radius; + vec3 Py = ld.l_up * ld.l_radius; + + vec3 points[3]; + points[0] = -ld.l_forward - Px - Py; + points[1] = -ld.l_forward + Px - Py; + points[2] = -ld.l_forward + Px + Py; + + float bsdf = ltc_evaluate_disk(N, V, ltc_mat, points); + bsdf *= brdf_lut.b; /* Bsdf intensity */ + + vec3 spec = F_area(f0, brdf_lut.xy) * bsdf; + + return spec; } #endif
\ No newline at end of file diff --git a/source/blender/draw/engines/eevee/shaders/bsdf_sampling_lib.glsl b/source/blender/draw/engines/eevee/shaders/bsdf_sampling_lib.glsl index 13586619fe9..e5c0cb9c9c9 100644 --- a/source/blender/draw/engines/eevee/shaders/bsdf_sampling_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/bsdf_sampling_lib.glsl @@ -9,12 +9,12 @@ vec2 jitternoise = vec2(0.0); #ifndef UTIL_TEX #define UTIL_TEX uniform sampler2DArray utilTex; +#define texelfetch_noise_tex(coord) texelFetch(utilTex, ivec3(ivec2(coord) % LUT_SIZE, 2.0), 0) #endif /* UTIL_TEX */ void setup_noise(void) { - jitternoise = texture(utilTex, vec3(gl_FragCoord.xy / LUT_SIZE, 2.0)).rg; /* Global variable */ - jitternoise.g = (jitternoise.g - 0.5) * 2.0; + jitternoise = texelfetch_noise_tex(gl_FragCoord.xy).rg; /* Global variable */ } #ifdef HAMMERSLEY_SIZE diff --git a/source/blender/draw/engines/eevee/shaders/common_uniforms_lib.glsl b/source/blender/draw/engines/eevee/shaders/common_uniforms_lib.glsl new file mode 100644 index 00000000000..37106fc32bd --- /dev/null +++ b/source/blender/draw/engines/eevee/shaders/common_uniforms_lib.glsl @@ -0,0 +1,55 @@ + +layout(std140) uniform common_block { + mat4 pastViewProjectionMatrix; + vec4 viewVecs[2]; + vec2 mipRatio[10]; /* To correct mip level texel mis-alignement */ + /* Ambient Occlusion */ + vec4 aoParameters[2]; + /* Volumetric */ + ivec4 volTexSize; + vec4 volDepthParameters; /* Parameters to the volume Z equation */ + vec4 volInvTexSize; + vec4 volJitter; + vec4 volCoordScale; /* To convert volume uvs to screen uvs */ + float volHistoryAlpha; + float volLightClamp; + float volShadowSteps; + bool volUseLights; + /* Screen Space Reflections */ + vec4 ssrParameters; + float ssrBorderFac; + float ssrMaxRoughness; + float ssrFireflyFac; + float ssrBrdfBias; + bool ssrToggle; + /* SubSurface Scattering */ + float sssJitterThreshold; + bool sssToggle; + /* Specular */ + bool specToggle; + /* Lamps */ + int laNumLight; + /* Probes */ + int prbNumPlanar; + int prbNumRenderCube; + int prbNumRenderGrid; + int prbIrradianceVisSize; + float prbLodCubeMax; + float prbLodPlanarMax; +}; + +/* aoParameters */ +#define aoDistance aoParameters[0].x +#define aoSamples aoParameters[0].y /* UNUSED */ +#define aoFactor aoParameters[0].z +#define aoInvSamples aoParameters[0].w /* UNUSED */ + +#define aoOffset aoParameters[1].x /* UNUSED */ +#define aoBounceFac aoParameters[1].y +#define aoQuality aoParameters[1].z +#define aoSettings aoParameters[1].w + +/* ssrParameters */ +#define ssrQuality ssrParameters.x +#define ssrThickness ssrParameters.y +#define ssrPixelSize ssrParameters.zw
\ No newline at end of file diff --git a/source/blender/draw/engines/eevee/shaders/default_frag.glsl b/source/blender/draw/engines/eevee/shaders/default_frag.glsl index 45c5c88e763..6d941ae6ec3 100644 --- a/source/blender/draw/engines/eevee/shaders/default_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/default_frag.glsl @@ -11,7 +11,7 @@ Closure nodetree_exec(void) vec3 f0 = mix(dielectric, basecol, metallic); vec3 N = (gl_FrontFacing) ? worldNormal : -worldNormal; vec3 out_diff, out_spec, ssr_spec; - eevee_closure_default(N, albedo, f0, 0, roughness, 1.0, out_diff, out_spec, ssr_spec); + eevee_closure_default(N, albedo, f0, 1, roughness, 1.0, out_diff, out_spec, ssr_spec); Closure result = Closure(out_spec + out_diff * albedo, 1.0, vec4(ssr_spec, roughness), normal_encode(normalize(viewNormal), viewCameraVec), 0); diff --git a/source/blender/draw/engines/eevee/shaders/effect_gtao_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_gtao_frag.glsl index 1c63051c65b..32edf709d88 100644 --- a/source/blender/draw/engines/eevee/shaders/effect_gtao_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/effect_gtao_frag.glsl @@ -12,8 +12,8 @@ uniform sampler2D normalBuffer; void main() { - vec4 texel_size = 1.0 / vec2(textureSize(depthBuffer, 0)).xyxy; - vec2 uvs = saturate(gl_FragCoord.xy * texel_size.xy); + vec2 texel_size = 1.0 / vec2(textureSize(depthBuffer, 0)).xy; + vec2 uvs = saturate(gl_FragCoord.xy * texel_size); float depth = textureLod(depthBuffer, uvs, 0.0).r; @@ -23,28 +23,32 @@ void main() vec3 bent_normal; float visibility; -#if 1 - gtao_deferred(normal, viewPosition, depth, visibility, bent_normal); -#else - vec2 rand = vec2((1.0 / 4.0) * float((int(gl_FragCoord.y) & 0x1) * 2 + (int(gl_FragCoord.x) & 0x1)), 0.5); - rand = fract(rand.x + texture(utilTex, vec3(floor(gl_FragCoord.xy * 0.5) / LUT_SIZE, 2.0)).rg); - gtao(normal, viewPosition, rand, visibility, bent_normal); -#endif - denoise_ao(normal, depth, visibility, bent_normal); + + vec4 noise = texelfetch_noise_tex(gl_FragCoord.xy); + + gtao_deferred(normal, viewPosition, noise, depth, visibility, bent_normal); FragColor = vec4(visibility); } #else -uniform float sampleNbr; + +#ifdef LAYERED_DEPTH +uniform sampler2DArray depthBufferLayered; +uniform int layer; +# define gtao_depthBuffer depthBufferLayered +# define gtao_textureLod(a, b, c) textureLod(a, vec3(b, layer), c) + +#else +# define gtao_depthBuffer depthBuffer +# define gtao_textureLod(a, b, c) textureLod(a, b, c) + +#endif void main() { - ivec2 hr_co = ivec2(gl_FragCoord.xy); - ivec2 fs_co = get_fs_co(hr_co); - - vec2 uvs = saturate((vec2(fs_co) + 0.5) / vec2(textureSize(depthBuffer, 0))); - float depth = textureLod(depthBuffer, uvs, 0.0).r; + vec2 uvs = saturate(gl_FragCoord.xy / vec2(textureSize(gtao_depthBuffer, 0).xy)); + float depth = gtao_textureLod(gtao_depthBuffer, uvs, 0.0).r; if (depth == 1.0) { /* Do not trace for background */ @@ -56,14 +60,17 @@ void main() depth = saturate(depth - 3e-6); /* Tweaked for 24bit depth buffer. */ vec3 viewPosition = get_view_space_from_depth(uvs, depth); - - float phi = get_phi(hr_co, fs_co, sampleNbr); - float offset = get_offset(fs_co, sampleNbr); + vec4 noise = texelfetch_noise_tex(gl_FragCoord.xy); vec2 max_dir = get_max_dir(viewPosition.z); + vec4 dirs; + dirs.xy = get_ao_dir(noise.x * 0.5); + dirs.zw = get_ao_dir(noise.x * 0.5 + 0.5); - FragColor.xy = search_horizon_sweep(phi, viewPosition, uvs, offset, max_dir); + /* Search in 4 directions. */ + FragColor.xy = search_horizon_sweep(dirs.xy, viewPosition, uvs, noise.y, max_dir); + FragColor.zw = search_horizon_sweep(dirs.zw, viewPosition, uvs, noise.y, max_dir); /* Resize output for integer texture. */ - FragColor = pack_horizons(FragColor.xy).xyxy; + FragColor = pack_horizons(FragColor); } #endif diff --git a/source/blender/draw/engines/eevee/shaders/effect_minmaxz_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_minmaxz_frag.glsl index ce6f3568cdf..65d3970a82a 100644 --- a/source/blender/draw/engines/eevee/shaders/effect_minmaxz_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/effect_minmaxz_frag.glsl @@ -23,6 +23,10 @@ uniform sampler2D depthBuffer; #define minmax(a, b) max(a, b) #endif +#ifdef GPU_INTEL +out vec4 fragColor; +#endif + void main() { ivec2 texelPos = ivec2(gl_FragCoord.xy); @@ -61,5 +65,10 @@ void main() } #endif +#ifdef GPU_INTEL + /* Use color format instead of 24bit depth texture */ + fragColor = vec4(val); +#else gl_FragDepth = val; +#endif }
\ No newline at end of file diff --git a/source/blender/draw/engines/eevee/shaders/effect_motion_blur_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_motion_blur_frag.glsl index 1a01db3a1a3..73e284570cd 100644 --- a/source/blender/draw/engines/eevee/shaders/effect_motion_blur_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/effect_motion_blur_frag.glsl @@ -57,7 +57,7 @@ void main() float inc = 2.0 * inv_samples; float i = -1.0 + noise; - FragColor = vec4(0.0, 0.0, 0.0, 1.0); + FragColor = vec4(0.0); for (int j = 0; j < samples && j < MAX_SAMPLE; j++) { FragColor += textureLod(colorBuffer, uvcoordsvar.xy + motion * i, 0.0) * inv_samples; i += inc; diff --git a/source/blender/draw/engines/eevee/shaders/effect_ssr_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_ssr_frag.glsl index 2dc8dfa0d1c..aa88e365d93 100644 --- a/source/blender/draw/engines/eevee/shaders/effect_ssr_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/effect_ssr_frag.glsl @@ -5,80 +5,78 @@ #ifndef UTIL_TEX #define UTIL_TEX uniform sampler2DArray utilTex; +#define texelfetch_noise_tex(coord) texelFetch(utilTex, ivec3(ivec2(coord) % LUT_SIZE, 2.0), 0) #endif /* UTIL_TEX */ -#define BRDF_BIAS 0.7 #define MAX_MIP 9.0 -uniform float fireflyFactor; -uniform float maxRoughness; +uniform ivec2 halfresOffset; + +ivec2 encode_hit_data(vec2 hit_pos, bool has_hit, bool is_planar) +{ + ivec2 hit_data = ivec2(saturate(hit_pos) * 32767.0); /* 16bit signed int limit */ + hit_data.x *= (is_planar) ? -1 : 1; + hit_data.y *= (has_hit) ? 1 : -1; + return hit_data; +} + +vec2 decode_hit_data(vec2 hit_data, out bool has_hit, out bool is_planar) +{ + is_planar = (hit_data.x < 0); + has_hit = (hit_data.y > 0); + return vec2(abs(hit_data)) / 32767.0; /* 16bit signed int limit */ +} #ifdef STEP_RAYTRACE uniform sampler2D normalBuffer; uniform sampler2D specroughBuffer; -uniform int planar_count; -uniform float noiseOffset; - -layout(location = 0) out vec4 hitData0; -layout(location = 1) out vec4 hitData1; -layout(location = 2) out vec4 hitData2; -layout(location = 3) out vec4 hitData3; +layout(location = 0) out ivec2 hitData; +layout(location = 1) out float pdfData; -vec4 do_planar_ssr(int index, vec3 V, vec3 N, vec3 T, vec3 B, vec3 planeNormal, vec3 viewPosition, float a2, vec3 rand, float ofs) +void do_planar_ssr(int index, vec3 V, vec3 N, vec3 T, vec3 B, vec3 planeNormal, vec3 viewPosition, float a2, vec4 rand) { - float pdf, NH; - float jitter = fract(rand.x + ofs); - - /* Importance sampling bias */ - rand.x = mix(rand.x, 0.0, BRDF_BIAS); - - vec3 H = sample_ggx(rand, a2, N, T, B, NH); /* Microfacet normal */ - pdf = pdf_ggx_reflect(NH, a2); + float NH; + vec3 H = sample_ggx(rand.xzw, a2, N, T, B, NH); /* Microfacet normal */ + float pdf = pdf_ggx_reflect(NH, a2); vec3 R = reflect(-V, H); R = reflect(R, planeNormal); /* If ray is bad (i.e. going below the plane) regenerate. */ if (dot(R, planeNormal) > 0.0) { - vec3 H = sample_ggx(rand * vec3(1.0, -1.0, -1.0), a2, N, T, B, NH); /* Microfacet normal */ + vec3 H = sample_ggx(rand.xzw * vec3(1.0, -1.0, -1.0), a2, N, T, B, NH); /* Microfacet normal */ pdf = pdf_ggx_reflect(NH, a2); R = reflect(-V, H); R = reflect(R, planeNormal); } - pdf = min(1024e32, pdf); /* Theoretical limit of 16bit float */ - pdf *= -1.0; /* Tag as planar ray. */ + pdfData = min(1024e32, pdf); /* Theoretical limit of 16bit float */ /* Since viewspace hit position can land behind the camera in this case, * we save the reflected view position (visualize it as the hit position * below the reflection plane). This way it's garanted that the hit will * be in front of the camera. That let us tag the bad rays with a negative * sign in the Z component. */ - vec3 hit_pos = raycast(index, viewPosition, R * 1e16, 1e16, jitter, ssrQuality, a2, false); + vec3 hit_pos = raycast(index, viewPosition, R * 1e16, 1e16, rand.y, ssrQuality, a2, false); - return vec4(hit_pos, pdf); + hitData = encode_hit_data(hit_pos.xy, (hit_pos.z > 0.0), true); } -vec4 do_ssr(vec3 V, vec3 N, vec3 T, vec3 B, vec3 viewPosition, float a2, vec3 rand, float ofs) +void do_ssr(vec3 V, vec3 N, vec3 T, vec3 B, vec3 viewPosition, float a2, vec4 rand) { - float pdf, NH; - float jitter = fract(rand.x + ofs); - - /* Importance sampling bias */ - rand.x = mix(rand.x, 0.0, BRDF_BIAS); - - vec3 H = sample_ggx(rand, a2, N, T, B, NH); /* Microfacet normal */ - pdf = pdf_ggx_reflect(NH, a2); + float NH; + vec3 H = sample_ggx(rand.xzw, a2, N, T, B, NH); /* Microfacet normal */ + float pdf = pdf_ggx_reflect(NH, a2); vec3 R = reflect(-V, H); - pdf = min(1024e32, pdf); /* Theoretical limit of 16bit float */ + pdfData = min(1024e32, pdf); /* Theoretical limit of 16bit float */ - vec3 hit_pos = raycast(-1, viewPosition, R * 1e16, ssrThickness, jitter, ssrQuality, a2, true); + vec3 hit_pos = raycast(-1, viewPosition, R * 1e16, ssrThickness, rand.y, ssrQuality, a2, true); - return vec4(hit_pos, pdf); + hitData = encode_hit_data(hit_pos.xy, (hit_pos.z > 0.0), false); } void main() @@ -87,20 +85,22 @@ void main() ivec2 fullres_texel = ivec2(gl_FragCoord.xy); ivec2 halfres_texel = fullres_texel; #else - ivec2 fullres_texel = ivec2(gl_FragCoord.xy) * 2; + ivec2 fullres_texel = ivec2(gl_FragCoord.xy) * 2 + halfresOffset; ivec2 halfres_texel = ivec2(gl_FragCoord.xy); #endif float depth = texelFetch(depthBuffer, fullres_texel, 0).r; + /* Default: not hits. */ + hitData = encode_hit_data(vec2(0.5), false, false); + pdfData = 0.0; + /* Early out */ + /* We can't do discard because we don't clear the render target. */ if (depth == 1.0) - discard; + return; - vec2 uvs = gl_FragCoord.xy / vec2(textureSize(depthBuffer, 0)); -#ifndef FULLRES - uvs *= 2.0; -#endif + vec2 uvs = vec2(fullres_texel) / vec2(textureSize(depthBuffer, 0)); /* Using view space */ vec3 viewPosition = get_view_space_from_depth(uvs, depth); @@ -112,18 +112,24 @@ void main() /* Early out */ if (dot(speccol_roughness.rgb, vec3(1.0)) == 0.0) - discard; + return; float roughness = speccol_roughness.a; float roughnessSquared = max(1e-3, roughness * roughness); float a2 = roughnessSquared * roughnessSquared; - if (roughness > maxRoughness + 0.2) { - hitData0 = hitData1 = hitData2 = hitData3 = vec4(0.0); + /* Early out */ + if (roughness > ssrMaxRoughness + 0.2) return; - } - vec3 rand = texelFetch(utilTex, ivec3(halfres_texel % LUT_SIZE, 2), 0).rba; + vec4 rand = texelFetch(utilTex, ivec3(halfres_texel % LUT_SIZE, 2), 0); + + /* Gives *perfect* reflection for very small roughness */ + if (roughness < 0.04) { + rand.xzw *= 0.0; + } + /* Importance sampling bias */ + rand.x = mix(rand.x, 0.0, ssrBrdfBias); vec3 worldPosition = transform_point(ViewMatrixInverse, viewPosition); vec3 wN = transform_direction(ViewMatrixInverse, N); @@ -132,7 +138,7 @@ void main() make_orthonormal_basis(N, T, B); /* Generate tangent space */ /* Planar Reflections */ - for (int i = 0; i < MAX_PLANAR && i < planar_count; ++i) { + for (int i = 0; i < MAX_PLANAR && i < prbNumPlanar; ++i) { PlanarData pd = planars_data[i]; float fade = probe_attenuation_planar(pd, worldPosition, wN, 0.0); @@ -144,31 +150,12 @@ void main() tracePosition = transform_point(ViewMatrix, tracePosition); vec3 planeNormal = transform_direction(ViewMatrix, pd.pl_normal); - hitData0 = do_planar_ssr(i, V, N, T, B, planeNormal, tracePosition, a2, rand, 0.0); -#if (RAY_COUNT > 1) - hitData1 = do_planar_ssr(i, V, N, T, B, planeNormal, tracePosition, a2, rand.xyz * vec3(1.0, -1.0, -1.0), 1.0 / float(RAY_COUNT)); -#endif -#if (RAY_COUNT > 2) - hitData2 = do_planar_ssr(i, V, N, T, B, planeNormal, tracePosition, a2, rand.xzy * vec3(1.0, 1.0, -1.0), 2.0 / float(RAY_COUNT)); -#endif -#if (RAY_COUNT > 3) - hitData3 = do_planar_ssr(i, V, N, T, B, planeNormal, tracePosition, a2, rand.xzy * vec3(1.0, -1.0, 1.0), 3.0 / float(RAY_COUNT)); -#endif + do_planar_ssr(i, V, N, T, B, planeNormal, tracePosition, a2, rand); return; } } - /* TODO : Raytrace together if textureGather is supported. */ - hitData0 = do_ssr(V, N, T, B, viewPosition, a2, rand, 0.0); -#if (RAY_COUNT > 1) - hitData1 = do_ssr(V, N, T, B, viewPosition, a2, rand.xyz * vec3(1.0, -1.0, -1.0), 1.0 / float(RAY_COUNT)); -#endif -#if (RAY_COUNT > 2) - hitData2 = do_ssr(V, N, T, B, viewPosition, a2, rand.xzy * vec3(1.0, 1.0, -1.0), 2.0 / float(RAY_COUNT)); -#endif -#if (RAY_COUNT > 3) - hitData3 = do_ssr(V, N, T, B, viewPosition, a2, rand.xzy * vec3(1.0, -1.0, 1.0), 3.0 / float(RAY_COUNT)); -#endif + do_ssr(V, N, T, B, viewPosition, a2, rand); } #else /* STEP_RESOLVE */ @@ -177,30 +164,42 @@ uniform sampler2D prevColorBuffer; /* previous frame */ uniform sampler2D normalBuffer; uniform sampler2D specroughBuffer; -uniform sampler2D hitBuffer0; -uniform sampler2D hitBuffer1; -uniform sampler2D hitBuffer2; -uniform sampler2D hitBuffer3; +uniform isampler2D hitBuffer; +uniform sampler2D pdfBuffer; + +uniform int neighborOffset; -uniform int probe_count; -uniform int planar_count; +const ivec2 neighbors[32] = ivec2[32]( + ivec2( 0, 0), ivec2( 1, 1), ivec2(-2, 0), ivec2( 0, -2), + ivec2( 0, 0), ivec2( 1, -1), ivec2(-2, 0), ivec2( 0, 2), + ivec2( 0, 0), ivec2(-1, -1), ivec2( 2, 0), ivec2( 0, 2), + ivec2( 0, 0), ivec2(-1, 1), ivec2( 2, 0), ivec2( 0, -2), -uniform mat4 PastViewProjectionMatrix; + ivec2( 0, 0), ivec2( 2, 2), ivec2(-2, 2), ivec2( 0, -1), + ivec2( 0, 0), ivec2( 2, -2), ivec2(-2, -2), ivec2( 0, 1), + ivec2( 0, 0), ivec2(-2, -2), ivec2(-2, 2), ivec2( 1, 0), + ivec2( 0, 0), ivec2( 2, 2), ivec2( 2, -2), ivec2(-1, 0) +); out vec4 fragColor; -void fallback_cubemap(vec3 N, vec3 V, vec3 W, vec3 viewPosition, float roughness, float roughnessSquared, inout vec4 spec_accum) +void fallback_cubemap( + vec3 N, vec3 V, vec3 W, vec3 viewPosition, float roughness, float roughnessSquared, inout vec4 spec_accum) { /* Specular probes */ vec3 spec_dir = get_specular_reflection_dominant_dir(N, V, roughnessSquared); - vec4 rand = texture(utilTex, vec3(gl_FragCoord.xy / LUT_SIZE, 2.0)); + vec4 rand = texelfetch_noise_tex(gl_FragCoord.xy); vec3 bent_normal; - float final_ao = occlusion_compute(N, viewPosition, 1.0, rand.rg, bent_normal); +#ifdef SSR_AO + float final_ao = occlusion_compute(N, viewPosition, 1.0, rand, bent_normal); final_ao = specular_occlusion(dot(N, V), final_ao, roughness); +#else + const float final_ao = 1.0; +#endif /* Starts at 1 because 0 is world probe */ - for (int i = 1; i < MAX_PROBE && i < probe_count && spec_accum.a < 0.999; ++i) { + for (int i = 1; i < MAX_PROBE && i < prbNumRenderCube && spec_accum.a < 0.999; ++i) { CubeData cd = probes_data[i]; float fade = probe_attenuation_cube(cd, W); @@ -251,90 +250,177 @@ float brightness(vec3 c) vec2 get_reprojected_reflection(vec3 hit, vec3 pos, vec3 N) { /* TODO real reprojection with motion vectors, etc... */ - return project_point(PastViewProjectionMatrix, hit).xy * 0.5 + 0.5; + return project_point(pastViewProjectionMatrix, hit).xy * 0.5 + 0.5; } -vec4 get_ssr_sample( - sampler2D hitBuffer, PlanarData pd, float planar_index, vec3 worldPosition, vec3 N, vec3 V, float roughnessSquared, - float cone_tan, vec2 source_uvs, vec2 texture_size, ivec2 target_texel, - inout float weight_acc) +float get_sample_depth(vec2 hit_co, bool is_planar, float planar_index) { - vec4 hit_co_pdf = texelFetch(hitBuffer, target_texel, 0).rgba; - bool has_hit = (hit_co_pdf.z > 0.0); - bool is_planar = (hit_co_pdf.w < 0.0); - hit_co_pdf.z = abs(hit_co_pdf.z); - hit_co_pdf.w = abs(hit_co_pdf.w); - - /* Hit position in world space. */ - hit_co_pdf.xyz = get_view_space_from_depth(hit_co_pdf.xy, hit_co_pdf.z); - vec3 hit_pos = transform_point(ViewMatrixInverse, hit_co_pdf.xyz); + if (is_planar) { + return textureLod(planarDepth, vec3(hit_co, planar_index), 0.0).r; + } + else { + return textureLod(depthBuffer, hit_co, 0.0).r; + } +} - vec2 ref_uvs; +vec3 get_hit_vector( + vec3 hit_pos, PlanarData pd, vec3 worldPosition, vec3 N, vec3 V, bool is_planar, + inout vec2 hit_co, inout float mask) +{ vec3 hit_vec; - float mask = 1.0; + if (is_planar) { /* Reflect back the hit position to have it in non-reflected world space */ vec3 trace_pos = line_plane_intersect(worldPosition, V, pd.pl_plane_eq); hit_vec = hit_pos - trace_pos; hit_vec = reflect(hit_vec, pd.pl_normal); - ref_uvs = project_point(ProjectionMatrix, hit_co_pdf.xyz).xy * 0.5 + 0.5; } else { /* Find hit position in previous frame. */ - ref_uvs = get_reprojected_reflection(hit_pos, worldPosition, N); + mask = screen_border_mask(gl_FragCoord.xy / vec2(textureSize(depthBuffer, 0))); + hit_co = get_reprojected_reflection(hit_pos, worldPosition, N); hit_vec = hit_pos - worldPosition; - mask = screen_border_mask(gl_FragCoord.xy / texture_size); } - mask = min(mask, screen_border_mask(ref_uvs)); - mask *= float(has_hit); - float hit_dist = max(1e-8, length(hit_vec)); - vec3 L = hit_vec / hit_dist; + mask = min(mask, screen_border_mask(hit_co)); + return hit_vec; +} - float cone_footprint = hit_dist * cone_tan; +vec3 get_scene_color(vec2 ref_uvs, float mip, float planar_index, bool is_planar) +{ + if (is_planar) { + return textureLod(probePlanars, vec3(ref_uvs, planar_index), min(mip, prbLodPlanarMax)).rgb; + } + else { + return textureLod(prevColorBuffer, ref_uvs, mip).rgb; + } +} + +vec4 get_ssr_samples( + vec4 hit_pdf, ivec4 hit_data[2], + PlanarData pd, float planar_index, vec3 worldPosition, vec3 N, vec3 V, + float roughnessSquared, float cone_tan, vec2 source_uvs, + inout float weight_acc) +{ + bvec4 is_planar, has_hit; + vec4 hit_co[2]; + hit_co[0].xy = decode_hit_data(hit_data[0].xy, has_hit.x, is_planar.x); + hit_co[0].zw = decode_hit_data(hit_data[0].zw, has_hit.y, is_planar.y); + hit_co[1].xy = decode_hit_data(hit_data[1].xy, has_hit.z, is_planar.z); + hit_co[1].zw = decode_hit_data(hit_data[1].zw, has_hit.w, is_planar.w); + + vec4 hit_depth; + hit_depth.x = get_sample_depth(hit_co[0].xy, is_planar.x, planar_index); + hit_depth.y = get_sample_depth(hit_co[0].zw, is_planar.y, planar_index); + hit_depth.z = get_sample_depth(hit_co[1].xy, is_planar.z, planar_index); + hit_depth.w = get_sample_depth(hit_co[1].zw, is_planar.w, planar_index); + + /* Hit position in view space. */ + vec3 hit_view[4]; + hit_view[0] = get_view_space_from_depth(hit_co[0].xy, hit_depth.x); + hit_view[1] = get_view_space_from_depth(hit_co[0].zw, hit_depth.y); + hit_view[2] = get_view_space_from_depth(hit_co[1].xy, hit_depth.z); + hit_view[3] = get_view_space_from_depth(hit_co[1].zw, hit_depth.w); + + vec4 homcoord = vec4(hit_view[0].z, hit_view[1].z, hit_view[2].z, hit_view[3].z); + homcoord = ProjectionMatrix[2][3] * homcoord + ProjectionMatrix[3][3]; + + /* Hit position in world space. */ + vec3 hit_pos[4]; + hit_pos[0] = transform_point(ViewMatrixInverse, hit_view[0]); + hit_pos[1] = transform_point(ViewMatrixInverse, hit_view[1]); + hit_pos[2] = transform_point(ViewMatrixInverse, hit_view[2]); + hit_pos[3] = transform_point(ViewMatrixInverse, hit_view[3]); + + /* Get actual hit vector and hit coordinate (from last frame). */ + vec4 mask = vec4(1.0); + hit_pos[0] = get_hit_vector(hit_pos[0], pd, worldPosition, N, V, is_planar.x, hit_co[0].xy, mask.x); + hit_pos[1] = get_hit_vector(hit_pos[1], pd, worldPosition, N, V, is_planar.y, hit_co[0].zw, mask.y); + hit_pos[2] = get_hit_vector(hit_pos[2], pd, worldPosition, N, V, is_planar.z, hit_co[1].xy, mask.z); + hit_pos[3] = get_hit_vector(hit_pos[3], pd, worldPosition, N, V, is_planar.w, hit_co[1].zw, mask.w); + + vec4 hit_dist; + hit_dist.x = length(hit_pos[0]); + hit_dist.y = length(hit_pos[1]); + hit_dist.z = length(hit_pos[2]); + hit_dist.w = length(hit_pos[3]); + hit_dist = max(vec4(1e-8), hit_dist); + + /* Normalize */ + hit_pos[0] /= hit_dist.x; + hit_pos[1] /= hit_dist.y; + hit_pos[2] /= hit_dist.z; + hit_pos[3] /= hit_dist.w; /* Compute cone footprint in screen space. */ - float homcoord = ProjectionMatrix[2][3] * hit_co_pdf.z + ProjectionMatrix[3][3]; - cone_footprint = BRDF_BIAS * 0.5 * cone_footprint * max(ProjectionMatrix[0][0], ProjectionMatrix[1][1]) / homcoord; + vec4 cone_footprint = hit_dist * cone_tan; + cone_footprint = ssrBrdfBias * 0.5 * cone_footprint * max(ProjectionMatrix[0][0], ProjectionMatrix[1][1]) / homcoord; /* Estimate a cone footprint to sample a corresponding mipmap level. */ - float mip = clamp(log2(cone_footprint * max(texture_size.x, texture_size.y)), 0.0, MAX_MIP); + vec4 mip = log2(cone_footprint * max_v2(vec2(textureSize(depthBuffer, 0)))); + mip = clamp(mip, 0.0, MAX_MIP); /* Correct UVs for mipmaping mis-alignment */ - ref_uvs *= mip_ratio_interp(mip); + hit_co[0].xy *= mip_ratio_interp(mip.x); + hit_co[0].zw *= mip_ratio_interp(mip.y); + hit_co[1].xy *= mip_ratio_interp(mip.z); + hit_co[1].zw *= mip_ratio_interp(mip.w); /* Slide 54 */ - float bsdf = bsdf_ggx(N, L, V, roughnessSquared); - float weight = step(1e-8, hit_co_pdf.w) * bsdf / max(1e-8, hit_co_pdf.w); - weight_acc += weight; + vec4 bsdf; + bsdf.x = bsdf_ggx(N, hit_pos[0], V, roughnessSquared); + bsdf.y = bsdf_ggx(N, hit_pos[1], V, roughnessSquared); + bsdf.z = bsdf_ggx(N, hit_pos[2], V, roughnessSquared); + bsdf.w = bsdf_ggx(N, hit_pos[3], V, roughnessSquared); - vec3 sample; - if (is_planar) { - sample = textureLod(probePlanars, vec3(ref_uvs, planar_index), min(mip, lodPlanarMax)).rgb; - } - else { - sample = textureLod(prevColorBuffer, ref_uvs, mip).rgb; - } + vec4 weight = step(1e-8, hit_pdf) * bsdf / max(vec4(1e-8), hit_pdf); - /* Clamped brightness. */ - float luma = max(1e-8, brightness(sample)); - sample *= 1.0 - max(0.0, luma - fireflyFactor) / luma; + vec3 sample[4]; + sample[0] = get_scene_color(hit_co[0].xy, mip.x, planar_index, is_planar.x); + sample[1] = get_scene_color(hit_co[0].zw, mip.y, planar_index, is_planar.y); + sample[2] = get_scene_color(hit_co[1].xy, mip.z, planar_index, is_planar.z); + sample[3] = get_scene_color(hit_co[1].zw, mip.w, planar_index, is_planar.w); - /* Do not add light if ray has failed. */ - sample *= float(has_hit); + /* Clamped brightness. */ + vec4 luma; + luma.x = brightness(sample[0]); + luma.y = brightness(sample[1]); + luma.z = brightness(sample[2]); + luma.w = brightness(sample[3]); + luma = max(vec4(1e-8), luma); + luma = 1.0 - max(vec4(0.0), luma - ssrFireflyFac) / luma; + + sample[0] *= luma.x; + sample[1] *= luma.y; + sample[2] *= luma.z; + sample[3] *= luma.w; /* Protection against NaNs in the history buffer. * This could be removed if some previous pass has already * sanitized the input. */ - if (any(isnan(sample))) { - sample = vec3(0.0); - weight = 0.0; + if (any(isnan(sample[0]))) { + sample[0] = vec3(0.0); weight.x = 0.0; + } + if (any(isnan(sample[1]))) { + sample[1] = vec3(0.0); weight.y = 0.0; + } + if (any(isnan(sample[2]))) { + sample[2] = vec3(0.0); weight.z = 0.0; + } + if (any(isnan(sample[3]))) { + sample[3] = vec3(0.0); weight.w = 0.0; } - return vec4(sample, mask) * weight; -} + weight_acc += sum(weight); -#define NUM_NEIGHBORS 4 + /* Do not add light if ray has failed. */ + vec4 accum; + accum = vec4(sample[0], mask.x) * weight.x * float(has_hit.x); + accum += vec4(sample[1], mask.y) * weight.y * float(has_hit.y); + accum += vec4(sample[2], mask.z) * weight.z * float(has_hit.z); + accum += vec4(sample[3], mask.w) * weight.w * float(has_hit.w); + return accum; +} void main() { @@ -344,9 +430,7 @@ void main() #else ivec2 halfres_texel = ivec2(gl_FragCoord.xy / 2.0); #endif - vec2 texture_size = vec2(textureSize(depthBuffer, 0)); - vec2 uvs = gl_FragCoord.xy / texture_size; - vec3 rand = texelFetch(utilTex, ivec3(fullres_texel % LUT_SIZE, 2), 0).rba; + vec2 uvs = gl_FragCoord.xy / vec2(textureSize(depthBuffer, 0)); float depth = textureLod(depthBuffer, uvs, 0.0).r; @@ -366,10 +450,24 @@ void main() if (dot(speccol_roughness.rgb, vec3(1.0)) == 0.0) discard; + /* TODO optimize with textureGather */ + /* Doing these fetches early to hide latency. */ + vec4 hit_pdf; + hit_pdf.x = texelFetch(pdfBuffer, halfres_texel + neighbors[0 + neighborOffset], 0).r; + hit_pdf.y = texelFetch(pdfBuffer, halfres_texel + neighbors[1 + neighborOffset], 0).r; + hit_pdf.z = texelFetch(pdfBuffer, halfres_texel + neighbors[2 + neighborOffset], 0).r; + hit_pdf.w = texelFetch(pdfBuffer, halfres_texel + neighbors[3 + neighborOffset], 0).r; + + ivec4 hit_data[2]; + hit_data[0].xy = texelFetch(hitBuffer, halfres_texel + neighbors[0 + neighborOffset], 0).rg; + hit_data[0].zw = texelFetch(hitBuffer, halfres_texel + neighbors[1 + neighborOffset], 0).rg; + hit_data[1].xy = texelFetch(hitBuffer, halfres_texel + neighbors[2 + neighborOffset], 0).rg; + hit_data[1].zw = texelFetch(hitBuffer, halfres_texel + neighbors[3 + neighborOffset], 0).rg; + /* Find Planar Reflections affecting this pixel */ PlanarData pd; float planar_index; - for (int i = 0; i < MAX_PLANAR && i < planar_count; ++i) { + for (int i = 0; i < MAX_PLANAR && i < prbNumPlanar; ++i) { pd = planars_data[i]; float fade = probe_attenuation_planar(pd, worldPosition, N, 0.0); @@ -390,55 +488,21 @@ void main() float cone_tan = sqrt(1 - cone_cos * cone_cos) / cone_cos; cone_tan *= mix(saturate(dot(N, -V) * 2.0), 1.0, roughness); /* Elongation fit */ - vec2 source_uvs = project_point(PastViewProjectionMatrix, worldPosition).xy * 0.5 + 0.5; + vec2 source_uvs = project_point(pastViewProjectionMatrix, worldPosition).xy * 0.5 + 0.5; vec4 ssr_accum = vec4(0.0); float weight_acc = 0.0; - const ivec2 neighbors[9] = ivec2[9]( - ivec2(0, 0), - - ivec2(0, 1), - ivec2(-1, -1), ivec2(1, -1), - - ivec2(-1, 1), ivec2(1, 1), - ivec2(0, -1), - - ivec2(-1, 0), ivec2(1, 0) - ); - ivec2 invert_neighbor; - invert_neighbor.x = ((fullres_texel.x & 0x1) == 0) ? 1 : -1; - invert_neighbor.y = ((fullres_texel.y & 0x1) == 0) ? 1 : -1; - - if (roughness < maxRoughness + 0.2) { - for (int i = 0; i < NUM_NEIGHBORS; i++) { - ivec2 target_texel = halfres_texel + neighbors[i] * invert_neighbor; - - ssr_accum += get_ssr_sample(hitBuffer0, pd, planar_index, worldPosition, N, V, - roughnessSquared, cone_tan, source_uvs, - texture_size, target_texel, weight_acc); -#if (RAY_COUNT > 1) - ssr_accum += get_ssr_sample(hitBuffer1, pd, planar_index, worldPosition, N, V, - roughnessSquared, cone_tan, source_uvs, - texture_size, target_texel, weight_acc); -#endif -#if (RAY_COUNT > 2) - ssr_accum += get_ssr_sample(hitBuffer2, pd, planar_index, worldPosition, N, V, - roughnessSquared, cone_tan, source_uvs, - texture_size, target_texel, weight_acc); -#endif -#if (RAY_COUNT > 3) - ssr_accum += get_ssr_sample(hitBuffer3, pd, planar_index, worldPosition, N, V, - roughnessSquared, cone_tan, source_uvs, - texture_size, target_texel, weight_acc); -#endif - } + + if (roughness < ssrMaxRoughness + 0.2) { + ssr_accum += get_ssr_samples(hit_pdf, hit_data, pd, planar_index, worldPosition, N, V, + roughnessSquared, cone_tan, source_uvs, weight_acc); } /* Compute SSR contribution */ if (weight_acc > 0.0) { ssr_accum /= weight_acc; /* fade between 0.5 and 1.0 roughness */ - ssr_accum.a *= smoothstep(maxRoughness + 0.2, maxRoughness, roughness); + ssr_accum.a *= smoothstep(ssrMaxRoughness + 0.2, ssrMaxRoughness, roughness); accumulate_light(ssr_accum.rgb, ssr_accum.a, spec_accum); } diff --git a/source/blender/draw/engines/eevee/shaders/effect_subsurface_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_subsurface_frag.glsl index 88e71a060c5..184eac54c26 100644 --- a/source/blender/draw/engines/eevee/shaders/effect_subsurface_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/effect_subsurface_frag.glsl @@ -8,16 +8,19 @@ layout(std140) uniform sssProfile { int sss_samples; }; -uniform float jitterThreshold; uniform sampler2D depthBuffer; uniform sampler2D sssData; uniform sampler2D sssAlbedo; + +#ifndef UTIL_TEX +#define UTIL_TEX uniform sampler2DArray utilTex; +#define texelfetch_noise_tex(coord) texelFetch(utilTex, ivec3(ivec2(coord) % LUT_SIZE, 2.0), 0) +#endif /* UTIL_TEX */ out vec4 FragColor; uniform mat4 ProjectionMatrix; -uniform vec4 viewvecs[2]; float get_view_z_from_depth(float depth) { @@ -26,7 +29,7 @@ float get_view_z_from_depth(float depth) return -ProjectionMatrix[3][2] / (d + ProjectionMatrix[2][2]); } else { - return viewvecs[0].z + depth * viewvecs[1].z; + return viewVecs[0].z + depth * viewVecs[1].z; } } @@ -41,7 +44,7 @@ void main(void) vec4 sss_data = texture(sssData, uvs).rgba; float depth_view = get_view_z_from_depth(texture(depthBuffer, uvs).r); - float rand = texelFetch(utilTex, ivec3(ivec2(gl_FragCoord.xy) % LUT_SIZE, 2), 0).r; + float rand = texelfetch_noise_tex(gl_FragCoord.xy).r; #ifdef FIRST_PASS float angle = M_2PI * rand + M_PI_2; vec2 dir = vec2(1.0, 0.0); @@ -61,7 +64,7 @@ void main(void) vec3 accum = sss_data.rgb * kernel[0].rgb; for (int i = 1; i < sss_samples && i < MAX_SSS_SAMPLES; i++) { - vec2 sample_uv = uvs + kernel[i].a * finalStep * ((abs(kernel[i].a) > jitterThreshold) ? dir : dir_rand); + vec2 sample_uv = uvs + kernel[i].a * finalStep * ((abs(kernel[i].a) > sssJitterThreshold) ? dir : dir_rand); vec3 color = texture(sssData, sample_uv).rgb; float sample_depth = texture(depthBuffer, sample_uv).r; sample_depth = get_view_z_from_depth(sample_depth); diff --git a/source/blender/draw/engines/eevee/shaders/irradiance_lib.glsl b/source/blender/draw/engines/eevee/shaders/irradiance_lib.glsl index 76d20486d3d..132cc16fcbd 100644 --- a/source/blender/draw/engines/eevee/shaders/irradiance_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/irradiance_lib.glsl @@ -1,6 +1,5 @@ uniform sampler2DArray irradianceGrid; -uniform int irradianceVisibilitySize; #define IRRADIANCE_LIB @@ -81,8 +80,8 @@ IrradianceData load_irradiance_cell(int cell, vec3 N) float load_visibility_cell(int cell, vec3 L, float dist, float bias, float bleed_bias, float range) { /* Keep in sync with diffuse_filter_probe() */ - ivec2 cell_co = ivec2(irradianceVisibilitySize); - ivec2 cell_per_row_col = textureSize(irradianceGrid, 0).xy / irradianceVisibilitySize; + ivec2 cell_co = ivec2(prbIrradianceVisSize); + ivec2 cell_per_row_col = textureSize(irradianceGrid, 0).xy / prbIrradianceVisSize; cell_co.x *= (cell % cell_per_row_col.x); cell_co.y *= (cell / cell_per_row_col.x) % cell_per_row_col.y; float layer = 1.0 + float((cell / cell_per_row_col.x) / cell_per_row_col.y); @@ -90,8 +89,8 @@ float load_visibility_cell(int cell, vec3 L, float dist, float bias, float bleed vec2 texel_size = 1.0 / vec2(textureSize(irradianceGrid, 0).xy); vec2 co = vec2(cell_co) * texel_size; - vec2 uv = mapping_octahedron(-L, vec2(1.0 / float(irradianceVisibilitySize))); - uv *= vec2(irradianceVisibilitySize) * texel_size; + vec2 uv = mapping_octahedron(-L, vec2(1.0 / float(prbIrradianceVisSize))); + uv *= vec2(prbIrradianceVisSize) * texel_size; vec4 data = texture(irradianceGrid, vec3(co + uv, layer)); diff --git a/source/blender/draw/engines/eevee/shaders/lamps_lib.glsl b/source/blender/draw/engines/eevee/shaders/lamps_lib.glsl index 933f056c401..1c7956bb807 100644 --- a/source/blender/draw/engines/eevee/shaders/lamps_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/lamps_lib.glsl @@ -161,7 +161,7 @@ float light_visibility(LightData ld, vec3 W, float x = dot(ld.l_right, lL) / ld.l_sizex; float y = dot(ld.l_up, lL) / ld.l_sizey; - float ellipse = 1.0 / sqrt(1.0 + x * x + y * y); + float ellipse = inversesqrt(1.0 + x * x + y * y); float spotmask = smoothstep(0.0, 1.0, (ellipse - ld.l_spot_size) / ld.l_spot_blend); @@ -203,14 +203,13 @@ float light_visibility(LightData ld, vec3 W, vec3 T, B; make_orthonormal_basis(L.xyz / L.w, T, B); - vec3 rand = texture(utilTex, vec3(gl_FragCoord.xy / LUT_SIZE, 2.0)).xzw; - /* XXX This is a hack to not have noise correlation artifacts. - * A better solution to have better noise is welcome. */ - rand.yz *= fast_sqrt(fract(rand.x * 7919.0)) * data.sh_contact_spread; + vec4 rand = texelfetch_noise_tex(gl_FragCoord.xy); + /* WATCH THIS : This still seems to have correlation artifacts for low samples. */ + rand.zw *= fast_sqrt(rand.y) * data.sh_contact_spread; /* We use the full l_vector.xyz so that the spread is minimize * if the shading point is further away from the light source */ - vec3 ray_dir = L.xyz + T * rand.y + B * rand.z; + vec3 ray_dir = L.xyz + T * rand.z + B * rand.w; ray_dir = transform_direction(ViewMatrix, ray_dir); ray_dir = normalize(ray_dir); vec3 ray_origin = viewPosition + viewNormal * data.sh_contact_offset; @@ -235,8 +234,7 @@ float light_diffuse(LightData ld, vec3 N, vec3 V, vec4 l_vector) { #ifdef USE_LTC if (ld.l_type == SUN) { - /* TODO disk area light */ - return direct_diffuse_sun(ld, N); + return direct_diffuse_unit_disc(ld, N, V); } else if (ld.l_type == AREA) { return direct_diffuse_rectangle(ld, N, V, l_vector); @@ -258,8 +256,7 @@ vec3 light_specular(LightData ld, vec3 N, vec3 V, vec4 l_vector, float roughness { #ifdef USE_LTC if (ld.l_type == SUN) { - /* TODO disk area light */ - return direct_ggx_sun(ld, N, V, roughness, f0); + return direct_ggx_unit_disc(ld, N, V, roughness, f0); } else if (ld.l_type == AREA) { return direct_ggx_rectangle(ld, N, V, l_vector, roughness, f0); @@ -298,9 +295,7 @@ vec3 light_translucent(LightData ld, vec3 W, vec3 N, vec4 l_vector, float scale) { #if !defined(USE_TRANSLUCENCY) || defined(VOLUMETRICS) return vec3(0.0); -#endif - -#ifndef VOLUMETRICS +#else vec3 vis = vec3(1.0); /* Only shadowed light can produce translucency */ @@ -313,14 +308,13 @@ vec3 light_translucent(LightData ld, vec3 W, vec3 N, vec4 l_vector, float scale) vec3 T, B; make_orthonormal_basis(L.xyz / L.w, T, B); - vec3 rand = texture(utilTex, vec3(gl_FragCoord.xy / LUT_SIZE, 2.0)).xzw; - /* XXX This is a hack to not have noise correlation artifacts. - * A better solution to have better noise is welcome. */ - rand.yz *= fast_sqrt(fract(rand.x * 7919.0)) * data.sh_blur; + vec4 rand = texelfetch_noise_tex(gl_FragCoord.xy); + /* WATCH THIS : This still seems to have correlation artifacts for low samples. */ + rand.zw *= fast_sqrt(rand.y) * data.sh_blur; /* We use the full l_vector.xyz so that the spread is minimize * if the shading point is further away from the light source */ - W = W + T * rand.y + B * rand.z; + W = W + T * rand.z + B * rand.w; if (ld.l_type == SUN) { ShadowCascadeData scd = shadows_cascade_data[int(data.sh_data_start)]; @@ -374,19 +368,24 @@ vec3 light_translucent(LightData ld, vec3 W, vec3 N, vec4 l_vector, float scale) /* TODO : put this out of the shader. */ float falloff; if (ld.l_type == AREA) { - vis *= 0.0962 * (ld.l_sizex * ld.l_sizey * 4.0 * M_PI); + vis *= (ld.l_sizex * ld.l_sizey * 4.0 * M_PI) * (1.0 / 80.0); + vis *= 0.3 * 20.0 * max(0.0, dot(-ld.l_forward, l_vector.xyz / l_vector.w)); /* XXX ad hoc, empirical */ vis /= (l_vector.w * l_vector.w); falloff = dot(N, l_vector.xyz / l_vector.w); } else if (ld.l_type == SUN) { + vis *= (4.0f * ld.l_radius * ld.l_radius * M_2PI) * (1.0 / 12.5); /* Removing area light power*/ + vis *= M_2PI * 0.78; /* Matching cycles with point light. */ + vis *= 0.082; /* XXX ad hoc, empirical */ falloff = dot(N, -ld.l_forward); } else { - vis *= 0.0248 * (4.0 * ld.l_radius * ld.l_radius * M_PI * M_PI); + vis *= (4.0 * ld.l_radius * ld.l_radius) * (1.0 /10.0); + vis *= 1.5; /* XXX ad hoc, empirical */ vis /= (l_vector.w * l_vector.w); falloff = dot(N, l_vector.xyz / l_vector.w); } - vis *= M_1_PI; /* Normalize */ + // vis *= M_1_PI; /* Normalize */ /* Applying profile */ vis *= sss_profile(abs(delta) / scale); @@ -400,7 +399,7 @@ vec3 light_translucent(LightData ld, vec3 W, vec3 N, vec4 l_vector, float scale) float x = dot(ld.l_right, lL) / ld.l_sizex; float y = dot(ld.l_up, lL) / ld.l_sizey; - float ellipse = 1.0 / sqrt(1.0 + x * x + y * y); + float ellipse = inversesqrt(1.0 + x * x + y * y); float spotmask = smoothstep(0.0, 1.0, (ellipse - ld.l_spot_size) / ld.l_spot_blend); diff --git a/source/blender/draw/engines/eevee/shaders/lightprobe_cube_display_frag.glsl b/source/blender/draw/engines/eevee/shaders/lightprobe_cube_display_frag.glsl index fc0b5b9548b..d10f4bc0d42 100644 --- a/source/blender/draw/engines/eevee/shaders/lightprobe_cube_display_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/lightprobe_cube_display_frag.glsl @@ -11,5 +11,5 @@ void main() ? normalize(cameraPos - worldPosition) : cameraForward; vec3 N = normalize(worldNormal); - FragColor = vec4(textureLod_octahedron(probeCubes, vec4(reflect(-V, N), pid), 0.0, lodCubeMax).rgb, 1.0); + FragColor = vec4(textureLod_octahedron(probeCubes, vec4(reflect(-V, N), pid), 0.0, prbLodCubeMax).rgb, 1.0); } diff --git a/source/blender/draw/engines/eevee/shaders/lightprobe_filter_diffuse_frag.glsl b/source/blender/draw/engines/eevee/shaders/lightprobe_filter_diffuse_frag.glsl index eb4315c93a3..b19ee7a9ea3 100644 --- a/source/blender/draw/engines/eevee/shaders/lightprobe_filter_diffuse_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/lightprobe_filter_diffuse_frag.glsl @@ -3,6 +3,7 @@ uniform samplerCube probeHdr; uniform int probeSize; uniform float lodFactor; uniform float lodMax; +uniform float intensityFac; in vec3 worldPosition; @@ -192,6 +193,6 @@ void main() } } - FragColor = irradiance_encode(out_radiance / weight); + FragColor = irradiance_encode(intensityFac * out_radiance / weight); #endif }
\ No newline at end of file diff --git a/source/blender/draw/engines/eevee/shaders/lightprobe_filter_glossy_frag.glsl b/source/blender/draw/engines/eevee/shaders/lightprobe_filter_glossy_frag.glsl index 33714c5293c..3aec3ce4642 100644 --- a/source/blender/draw/engines/eevee/shaders/lightprobe_filter_glossy_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/lightprobe_filter_glossy_frag.glsl @@ -5,6 +5,7 @@ uniform float texelSize; uniform float lodFactor; uniform float lodMax; uniform float paddingSize; +uniform float intensityFac; in vec3 worldPosition; @@ -82,5 +83,5 @@ void main() { } } - FragColor = vec4(out_radiance / weight, 1.0); + FragColor = vec4(intensityFac * out_radiance / weight, 1.0); }
\ No newline at end of file diff --git a/source/blender/draw/engines/eevee/shaders/lightprobe_lib.glsl b/source/blender/draw/engines/eevee/shaders/lightprobe_lib.glsl index e914228aded..429f6ea92e4 100644 --- a/source/blender/draw/engines/eevee/shaders/lightprobe_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/lightprobe_lib.glsl @@ -1,10 +1,7 @@ /* ----------- Uniforms --------- */ uniform sampler2DArray probePlanars; -uniform float lodPlanarMax; - uniform sampler2DArray probeCubes; -uniform float lodCubeMax; /* ----------- Structures --------- */ @@ -162,12 +159,12 @@ vec3 probe_evaluate_cube(float id, CubeData cd, vec3 W, vec3 R, float roughness) float fac = saturate(original_roughness * 2.0 - 1.0); R = mix(intersection, R, fac * fac); - return textureLod_octahedron(probeCubes, vec4(R, id), roughness * lodCubeMax, lodCubeMax).rgb; + return textureLod_octahedron(probeCubes, vec4(R, id), roughness * prbLodCubeMax, prbLodCubeMax).rgb; } vec3 probe_evaluate_world_spec(vec3 R, float roughness) { - return textureLod_octahedron(probeCubes, vec4(R, 0.0), roughness * lodCubeMax, lodCubeMax).rgb; + return textureLod_octahedron(probeCubes, vec4(R, 0.0), roughness * prbLodCubeMax, prbLodCubeMax).rgb; } vec3 probe_evaluate_planar( 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 6ecaf0a627b..cc66b477da0 100644 --- a/source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl @@ -2,19 +2,12 @@ #ifndef LIT_SURFACE_UNIFORM #define LIT_SURFACE_UNIFORM -uniform int light_count; -uniform int probe_count; -uniform int grid_count; -uniform int planar_count; - -uniform bool specToggle; -uniform bool ssrToggle; - uniform float refractionDepth; #ifndef UTIL_TEX #define UTIL_TEX uniform sampler2DArray utilTex; +#define texelfetch_noise_tex(coord) texelFetch(utilTex, ivec3(ivec2(coord) % LUT_SIZE, 2.0), 0) #endif /* UTIL_TEX */ in vec3 worldPosition; @@ -28,9 +21,6 @@ in vec3 worldNormal; in vec3 viewNormal; #endif -uniform float maxRoughness; -uniform int rayCount; - #endif /* LIT_SURFACE_UNIFORM */ /** AUTO CONFIG @@ -176,7 +166,7 @@ void CLOSURE_NAME( vec3 V = cameraVec; - vec4 rand = texture(utilTex, vec3(gl_FragCoord.xy / LUT_SIZE, 2.0)); + vec4 rand = texelFetch(utilTex, ivec3(ivec2(gl_FragCoord.xy) % LUT_SIZE, 2.0), 0); /* ---------------------------------------------------------------- */ /* -------------------- SCENE LAMPS LIGHTING ---------------------- */ @@ -187,7 +177,7 @@ void CLOSURE_NAME( norm_view = normalize(cross(norm_view, N)); /* Normal facing view */ #endif - for (int i = 0; i < MAX_LIGHT && i < light_count; ++i) { + for (int i = 0; i < MAX_LIGHT && i < laNumLight; ++i) { LightData ld = lights_data[i]; vec4 l_vector; /* Non-Normalized Light Vector with length in last component. */ @@ -266,7 +256,7 @@ void CLOSURE_NAME( /* Planar Reflections */ /* ---------------------------- */ - for (int i = 0; i < MAX_PLANAR && i < planar_count && spec_accum.a < 0.999; ++i) { + for (int i = 0; i < MAX_PLANAR && i < prbNumPlanar && spec_accum.a < 0.999; ++i) { PlanarData pd = planars_data[i]; /* Fade on geometric normal. */ @@ -312,17 +302,11 @@ void CLOSURE_NAME( /* Screen Space Refraction */ /* ---------------------------- */ #ifdef USE_REFRACTION - if (ssrToggle && roughness < maxRoughness + 0.2) { + if (ssrToggle && roughness < ssrMaxRoughness + 0.2) { /* Find approximated position of the 2nd refraction event. */ vec3 refr_vpos = (refractionDepth > 0.0) ? transform_point(ViewMatrix, refr_pos) : viewPosition; - - float ray_ofs = 1.0 / float(rayCount); - vec4 trans = screen_space_refraction(refr_vpos, N, refr_V, final_ior, roughnessSquared, rand.xzw, 0.0); - if (rayCount > 1) trans += screen_space_refraction(refr_vpos, N, refr_V, final_ior, roughnessSquared, rand.xzw * vec3(1.0, -1.0, -1.0), 1.0 * ray_ofs); - if (rayCount > 2) trans += screen_space_refraction(refr_vpos, N, refr_V, final_ior, roughnessSquared, rand.xwz * vec3(1.0, 1.0, -1.0), 2.0 * ray_ofs); - if (rayCount > 3) trans += screen_space_refraction(refr_vpos, N, refr_V, final_ior, roughnessSquared, rand.xwz * vec3(1.0, -1.0, 1.0), 3.0 * ray_ofs); - trans /= float(rayCount); - trans.a *= smoothstep(maxRoughness + 0.2, maxRoughness, roughness); + vec4 trans = screen_space_refraction(refr_vpos, N, refr_V, final_ior, roughnessSquared, rand); + trans.a *= smoothstep(ssrMaxRoughness + 0.2, ssrMaxRoughness, roughness); accumulate_light(trans.rgb, trans.a, refr_accum); } #endif @@ -342,7 +326,7 @@ void CLOSURE_NAME( #endif /* Starts at 1 because 0 is world probe */ - for (int i = 1; ACCUM.a < 0.999 && i < probe_count && i < MAX_PROBE; ++i) { + for (int i = 1; ACCUM.a < 0.999 && i < prbNumRenderCube && i < MAX_PROBE; ++i) { CubeData cd = probes_data[i]; float fade = probe_attenuation_cube(cd, worldPosition); @@ -402,7 +386,7 @@ void CLOSURE_NAME( /* ---------------------------- */ #if defined(CLOSURE_GLOSSY) || defined(CLOSURE_DIFFUSE) vec3 bent_normal; - float final_ao = occlusion_compute(N, viewPosition, ao, rand.rg, bent_normal); + float final_ao = occlusion_compute(N, viewPosition, ao, rand, bent_normal); #endif @@ -417,12 +401,14 @@ void CLOSURE_NAME( /* This factor is outputed to be used by SSR in order * to match the intensity of the regular reflections. */ ssr_spec = F_ibl(f0, brdf_lut); - if (!(ssrToggle && ssr_id == outputSsrId)) { - /* The SSR pass recompute the occlusion to not apply it to the SSR */ - ssr_spec *= specular_occlusion(NV, final_ao, roughness); + float spec_occlu = specular_occlusion(NV, final_ao, roughness); + + /* The SSR pass recompute the occlusion to not apply it to the SSR */ + if (ssrToggle && ssr_id == outputSsrId) { + spec_occlu = 1.0; } - out_spec += spec_accum.rgb * ssr_spec * float(specToggle); + out_spec += spec_accum.rgb * ssr_spec * spec_occlu * float(specToggle); #endif #ifdef CLOSURE_REFRACTION @@ -452,7 +438,7 @@ void CLOSURE_NAME( /* Irradiance Grids */ /* ---------------------------- */ /* Start at 1 because 0 is world irradiance */ - for (int i = 1; i < MAX_GRID && i < grid_count && diff_accum.a < 0.999; ++i) { + for (int i = 1; i < MAX_GRID && i < prbNumRenderGrid && diff_accum.a < 0.999; ++i) { GridData gd = grids_data[i]; vec3 localpos; @@ -467,7 +453,7 @@ void CLOSURE_NAME( /* ---------------------------- */ /* World Diffuse */ /* ---------------------------- */ - if (diff_accum.a < 0.999 && grid_count > 0) { + if (diff_accum.a < 0.999 && prbNumRenderGrid > 0) { vec3 diff = probe_evaluate_world_diff(bent_normal); accumulate_light(diff, 1.0, diff_accum); } diff --git a/source/blender/draw/engines/eevee/shaders/ltc_lib.glsl b/source/blender/draw/engines/eevee/shaders/ltc_lib.glsl index ffaa81c3638..5c62cb19152 100644 --- a/source/blender/draw/engines/eevee/shaders/ltc_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/ltc_lib.glsl @@ -1,150 +1,140 @@ -/* Mainly From https://eheitzresearch.wordpress.com/415-2/ */ +/** + * Adapted from : + * Real-Time Polygonal-Light Shading with Linearly Transformed Cosines. + * Eric Heitz, Jonathan Dupuy, Stephen Hill and David Neubelt. + * ACM Transactions on Graphics (Proceedings of ACM SIGGRAPH 2016) 35(4), 2016. + * Project page: https://eheitzresearch.wordpress.com/415-2/ + **/ #define USE_LTC #ifndef UTIL_TEX #define UTIL_TEX uniform sampler2DArray utilTex; +#define texelfetch_noise_tex(coord) texelFetch(utilTex, ivec3(ivec2(coord) % LUT_SIZE, 2.0), 0) #endif /* UTIL_TEX */ -/* from Real-Time Area Lighting: a Journey from Research to Production - * Stephen Hill and Eric Heitz */ -float edge_integral(vec3 p1, vec3 p2) +/* Diffuse *clipped* sphere integral. */ +float diffuse_sphere_integral_lut(float avg_dir_z, float form_factor) { -#if 0 - /* more accurate replacement of acos */ - float x = dot(p1, p2); - float y = abs(x); + vec2 uv = vec2(avg_dir_z * 0.5 + 0.5, form_factor); + uv = uv * (LUT_SIZE - 1.0) / LUT_SIZE + 0.5 / LUT_SIZE; - float a = 5.42031 + (3.12829 + 0.0902326 * y) * y; - float b = 3.45068 + (4.18814 + y) * y; - float theta_sintheta = a / b; - - if (x < 0.0) { - theta_sintheta = (M_PI / sqrt(1.0 - x * x)) - theta_sintheta; - } - vec3 u = cross(p1, p2); - return theta_sintheta * dot(u, N); -#endif - float cos_theta = dot(p1, p2); - cos_theta = clamp(cos_theta, -0.9999, 0.9999); + return texture(utilTex, vec3(uv, 1.0)).w; +} - float theta = acos(cos_theta); - vec3 u = normalize(cross(p1, p2)); - return theta * cross(p1, p2).z / sin(theta); +float diffuse_sphere_integral_cheap(float avg_dir_z, float form_factor) +{ + return max((form_factor * form_factor + avg_dir_z) / (form_factor + 1.0), 0.0); } -int clip_quad_to_horizon(inout vec3 L[5]) +/** + * An extended version of the implementation from + * "How to solve a cubic equation, revisited" + * http://momentsingraphics.de/?p=105 + **/ +vec3 solve_cubic(vec4 coefs) { - /* detect clipping config */ - int config = 0; - if (L[0].z > 0.0) config += 1; - if (L[1].z > 0.0) config += 2; - if (L[2].z > 0.0) config += 4; - if (L[3].z > 0.0) config += 8; + /* Normalize the polynomial */ + coefs.xyz /= coefs.w; + /* Divide middle coefficients by three */ + coefs.yz /= 3.0; - /* clip */ - int n = 0; + float A = coefs.w; + float B = coefs.z; + float C = coefs.y; + float D = coefs.x; - if (config == 0) - { - /* clip all */ - } - else if (config == 1) /* V1 clip V2 V3 V4 */ - { - n = 3; - L[1] = -L[1].z * L[0] + L[0].z * L[1]; - L[2] = -L[3].z * L[0] + L[0].z * L[3]; - } - else if (config == 2) /* V2 clip V1 V3 V4 */ - { - n = 3; - L[0] = -L[0].z * L[1] + L[1].z * L[0]; - L[2] = -L[2].z * L[1] + L[1].z * L[2]; - } - else if (config == 3) /* V1 V2 clip V3 V4 */ - { - n = 4; - L[2] = -L[2].z * L[1] + L[1].z * L[2]; - L[3] = -L[3].z * L[0] + L[0].z * L[3]; - } - else if (config == 4) /* V3 clip V1 V2 V4 */ - { - n = 3; - L[0] = -L[3].z * L[2] + L[2].z * L[3]; - L[1] = -L[1].z * L[2] + L[2].z * L[1]; - } - else if (config == 5) /* V1 V3 clip V2 V4) impossible */ - { - n = 0; - } - else if (config == 6) /* V2 V3 clip V1 V4 */ - { - n = 4; - L[0] = -L[0].z * L[1] + L[1].z * L[0]; - L[3] = -L[3].z * L[2] + L[2].z * L[3]; - } - else if (config == 7) /* V1 V2 V3 clip V4 */ - { - n = 5; - L[4] = -L[3].z * L[0] + L[0].z * L[3]; - L[3] = -L[3].z * L[2] + L[2].z * L[3]; - } - else if (config == 8) /* V4 clip V1 V2 V3 */ - { - n = 3; - L[0] = -L[0].z * L[3] + L[3].z * L[0]; - L[1] = -L[2].z * L[3] + L[3].z * L[2]; - L[2] = L[3]; - } - else if (config == 9) /* V1 V4 clip V2 V3 */ - { - n = 4; - L[1] = -L[1].z * L[0] + L[0].z * L[1]; - L[2] = -L[2].z * L[3] + L[3].z * L[2]; - } - else if (config == 10) /* V2 V4 clip V1 V3) impossible */ - { - n = 0; - } - else if (config == 11) /* V1 V2 V4 clip V3 */ - { - n = 5; - L[4] = L[3]; - L[3] = -L[2].z * L[3] + L[3].z * L[2]; - L[2] = -L[2].z * L[1] + L[1].z * L[2]; - } - else if (config == 12) /* V3 V4 clip V1 V2 */ + /* Compute the Hessian and the discriminant */ + vec3 delta = vec3( + -coefs.z*coefs.z + coefs.y, + -coefs.y*coefs.z + coefs.x, + dot(vec2(coefs.z, -coefs.y), coefs.xy) + ); + + /* Discriminant */ + float discr = dot(vec2(4.0 * delta.x, -delta.y), delta.zy); + + vec2 xlc, xsc; + + /* Algorithm A */ { - n = 4; - L[1] = -L[1].z * L[2] + L[2].z * L[1]; - L[0] = -L[0].z * L[3] + L[3].z * L[0]; + float A_a = 1.0; + float C_a = delta.x; + float D_a = -2.0 * B * delta.x + delta.y; + + /* Take the cubic root of a normalized complex number */ + float theta = atan(sqrt(discr), -D_a) / 3.0; + + float x_1a = 2.0 * sqrt(-C_a) * cos(theta); + float x_3a = 2.0 * sqrt(-C_a) * cos(theta + (2.0 / 3.0) * M_PI); + + float xl; + if ((x_1a + x_3a) > 2.0 * B) { + xl = x_1a; + } + else { + xl = x_3a; + } + + xlc = vec2(xl - B, A); } - else if (config == 13) /* V1 V3 V4 clip V2 */ + + /* Algorithm D */ { - n = 5; - L[4] = L[3]; - L[3] = L[2]; - L[2] = -L[1].z * L[2] + L[2].z * L[1]; - L[1] = -L[1].z * L[0] + L[0].z * L[1]; + float A_d = D; + float C_d = delta.z; + float D_d = -D * delta.y + 2.0 * C * delta.z; + + /* Take the cubic root of a normalized complex number */ + float theta = atan(D * sqrt(discr), -D_d) / 3.0; + + float x_1d = 2.0 * sqrt(-C_d) * cos(theta); + float x_3d = 2.0 * sqrt(-C_d) * cos(theta + (2.0 / 3.0) * M_PI); + + float xs; + if (x_1d + x_3d < 2.0 * C) + xs = x_1d; + else + xs = x_3d; + + xsc = vec2(-D, xs + C); } - else if (config == 14) /* V2 V3 V4 clip V1 */ - { - n = 5; - L[4] = -L[0].z * L[3] + L[3].z * L[0]; - L[0] = -L[0].z * L[1] + L[1].z * L[0]; + + float E = xlc.y * xsc.y; + float F = -xlc.x * xsc.y - xlc.y * xsc.x; + float G = xlc.x * xsc.x; + + vec2 xmc = vec2(C * F - B * G, -B * F + C * E); + + vec3 root = vec3(xsc.x / xsc.y, + xmc.x / xmc.y, + xlc.x / xlc.y); + + if (root.x < root.y && root.x < root.z) { + root.xyz = root.yxz; } - else if (config == 15) /* V1 V2 V3 V4 */ - { - n = 4; + else if (root.z < root.x && root.z < root.y) { + root.xyz = root.xzy; } - if (n == 3) - L[3] = L[0]; - if (n == 4) - L[4] = L[0]; + return root; +} + +/* from Real-Time Area Lighting: a Journey from Research to Production + * Stephen Hill and Eric Heitz */ +vec3 edge_integral_vec(vec3 v1, vec3 v2) +{ + float x = dot(v1, v2); + float y = abs(x); + + float a = 0.8543985 + (0.4965155 + 0.0145206 * y) * y; + float b = 3.4175940 + (4.1616724 + y) * y; + float v = a / b; - return n; + float theta_sintheta = (x > 0.0) ? v : 0.5 * inversesqrt(max(1.0 - x * x, 1e-7)) - v; + + return cross(v1, v2) * theta_sintheta; } mat3 ltc_matrix(vec4 lut) @@ -159,7 +149,7 @@ mat3 ltc_matrix(vec4 lut) return Minv; } -float ltc_evaluate(vec3 N, vec3 V, mat3 Minv, vec3 corners[4]) +void ltc_transform_quad(vec3 N, vec3 V, mat3 Minv, inout vec3 corners[4]) { /* Avoid dot(N, V) == 1 in ortho mode, leading T1 normalize to fail. */ V = normalize(V + 1e-8); @@ -172,42 +162,51 @@ float ltc_evaluate(vec3 N, vec3 V, mat3 Minv, vec3 corners[4]) /* rotate area light in (T1, T2, R) basis */ Minv = Minv * transpose(mat3(T1, T2, N)); - /* polygon (allocate 5 vertices for clipping) */ - vec3 L[5]; - L[0] = Minv * corners[0]; - L[1] = Minv * corners[1]; - L[2] = Minv * corners[2]; - L[3] = Minv * corners[3]; - - int n = clip_quad_to_horizon(L); - - if (n == 0) - return 0.0; - - /* project onto sphere */ - L[0] = normalize(L[0]); - L[1] = normalize(L[1]); - L[2] = normalize(L[2]); - L[3] = normalize(L[3]); - L[4] = normalize(L[4]); - - /* integrate */ - float sum = 0.0; - - sum += edge_integral(L[0], L[1]); - sum += edge_integral(L[1], L[2]); - sum += edge_integral(L[2], L[3]); - if (n >= 4) - sum += edge_integral(L[3], L[4]); - if (n == 5) - sum += edge_integral(L[4], L[0]); - - return abs(sum); + /* Apply LTC inverse matrix. */ + corners[0] = normalize(Minv * corners[0]); + corners[1] = normalize(Minv * corners[1]); + corners[2] = normalize(Minv * corners[2]); + corners[3] = normalize(Minv * corners[3]); } -/* Aproximate circle with an octogone */ -#define LTC_CIRCLE_RES 8 -float ltc_evaluate_circle(vec3 N, vec3 V, mat3 Minv, vec3 p[LTC_CIRCLE_RES]) +/* If corners have already pass through ltc_transform_quad(), then N **MUST** be vec3(0.0, 0.0, 1.0), + * corresponding to the Up axis of the shading basis. */ +float ltc_evaluate_quad(vec3 corners[4], vec3 N) +{ + /* Approximation using a sphere of the same solid angle than the quad. + * Finding the clipped sphere diffuse integral is easier than clipping the quad. */ + vec3 avg_dir; + avg_dir = edge_integral_vec(corners[0], corners[1]); + avg_dir += edge_integral_vec(corners[1], corners[2]); + avg_dir += edge_integral_vec(corners[2], corners[3]); + avg_dir += edge_integral_vec(corners[3], corners[0]); + + float form_factor = length(avg_dir); + float avg_dir_z = dot(N, avg_dir / form_factor); + +#if 1 /* use tabulated horizon-clipped sphere */ + return form_factor * diffuse_sphere_integral_lut(avg_dir_z, form_factor); +#else /* Less accurate version, a bit cheaper. */ + return form_factor * diffuse_sphere_integral_cheap(avg_dir_z, form_factor); +#endif +} + +/* If disk does not need to be transformed and is already front facing. */ +float ltc_evaluate_disk_simple(float disk_radius, float NL) +{ + float r_sqr = disk_radius * disk_radius; + float one_r_sqr = 1.0 + r_sqr; + float form_factor = r_sqr * inversesqrt(one_r_sqr * one_r_sqr); + +#if 1 /* use tabulated horizon-clipped sphere */ + return form_factor * diffuse_sphere_integral_lut(NL, form_factor); +#else /* Less accurate version, a bit cheaper. */ + return form_factor * diffuse_sphere_integral_cheap(NL, form_factor); +#endif +} + +/* disk_points are WS vectors from the shading point to the disk "bounding domain" */ +float ltc_evaluate_disk(vec3 N, vec3 V, mat3 Minv, vec3 disk_points[3]) { /* Avoid dot(N, V) == 1 in ortho mode, leading T1 normalize to fail. */ V = normalize(V + 1e-8); @@ -218,23 +217,106 @@ float ltc_evaluate_circle(vec3 N, vec3 V, mat3 Minv, vec3 p[LTC_CIRCLE_RES]) T2 = cross(N, T1); /* rotate area light in (T1, T2, R) basis */ - Minv = Minv * transpose(mat3(T1, T2, N)); + mat3 R = transpose(mat3(T1, T2, N)); - for (int i = 0; i < LTC_CIRCLE_RES; ++i) { - p[i] = Minv * p[i]; - /* clip to horizon */ - p[i].z = max(0.0, p[i].z); - /* project onto sphere */ - p[i] = normalize(p[i]); - } + /* Intermediate step: init ellipse. */ + vec3 L_[3]; + L_[0] = mul(R, disk_points[0]); + L_[1] = mul(R, disk_points[1]); + L_[2] = mul(R, disk_points[2]); + + vec3 C = 0.5 * (L_[0] + L_[2]); + vec3 V1 = 0.5 * (L_[1] - L_[2]); + vec3 V2 = 0.5 * (L_[1] - L_[0]); + + /* Transform ellipse by Minv. */ + C = Minv * C; + V1 = Minv * V1; + V2 = Minv * V2; + + /* Compute eigenvectors of new ellipse. */ - /* integrate */ - float sum = 0.0; - for (int i = 0; i < LTC_CIRCLE_RES - 1; ++i) { - sum += edge_integral(p[i], p[i + 1]); + float d11 = dot(V1, V1); + float d22 = dot(V2, V2); + float d12 = dot(V1, V2); + float a, b; /* Eigenvalues */ + const float threshold = 0.0007; /* Can be adjusted. Fix artifacts. */ + if (abs(d12) / sqrt(d11 * d22) > threshold) { + float tr = d11 + d22; + float det = -d12 * d12 + d11 * d22; + + /* use sqrt matrix to solve for eigenvalues */ + det = sqrt(det); + float u = 0.5 * sqrt(tr - 2.0 * det); + float v = 0.5 * sqrt(tr + 2.0 * det); + float e_max = (u + v); + float e_min = (u - v); + e_max *= e_max; + e_min *= e_min; + + vec3 V1_, V2_; + if (d11 > d22) { + V1_ = d12 * V1 + (e_max - d11) * V2; + V2_ = d12 * V1 + (e_min - d11) * V2; + } + else { + V1_ = d12 * V2 + (e_max - d22) * V1; + V2_ = d12 * V2 + (e_min - d22) * V1; + } + + a = 1.0 / e_max; + b = 1.0 / e_min; + V1 = normalize(V1_); + V2 = normalize(V2_); } - sum += edge_integral(p[LTC_CIRCLE_RES - 1], p[0]); + else { + a = 1.0 / d11; + b = 1.0 / d22; + V1 *= sqrt(a); + V2 *= sqrt(b); + } + + /* Now find front facing ellipse with same solid angle. */ - return max(0.0, sum); + vec3 V3 = normalize(cross(V1, V2)); + if (dot(C, V3) < 0.0) + V3 *= -1.0; + + float L = dot(V3, C); + float x0 = dot(V1, C) / L; + float y0 = dot(V2, C) / L; + + a *= L*L; + b *= L*L; + + float c0 = a * b; + float c1 = a * b * (1.0 + x0 * x0 + y0 * y0) - a - b; + float c2 = 1.0 - a * (1.0 + x0 * x0) - b * (1.0 + y0 * y0); + float c3 = 1.0; + + vec3 roots = solve_cubic(vec4(c0, c1, c2, c3)); + float e1 = roots.x; + float e2 = roots.y; + float e3 = roots.z; + + vec3 avg_dir = vec3(a * x0 / (a - e2), b * y0 / (b - e2), 1.0); + + mat3 rotate = mat3(V1, V2, V3); + + avg_dir = rotate * avg_dir; + avg_dir = normalize(avg_dir); + + /* L1, L2 are the extends of the front facing ellipse. */ + float L1 = sqrt(-e2/e3); + float L2 = sqrt(-e2/e1); + + /* Find the sphere and compute lighting. */ + float form_factor = max(0.0, L1 * L2 * inversesqrt((1.0 + L1 * L1) * (1.0 + L2 * L2))); + +#if 1 /* use tabulated horizon-clipped sphere */ + return form_factor * diffuse_sphere_integral_lut(avg_dir.z, form_factor); +#else /* Less accurate version, a bit cheaper. */ + return form_factor * diffuse_sphere_integral_cheap(avg_dir.z, form_factor); +#endif } diff --git a/source/blender/draw/engines/eevee/shaders/prepass_frag.glsl b/source/blender/draw/engines/eevee/shaders/prepass_frag.glsl index f921d56e3bc..1c0e65f0613 100644 --- a/source/blender/draw/engines/eevee/shaders/prepass_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/prepass_frag.glsl @@ -10,14 +10,15 @@ float hash3d(vec3 a) { return hash(vec2(hash(a.xy), a.z)); } -//uniform float hashScale; -float hashScale = 0.001; +uniform float hashAlphaOffset; float hashed_alpha_threshold(vec3 co) { + const float hash_scale = 1.0; /* Roughly in pixel */ + /* Find the discretized derivatives of our coordinates. */ float max_deriv = max(length(dFdx(co)), length(dFdy(co))); - float pix_scale = 1.0 / (hashScale * max_deriv); + float pix_scale = 1.0 / (hash_scale * max_deriv); /* Find two nearest log-discretized noise scales. */ float pix_scale_log = log2(pix_scale); @@ -53,7 +54,8 @@ float hashed_alpha_threshold(vec3 co) /* Avoids threshold == 0. */ threshold = clamp(threshold, 1.0e-6, 1.0); - return threshold; + /* Jitter the threshold for TAA accumulation. */ + return fract(threshold + hashAlphaOffset); } #endif diff --git a/source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl b/source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl index c593081ce91..cb75731b7da 100644 --- a/source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl @@ -1,13 +1,5 @@ #define MAX_STEP 256 -uniform vec4 ssrParameters; - -#define ssrQuality ssrParameters.x -#define ssrThickness ssrParameters.y -#define ssrPixelSize ssrParameters.zw - -uniform float borderFadeFactor; - float sample_depth(vec2 uv, int index, float lod) { #ifdef PLANAR_PROBE_RAYTRACE @@ -233,7 +225,7 @@ vec3 raycast( float screen_border_mask(vec2 hit_co) { const float margin = 0.003; - float atten = borderFadeFactor + margin; /* Screen percentage */ + float atten = ssrBorderFac + margin; /* Screen percentage */ hit_co = smoothstep(margin, atten, hit_co) * (1 - smoothstep(1.0 - atten, 1.0 - margin, hit_co)); float screenfade = hit_co.x * hit_co.y; diff --git a/source/blender/draw/engines/eevee/shaders/ssr_lib.glsl b/source/blender/draw/engines/eevee/shaders/ssr_lib.glsl index 92287d2ecbc..6c7bfeb6b82 100644 --- a/source/blender/draw/engines/eevee/shaders/ssr_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/ssr_lib.glsl @@ -2,10 +2,9 @@ #define BTDF_BIAS 0.85 -vec4 screen_space_refraction(vec3 viewPosition, vec3 N, vec3 V, float ior, float roughnessSquared, vec3 rand, float ofs) +vec4 screen_space_refraction(vec3 viewPosition, vec3 N, vec3 V, float ior, float roughnessSquared, vec4 rand) { float a2 = max(5e-6, roughnessSquared * roughnessSquared); - float jitter = fract(rand.x + ofs); /* Importance sampling bias */ rand.x = mix(rand.x, 0.0, BTDF_BIAS); @@ -13,12 +12,12 @@ vec4 screen_space_refraction(vec3 viewPosition, vec3 N, vec3 V, float ior, float vec3 T, B; float NH; make_orthonormal_basis(N, T, B); - vec3 H = sample_ggx(rand, a2, N, T, B, NH); /* Microfacet normal */ + vec3 H = sample_ggx(rand.xzw, a2, N, T, B, NH); /* Microfacet normal */ float pdf = pdf_ggx_reflect(NH, a2); /* If ray is bad (i.e. going below the plane) regenerate. */ if (F_eta(ior, dot(H, V)) < 1.0) { - H = sample_ggx(rand * vec3(1.0, -1.0, -1.0), a2, N, T, B, NH); /* Microfacet normal */ + H = sample_ggx(rand.xzw * vec3(1.0, -1.0, -1.0), a2, N, T, B, NH); /* Microfacet normal */ pdf = pdf_ggx_reflect(NH, a2); } @@ -33,7 +32,7 @@ vec4 screen_space_refraction(vec3 viewPosition, vec3 N, vec3 V, float ior, float R = transform_direction(ViewMatrix, R); - vec3 hit_pos = raycast(-1, viewPosition, R * 1e16, ssrThickness, jitter, ssrQuality, roughnessSquared, false); + vec3 hit_pos = raycast(-1, viewPosition, R * 1e16, ssrThickness, rand.y, ssrQuality, roughnessSquared, false); if ((hit_pos.z > 0.0) && (F_eta(ior, dot(H, V)) < 1.0)) { hit_pos = get_view_space_from_depth(hit_pos.xy, hit_pos.z); diff --git a/source/blender/draw/engines/eevee/shaders/update_noise_frag.glsl b/source/blender/draw/engines/eevee/shaders/update_noise_frag.glsl new file mode 100644 index 00000000000..13ffe02eb0d --- /dev/null +++ b/source/blender/draw/engines/eevee/shaders/update_noise_frag.glsl @@ -0,0 +1,18 @@ + +uniform sampler2D blueNoise; +uniform vec3 offsets; + +out vec4 FragColor; + +#define M_2PI 6.28318530717958647692 + +void main(void) +{ + vec2 blue_noise = texelFetch(blueNoise, ivec2(gl_FragCoord.xy), 0).xy; + + float noise = fract(blue_noise.y + offsets.z); + FragColor.x = fract(blue_noise.x + offsets.x); + FragColor.y = fract(blue_noise.y + offsets.y); + FragColor.z = cos(noise * M_2PI); + FragColor.w = sin(noise * M_2PI); +} diff --git a/source/blender/draw/engines/eevee/shaders/volumetric_frag.glsl b/source/blender/draw/engines/eevee/shaders/volumetric_frag.glsl index 00e01e753f9..3a293647f84 100644 --- a/source/blender/draw/engines/eevee/shaders/volumetric_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/volumetric_frag.glsl @@ -4,9 +4,6 @@ #define NODETREE_EXEC -uniform ivec3 volumeTextureSize; -uniform vec3 volume_jitter; - #ifdef MESH_SHADER uniform mat4 volumeObjectMatrix; uniform vec3 volumeOrcoLoc; @@ -33,7 +30,7 @@ layout(location = 3) out vec4 volumePhase; void main() { ivec3 volume_cell = ivec3(gl_FragCoord.xy, slice); - vec3 ndc_cell = volume_to_ndc((vec3(volume_cell) + volume_jitter) / volumeTextureSize); + vec3 ndc_cell = volume_to_ndc((vec3(volume_cell) + volJitter.xyz) * volInvTexSize.xyz); viewPosition = get_view_space_from_depth(ndc_cell.xy, ndc_cell.z); worldPosition = transform_point(ViewMatrixInverse, viewPosition); diff --git a/source/blender/draw/engines/eevee/shaders/volumetric_lib.glsl b/source/blender/draw/engines/eevee/shaders/volumetric_lib.glsl index 1376c53d633..1a8167c2830 100644 --- a/source/blender/draw/engines/eevee/shaders/volumetric_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/volumetric_lib.glsl @@ -2,22 +2,16 @@ /* Based on Frosbite Unified Volumetric. * https://www.ea.com/frostbite/news/physically-based-unified-volumetric-rendering-in-frostbite */ -uniform float volume_light_clamp; - -uniform vec3 volume_param; /* Parameters to the volume Z equation */ - -uniform vec2 volume_uv_ratio; /* To convert volume uvs to screen uvs */ - /* Volume slice to view space depth. */ float volume_z_to_view_z(float z) { if (ProjectionMatrix[3][3] == 0.0) { /* Exponential distribution */ - return (exp2(z / volume_param.z) - volume_param.x) / volume_param.y; + return (exp2(z / volDepthParameters.z) - volDepthParameters.x) / volDepthParameters.y; } else { /* Linear distribution */ - return mix(volume_param.x, volume_param.y, z); + return mix(volDepthParameters.x, volDepthParameters.y, z); } } @@ -25,11 +19,11 @@ float view_z_to_volume_z(float depth) { if (ProjectionMatrix[3][3] == 0.0) { /* Exponential distribution */ - return volume_param.z * log2(depth * volume_param.y + volume_param.x); + return volDepthParameters.z * log2(depth * volDepthParameters.y + volDepthParameters.x); } else { /* Linear distribution */ - return (depth - volume_param.x) * volume_param.z; + return (depth - volDepthParameters.x) * volDepthParameters.z; } } @@ -38,7 +32,7 @@ vec3 volume_to_ndc(vec3 cos) { cos.z = volume_z_to_view_z(cos.z); cos.z = get_depth_from_view_z(cos.z); - cos.xy /= volume_uv_ratio; + cos.xy /= volCoordScale.xy; return cos; } @@ -46,7 +40,7 @@ vec3 ndc_to_volume(vec3 cos) { cos.z = get_view_z_from_depth(cos.z); cos.z = view_z_to_volume_z(cos.z); - cos.xy *= volume_uv_ratio; + cos.xy *= volCoordScale.xy; return cos; } @@ -71,14 +65,17 @@ vec3 light_volume(LightData ld, vec4 l_vector) /* TODO : Area lighting ? */ /* XXX : Removing Area Power. */ /* TODO : put this out of the shader. */ + /* See eevee_light_setup(). */ if (ld.l_type == AREA) { - power = 0.0962 * (ld.l_sizex * ld.l_sizey * 4.0 * M_PI); + power = (ld.l_sizex * ld.l_sizey * 4.0 * M_PI) * (1.0 / 80.0); + power *= 20.0 * max(0.0, dot(-ld.l_forward, l_vector.xyz / l_vector.w)); /* XXX ad hoc, empirical */ } else if (ld.l_type == SUN) { - power = 1.0; + power = (4.0f * ld.l_radius * ld.l_radius * M_2PI) * (1.0 / 12.5); /* Removing area light power*/ + power *= M_2PI * 0.78; /* Matching cycles with point light. */ } else { - power = 0.0248 * (4.0 * ld.l_radius * ld.l_radius * M_PI * M_PI); + power = (4.0 * ld.l_radius * ld.l_radius) * (1.0 /10.0); } /* OPTI: find a better way than calculating this on the fly */ @@ -87,15 +84,13 @@ vec3 light_volume(LightData ld, vec4 l_vector) power /= (l_vector.w * l_vector.w); - lum = min(lum * power, volume_light_clamp); + lum = min(lum * power, volLightClamp); return tint * lum; } #define VOLUMETRIC_SHADOW_MAX_STEP 32.0 -uniform float volume_shadows_steps; - vec3 participating_media_extinction(vec3 wpos, sampler3D volume_extinction) { /* Waiting for proper volume shadowmaps and out of frustum shadow map. */ @@ -110,11 +105,11 @@ vec3 light_volume_shadow(LightData ld, vec3 ray_wpos, vec4 l_vector, sampler3D v { #if defined(VOLUME_SHADOW) /* Heterogeneous volume shadows */ - float dd = l_vector.w / volume_shadows_steps; + float dd = l_vector.w / volShadowSteps; vec3 L = l_vector.xyz * l_vector.w; vec3 shadow = vec3(1.0); - for (float s = 0.5; s < VOLUMETRIC_SHADOW_MAX_STEP && s < (volume_shadows_steps - 0.1); s += 1.0) { - vec3 pos = ray_wpos + L * (s / volume_shadows_steps); + for (float s = 0.5; s < VOLUMETRIC_SHADOW_MAX_STEP && s < (volShadowSteps - 0.1); s += 1.0) { + vec3 pos = ray_wpos + L * (s / volShadowSteps); vec3 s_extinction = participating_media_extinction(pos, volume_extinction); shadow *= exp(-s_extinction * dd); } diff --git a/source/blender/draw/engines/eevee/shaders/volumetric_scatter_frag.glsl b/source/blender/draw/engines/eevee/shaders/volumetric_scatter_frag.glsl index ea402ff3d99..fcbb6661b14 100644 --- a/source/blender/draw/engines/eevee/shaders/volumetric_scatter_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/volumetric_scatter_frag.glsl @@ -13,28 +13,20 @@ uniform sampler3D volumePhase; uniform sampler3D historyScattering; uniform sampler3D historyTransmittance; -uniform vec3 volume_jitter; -uniform float volume_history_alpha; -uniform int light_count; -uniform mat4 PastViewProjectionMatrix; - flat in int slice; layout(location = 0) out vec4 outScattering; layout(location = 1) out vec4 outTransmittance; -#define VOLUME_LIGHTING - void main() { - vec3 volume_tex_size = vec3(textureSize(volumeScattering, 0)); ivec3 volume_cell = ivec3(gl_FragCoord.xy, slice); /* Emission */ outScattering = texelFetch(volumeEmission, volume_cell, 0); outTransmittance = texelFetch(volumeExtinction, volume_cell, 0); vec3 s_scattering = texelFetch(volumeScattering, volume_cell, 0).rgb; - vec3 volume_ndc = volume_to_ndc((vec3(volume_cell) + volume_jitter) / volume_tex_size); + vec3 volume_ndc = volume_to_ndc((vec3(volume_cell) + volJitter.xyz) * volInvTexSize.xyz); vec3 worldPosition = get_world_space_from_depth(volume_ndc.xy, volume_ndc.z); vec3 wdir = cameraVec; @@ -45,7 +37,7 @@ void main() outScattering.rgb += irradiance_volumetric(worldPosition) * s_scattering * phase_function_isotropic(); #ifdef VOLUME_LIGHTING /* Lights */ - for (int i = 0; i < MAX_LIGHT && i < light_count; ++i) { + for (int i = 0; i < MAX_LIGHT && i < laNumLight; ++i) { LightData ld = lights_data[i]; @@ -63,16 +55,16 @@ void main() /* Temporal supersampling */ /* Note : this uses the cell non-jittered position (texel center). */ - vec3 curr_ndc = volume_to_ndc(vec3(gl_FragCoord.xy, float(slice) + 0.5) / volume_tex_size); + vec3 curr_ndc = volume_to_ndc(vec3(gl_FragCoord.xy, float(slice) + 0.5) * volInvTexSize.xyz); vec3 wpos = get_world_space_from_depth(curr_ndc.xy, curr_ndc.z); - vec3 prev_ndc = project_point(PastViewProjectionMatrix, wpos); + vec3 prev_ndc = project_point(pastViewProjectionMatrix, wpos); vec3 prev_volume = ndc_to_volume(prev_ndc * 0.5 + 0.5); - if ((volume_history_alpha > 0.0) && all(greaterThan(prev_volume, vec3(0.0))) && all(lessThan(prev_volume, vec3(1.0)))) { + if ((volHistoryAlpha > 0.0) && all(greaterThan(prev_volume, vec3(0.0))) && all(lessThan(prev_volume, vec3(1.0)))) { vec4 h_Scattering = texture(historyScattering, prev_volume); vec4 h_Transmittance = texture(historyTransmittance, prev_volume); - outScattering = mix(outScattering, h_Scattering, volume_history_alpha); - outTransmittance = mix(outTransmittance, h_Transmittance, volume_history_alpha); + outScattering = mix(outScattering, h_Scattering, volHistoryAlpha); + outTransmittance = mix(outTransmittance, h_Transmittance, volHistoryAlpha); } /* Catch NaNs */ |