Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/draw/engines/eevee/shaders/effect_ssr_frag.glsl')
-rw-r--r--source/blender/draw/engines/eevee/shaders/effect_ssr_frag.glsl841
1 files changed, 450 insertions, 391 deletions
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 2178b15a753..44f22848c2f 100644
--- a/source/blender/draw/engines/eevee/shaders/effect_ssr_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/effect_ssr_frag.glsl
@@ -8,21 +8,21 @@ 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;
+ 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);
- vec2 hit_co = vec2(abs(hit_data)) / 32767.0; /* 16bit signed int limit */
- if (is_planar) {
- hit_co.x = 1.0 - hit_co.x;
- }
- return hit_co;
+ is_planar = (hit_data.x < 0);
+ has_hit = (hit_data.y > 0);
+ vec2 hit_co = vec2(abs(hit_data)) / 32767.0; /* 16bit signed int limit */
+ if (is_planar) {
+ hit_co.x = 1.0 - hit_co.x;
+ }
+ return hit_co;
}
#ifdef STEP_RAYTRACE
@@ -33,130 +33,138 @@ uniform sampler2D specroughBuffer;
layout(location = 0) out ivec2 hitData;
layout(location = 1) out float pdfData;
-void do_planar_ssr(int index, vec3 V, vec3 N, vec3 T, vec3 B, vec3 planeNormal, vec3 viewPosition, float a2, vec4 rand)
+void do_planar_ssr(int index,
+ vec3 V,
+ vec3 N,
+ vec3 T,
+ vec3 B,
+ vec3 planeNormal,
+ vec3 viewPosition,
+ float a2,
+ vec4 rand)
{
- float NH;
- vec3 H = sample_ggx(rand.xzw, a2, N, T, B, NH); /* Microfacet normal */
- float 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);
+ 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.xzw * vec3(1.0, -1.0, -1.0), a2, N, T, B, NH); /* Microfacet normal */
- pdf = pdf_ggx_reflect(NH, a2);
+ /* If ray is bad (i.e. going below the plane) regenerate. */
+ if (dot(R, planeNormal) > 0.0) {
+ 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);
- }
+ R = reflect(-V, H);
+ R = reflect(R, planeNormal);
+ }
- pdfData = min(1024e32, pdf); /* Theoretical limit of 16bit float */
+ 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, rand.y, ssrQuality, a2, false);
+ /* 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, rand.y, ssrQuality, a2, false);
- hitData = encode_hit_data(hit_pos.xy, (hit_pos.z > 0.0), true);
+ hitData = encode_hit_data(hit_pos.xy, (hit_pos.z > 0.0), true);
}
void do_ssr(vec3 V, vec3 N, vec3 T, vec3 B, vec3 viewPosition, float a2, vec4 rand)
{
- float NH;
- vec3 H = sample_ggx(rand.xzw, a2, N, T, B, NH); /* Microfacet normal */
- float 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);
- pdfData = min(1024e32, pdf); /* Theoretical limit of 16bit float */
+ vec3 R = reflect(-V, H);
+ pdfData = min(1024e32, pdf); /* Theoretical limit of 16bit float */
- vec3 hit_pos = raycast(-1, viewPosition, R * 1e16, ssrThickness, rand.y, ssrQuality, a2, true);
+ vec3 hit_pos = raycast(-1, viewPosition, R * 1e16, ssrThickness, rand.y, ssrQuality, a2, true);
- hitData = encode_hit_data(hit_pos.xy, (hit_pos.z > 0.0), false);
+ hitData = encode_hit_data(hit_pos.xy, (hit_pos.z > 0.0), false);
}
void main()
{
-#ifdef FULLRES
- ivec2 fullres_texel = ivec2(gl_FragCoord.xy);
- ivec2 halfres_texel = fullres_texel;
-#else
- 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) {
- return;
- }
-
- vec2 uvs = vec2(fullres_texel) / vec2(textureSize(depthBuffer, 0));
-
- /* Using view space */
- vec3 viewPosition = get_view_space_from_depth(uvs, depth);
- vec3 V = viewCameraVec;
- vec3 N = normal_decode(texelFetch(normalBuffer, fullres_texel, 0).rg, V);
-
- /* Retrieve pixel data */
- vec4 speccol_roughness = texelFetch(specroughBuffer, fullres_texel, 0).rgba;
-
- /* Early out */
- if (dot(speccol_roughness.rgb, vec3(1.0)) == 0.0) {
- return;
- }
-
- float roughness = speccol_roughness.a;
- float roughnessSquared = max(1e-3, roughness * roughness);
- float a2 = roughnessSquared * roughnessSquared;
-
- /* Early out */
- if (roughness > ssrMaxRoughness + 0.2) {
- return;
- }
-
- 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);
-
- vec3 T, B;
- make_orthonormal_basis(N, T, B); /* Generate tangent space */
-
- /* Planar Reflections */
- 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);
-
- if (fade > 0.5) {
- /* Find view vector / reflection plane intersection. */
- /* TODO optimize, use view space for all. */
- vec3 tracePosition = line_plane_intersect(worldPosition, cameraVec, pd.pl_plane_eq);
- tracePosition = transform_point(ViewMatrix, tracePosition);
- vec3 planeNormal = transform_direction(ViewMatrix, pd.pl_normal);
-
- do_planar_ssr(i, V, N, T, B, planeNormal, tracePosition, a2, rand);
- return;
- }
- }
-
- do_ssr(V, N, T, B, viewPosition, a2, rand);
+# ifdef FULLRES
+ ivec2 fullres_texel = ivec2(gl_FragCoord.xy);
+ ivec2 halfres_texel = fullres_texel;
+# else
+ 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) {
+ return;
+ }
+
+ vec2 uvs = vec2(fullres_texel) / vec2(textureSize(depthBuffer, 0));
+
+ /* Using view space */
+ vec3 viewPosition = get_view_space_from_depth(uvs, depth);
+ vec3 V = viewCameraVec;
+ vec3 N = normal_decode(texelFetch(normalBuffer, fullres_texel, 0).rg, V);
+
+ /* Retrieve pixel data */
+ vec4 speccol_roughness = texelFetch(specroughBuffer, fullres_texel, 0).rgba;
+
+ /* Early out */
+ if (dot(speccol_roughness.rgb, vec3(1.0)) == 0.0) {
+ return;
+ }
+
+ float roughness = speccol_roughness.a;
+ float roughnessSquared = max(1e-3, roughness * roughness);
+ float a2 = roughnessSquared * roughnessSquared;
+
+ /* Early out */
+ if (roughness > ssrMaxRoughness + 0.2) {
+ return;
+ }
+
+ 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);
+
+ vec3 T, B;
+ make_orthonormal_basis(N, T, B); /* Generate tangent space */
+
+ /* Planar Reflections */
+ 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);
+
+ if (fade > 0.5) {
+ /* Find view vector / reflection plane intersection. */
+ /* TODO optimize, use view space for all. */
+ vec3 tracePosition = line_plane_intersect(worldPosition, cameraVec, pd.pl_plane_eq);
+ tracePosition = transform_point(ViewMatrix, tracePosition);
+ vec3 planeNormal = transform_direction(ViewMatrix, pd.pl_normal);
+
+ do_planar_ssr(i, V, N, T, B, planeNormal, tracePosition, a2, rand);
+ return;
+ }
+ }
+
+ do_ssr(V, N, T, B, viewPosition, a2, rand);
}
#else /* STEP_RESOLVE */
@@ -170,21 +178,43 @@ uniform sampler2D pdfBuffer;
uniform int neighborOffset;
-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),
-
- 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)
-);
+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),
+
+ 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;
-#if 0 /* Finish reprojection with motion vectors */
+# if 0 /* Finish reprojection with motion vectors */
vec3 get_motion_vector(vec3 pos)
{
}
@@ -192,297 +222,326 @@ vec3 get_motion_vector(vec3 pos)
/* http://bitsquid.blogspot.fr/2017/06/reprojecting-reflections_22.html */
vec3 find_reflection_incident_point(vec3 cam, vec3 hit, vec3 pos, vec3 N)
{
- float d_cam = point_plane_projection_dist(cam, pos, N);
- float d_hit = point_plane_projection_dist(hit, pos, N);
+ float d_cam = point_plane_projection_dist(cam, pos, N);
+ float d_hit = point_plane_projection_dist(hit, pos, N);
- if (d_hit < d_cam) {
- /* Swap */
- float tmp = d_cam;
- d_cam = d_hit;
- d_hit = tmp;
- }
+ if (d_hit < d_cam) {
+ /* Swap */
+ float tmp = d_cam;
+ d_cam = d_hit;
+ d_hit = tmp;
+ }
- vec3 proj_cam = cam - (N * d_cam);
- vec3 proj_hit = hit - (N * d_hit);
+ vec3 proj_cam = cam - (N * d_cam);
+ vec3 proj_hit = hit - (N * d_hit);
- return (proj_hit - proj_cam) * d_cam / (d_cam + d_hit) + proj_cam;
+ return (proj_hit - proj_cam) * d_cam / (d_cam + d_hit) + proj_cam;
}
-#endif
+# endif
float brightness(vec3 c)
{
- return max(max(c.r, c.g), c.b);
+ return max(max(c.r, c.g), c.b);
}
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;
+ /* TODO real reprojection with motion vectors, etc... */
+ return project_point(pastViewProjectionMatrix, hit).xy * 0.5 + 0.5;
}
float get_sample_depth(vec2 hit_co, bool is_planar, float planar_index)
{
- if (is_planar) {
- hit_co.x = 1.0 - hit_co.x;
- return textureLod(planarDepth, vec3(hit_co, planar_index), 0.0).r;
- }
- else {
- return textureLod(depthBuffer, hit_co, 0.0).r;
- }
+ if (is_planar) {
+ hit_co.x = 1.0 - hit_co.x;
+ return textureLod(planarDepth, vec3(hit_co, planar_index), 0.0).r;
+ }
+ else {
+ return textureLod(depthBuffer, hit_co, 0.0).r;
+ }
}
-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 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;
-
- 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);
- /* Modify here so mip texel alignment is correct. */
- hit_co.x = 1.0 - hit_co.x;
- }
- else {
- /* Find hit position in previous frame. */
- hit_co = get_reprojected_reflection(hit_pos, worldPosition, N);
- hit_vec = hit_pos - worldPosition;
- }
-
- mask = screen_border_mask(hit_co);
- return hit_vec;
+ vec3 hit_vec;
+
+ 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);
+ /* Modify here so mip texel alignment is correct. */
+ hit_co.x = 1.0 - hit_co.x;
+ }
+ else {
+ /* Find hit position in previous frame. */
+ hit_co = get_reprojected_reflection(hit_pos, worldPosition, N);
+ hit_vec = hit_pos - worldPosition;
+ }
+
+ mask = screen_border_mask(hit_co);
+ return hit_vec;
}
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;
- }
+ 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)
+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. */
- 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. */
- vec4 mip = log2(cone_footprint * max_v2(vec2(textureSize(depthBuffer, 0))));
- mip = clamp(mip, 0.0, MAX_MIP);
-
- /* Correct UVs for mipmaping mis-alignment */
- 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 */
- 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);
-
- vec4 weight = step(1e-8, hit_pdf) * bsdf / max(vec4(1e-8), hit_pdf);
-
- 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);
-
- /* 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[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;
- }
-
- weight_acc += sum(weight);
-
- /* 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;
+ 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. */
+ 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. */
+ vec4 mip = log2(cone_footprint * max_v2(vec2(textureSize(depthBuffer, 0))));
+ mip = clamp(mip, 0.0, MAX_MIP);
+
+ /* Correct UVs for mipmaping mis-alignment */
+ 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 */
+ 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);
+
+ vec4 weight = step(1e-8, hit_pdf) * bsdf / max(vec4(1e-8), hit_pdf);
+
+ 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);
+
+ /* 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[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;
+ }
+
+ weight_acc += sum(weight);
+
+ /* 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()
{
- ivec2 fullres_texel = ivec2(gl_FragCoord.xy);
-#ifdef FULLRES
- ivec2 halfres_texel = fullres_texel;
-#else
- ivec2 halfres_texel = ivec2(gl_FragCoord.xy / 2.0);
-#endif
- vec2 uvs = gl_FragCoord.xy / vec2(textureSize(depthBuffer, 0));
-
- float depth = textureLod(depthBuffer, uvs, 0.0).r;
-
- /* Early out */
- if (depth == 1.0) {
- discard;
- }
-
- /* Using world space */
- vec3 viewPosition = get_view_space_from_depth(uvs, depth); /* Needed for viewCameraVec */
- vec3 worldPosition = transform_point(ViewMatrixInverse, viewPosition);
- vec3 V = cameraVec;
- vec3 vN = normal_decode(texelFetch(normalBuffer, fullres_texel, 0).rg, viewCameraVec);
- vec3 N = transform_direction(ViewMatrixInverse, vN);
- vec4 speccol_roughness = texelFetch(specroughBuffer, fullres_texel, 0).rgba;
-
- /* Early out */
- if (dot(speccol_roughness.rgb, vec3(1.0)) == 0.0) {
- discard;
- }
-
- float roughness = speccol_roughness.a;
- float roughnessSquared = max(1e-3, roughness * roughness);
-
- vec4 spec_accum = vec4(0.0);
-
- /* Resolve SSR */
- float cone_cos = cone_cosine(roughnessSquared);
- 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;
-
- vec4 ssr_accum = vec4(0.0);
- float weight_acc = 0.0;
-
- if (roughness < ssrMaxRoughness + 0.2) {
- /* 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 < prbNumPlanar; ++i) {
- pd = planars_data[i];
-
- float fade = probe_attenuation_planar(pd, worldPosition, N, 0.0);
-
- if (fade > 0.5) {
- planar_index = float(i);
- break;
- }
- }
-
- 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(ssrMaxRoughness + 0.2, ssrMaxRoughness, roughness);
- accumulate_light(ssr_accum.rgb, ssr_accum.a, spec_accum);
- }
-
- /* If SSR contribution is not 1.0, blend with cubemaps */
- if (spec_accum.a < 1.0) {
- fallback_cubemap(N, V, worldPosition, viewPosition, roughness, roughnessSquared, spec_accum);
- }
-
- fragColor = vec4(spec_accum.rgb * speccol_roughness.rgb, 1.0);
+ ivec2 fullres_texel = ivec2(gl_FragCoord.xy);
+# ifdef FULLRES
+ ivec2 halfres_texel = fullres_texel;
+# else
+ ivec2 halfres_texel = ivec2(gl_FragCoord.xy / 2.0);
+# endif
+ vec2 uvs = gl_FragCoord.xy / vec2(textureSize(depthBuffer, 0));
+
+ float depth = textureLod(depthBuffer, uvs, 0.0).r;
+
+ /* Early out */
+ if (depth == 1.0) {
+ discard;
+ }
+
+ /* Using world space */
+ vec3 viewPosition = get_view_space_from_depth(uvs, depth); /* Needed for viewCameraVec */
+ vec3 worldPosition = transform_point(ViewMatrixInverse, viewPosition);
+ vec3 V = cameraVec;
+ vec3 vN = normal_decode(texelFetch(normalBuffer, fullres_texel, 0).rg, viewCameraVec);
+ vec3 N = transform_direction(ViewMatrixInverse, vN);
+ vec4 speccol_roughness = texelFetch(specroughBuffer, fullres_texel, 0).rgba;
+
+ /* Early out */
+ if (dot(speccol_roughness.rgb, vec3(1.0)) == 0.0) {
+ discard;
+ }
+
+ float roughness = speccol_roughness.a;
+ float roughnessSquared = max(1e-3, roughness * roughness);
+
+ vec4 spec_accum = vec4(0.0);
+
+ /* Resolve SSR */
+ float cone_cos = cone_cosine(roughnessSquared);
+ 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;
+
+ vec4 ssr_accum = vec4(0.0);
+ float weight_acc = 0.0;
+
+ if (roughness < ssrMaxRoughness + 0.2) {
+ /* 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 < prbNumPlanar; ++i) {
+ pd = planars_data[i];
+
+ float fade = probe_attenuation_planar(pd, worldPosition, N, 0.0);
+
+ if (fade > 0.5) {
+ planar_index = float(i);
+ break;
+ }
+ }
+
+ 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(ssrMaxRoughness + 0.2, ssrMaxRoughness, roughness);
+ accumulate_light(ssr_accum.rgb, ssr_accum.a, spec_accum);
+ }
+
+ /* If SSR contribution is not 1.0, blend with cubemaps */
+ if (spec_accum.a < 1.0) {
+ fallback_cubemap(N, V, worldPosition, viewPosition, roughness, roughnessSquared, spec_accum);
+ }
+
+ fragColor = vec4(spec_accum.rgb * speccol_roughness.rgb, 1.0);
}
#endif