ssao: implement accurate normal reconstruction
This removes "false AO" effect on geometry edges. Currently this is enabled on desktop only (quality == high).
This commit is contained in:
committed by
Mathias Agopian
parent
f5adbbddb8
commit
dc56408d5f
@@ -189,14 +189,47 @@ fragment {
|
||||
// are essentially equivalent to textureGather (which we don't have on ES3.0),
|
||||
// and this is executed just once.
|
||||
highp vec3 computeViewSpaceNormal(const highp vec3 position, const highp vec2 uv) {
|
||||
precision highp float;
|
||||
highp vec2 uvdx = uv + vec2(materialParams.resolution.z, 0.0);
|
||||
highp vec2 uvdy = uv + vec2(0.0, materialParams.resolution.w);
|
||||
highp vec3 px = computeViewSpacePositionFromDepth(uvdx,
|
||||
vec3 px = computeViewSpacePositionFromDepth(uvdx,
|
||||
sampleDepthLinear(materialParams_depth, uvdx, 0.0, materialParams.depthParams));
|
||||
highp vec3 py = computeViewSpacePositionFromDepth(uvdy,
|
||||
vec3 py = computeViewSpacePositionFromDepth(uvdy,
|
||||
sampleDepthLinear(materialParams_depth, uvdy, 0.0, materialParams.depthParams));
|
||||
highp vec3 dpdx = px - position;
|
||||
highp vec3 dpdy = py - position;
|
||||
vec3 dpdx = px - position;
|
||||
vec3 dpdy = py - position;
|
||||
return faceNormal(dpdx, dpdy);
|
||||
}
|
||||
|
||||
// Accurate view-space normal reconstruction
|
||||
// Based on Yuwen Wu "Accurate Normal Reconstruction"
|
||||
// (https://atyuwen.github.io/posts/normal-reconstruction)
|
||||
highp vec3 computeViewSpaceNormalAccurate(const highp vec3 position, const highp vec2 uv) {
|
||||
precision highp float;
|
||||
|
||||
vec3 pos_c = position;
|
||||
highp vec2 dx = vec2(materialParams.resolution.z, 0.0);
|
||||
highp vec2 dy = vec2(0.0, materialParams.resolution.w);
|
||||
|
||||
vec4 H;
|
||||
H.x = sampleDepth(materialParams_depth, uv - dx, 0.0);
|
||||
H.y = sampleDepth(materialParams_depth, uv + dx, 0.0);
|
||||
H.z = sampleDepth(materialParams_depth, uv - dx * 2.0, 0.0);
|
||||
H.w = sampleDepth(materialParams_depth, uv + dx * 2.0, 0.0);
|
||||
vec2 he = abs((2.0 * H.xy - H.zw) - pos_c.z);
|
||||
vec3 pos_l = computeViewSpacePositionFromDepth(uv - dx, linearizeDepth(H.x, materialParams.depthParams));
|
||||
vec3 pos_r = computeViewSpacePositionFromDepth(uv + dx, linearizeDepth(H.y, materialParams.depthParams));
|
||||
vec3 dpdx = (he.x < he.y) ? (pos_c - pos_l) : (pos_r - pos_c);
|
||||
|
||||
vec4 V;
|
||||
V.x = sampleDepth(materialParams_depth, uv - dy, 0.0);
|
||||
V.y = sampleDepth(materialParams_depth, uv + dy, 0.0);
|
||||
V.z = sampleDepth(materialParams_depth, uv - dy * 2.0, 0.0);
|
||||
V.w = sampleDepth(materialParams_depth, uv + dy * 2.0, 0.0);
|
||||
vec2 ve = abs((2.0 * V.xy - V.zw) - pos_c.z);
|
||||
vec3 pos_d = computeViewSpacePositionFromDepth(uv - dy, linearizeDepth(V.x, materialParams.depthParams));
|
||||
vec3 pos_u = computeViewSpacePositionFromDepth(uv + dy, linearizeDepth(V.y, materialParams.depthParams));
|
||||
vec3 dpdy = (ve.x < ve.y) ? (pos_c - pos_d) : (pos_u - pos_c);
|
||||
return faceNormal(dpdx, dpdy);
|
||||
}
|
||||
|
||||
@@ -314,7 +347,13 @@ fragment {
|
||||
|
||||
highp float depth = sampleDepthLinear(materialParams_depth, uv, 0.0, materialParams.depthParams);
|
||||
highp vec3 origin = computeViewSpacePositionFromDepth(uv, depth);
|
||||
vec3 normal = computeViewSpaceNormal(origin, uv);
|
||||
|
||||
// todo: maybe make this a quality parameter of SSAO
|
||||
#if FILAMENT_QUALITY == FILAMENT_QUALITY_HIGH
|
||||
vec3 normal = computeViewSpaceNormalAccurate(origin, uv);
|
||||
#else
|
||||
vec3 normal = computeViewSpaceNormal(origin, uv);
|
||||
#endif
|
||||
|
||||
float occlusion = 0.0;
|
||||
|
||||
|
||||
@@ -9,15 +9,19 @@ highp float linearizeDepth(highp float depth, highp float depthParams) {
|
||||
return depthParams / max(depth, preventDiv0);
|
||||
}
|
||||
|
||||
highp float sampleDepthLinear(const highp sampler2D depthTexture, const highp vec2 uv, float lod, highp float depthParams) {
|
||||
highp float sampleDepth(const highp sampler2D depthTexture, const highp vec2 uv, float lod) {
|
||||
#if defined(TARGET_METAL_ENVIRONMENT) || defined(TARGET_VULKAN_ENVIRONMENT)
|
||||
// On metal/vulkan, texture space is flipped vertically and we need to adjust the uv
|
||||
// coordinates.
|
||||
return linearizeDepth(textureLod(depthTexture, vec2(uv.x, 1.0 - uv.y), lod).r, depthParams);
|
||||
return textureLod(depthTexture, vec2(uv.x, 1.0 - uv.y), lod).r;
|
||||
#else
|
||||
return linearizeDepth(textureLod(depthTexture, uv, lod).r, depthParams);
|
||||
return textureLod(depthTexture, uv, lod).r;
|
||||
#endif
|
||||
}
|
||||
|
||||
highp float sampleDepthLinear(const highp sampler2D depthTexture, const highp vec2 uv, float lod, highp float depthParams) {
|
||||
return linearizeDepth(sampleDepth(depthTexture, uv, lod), depthParams);
|
||||
}
|
||||
|
||||
#endif // MATERIALS_SSAO_UTILS
|
||||
|
||||
|
||||
@@ -28,13 +28,10 @@ float evaluateSSAO() {
|
||||
|
||||
// Read four AO samples and their depths values
|
||||
#if defined(FILAMENT_HAS_FEATURE_TEXTURE_GATHER)
|
||||
vec4 ao = textureGather(light_ssao, uv, 0); // 01, 11, 10, 00
|
||||
vec4 dg = textureGather(light_ssao, uv, 1); // 01, 11, 10, 00
|
||||
vec4 db = textureGather(light_ssao, uv, 2); // 01, 11, 10, 00
|
||||
vec4 ao = textureGather(light_ssao, uv, 0);
|
||||
vec4 dg = textureGather(light_ssao, uv, 1);
|
||||
vec4 db = textureGather(light_ssao, uv, 2);
|
||||
#else
|
||||
// on mobile we can't use textureGather() because we're limited to ES3.0,
|
||||
// so we emulate it with texelFetch(), on Pixel 4 this doesn't seem to have any
|
||||
// significant impact on performance.
|
||||
vec3 s01 = textureLodOffset(light_ssao, uv, 0.0, ivec2(0, 1)).rgb;
|
||||
vec3 s11 = textureLodOffset(light_ssao, uv, 0.0, ivec2(1, 1)).rgb;
|
||||
vec3 s10 = textureLodOffset(light_ssao, uv, 0.0, ivec2(1, 0)).rgb;
|
||||
|
||||
Reference in New Issue
Block a user