diff --git a/WickedEngine/depthoffield_mainCS.hlsl b/WickedEngine/depthoffield_mainCS.hlsl index f30a4c658..c1f495c53 100644 --- a/WickedEngine/depthoffield_mainCS.hlsl +++ b/WickedEngine/depthoffield_mainCS.hlsl @@ -20,7 +20,7 @@ void main(uint3 DTid : SV_DispatchThreadID) const float spreadScale = ringCount / maxcoc; const float2 ringScale = float(ringCount) / float(DOF_RING_COUNT) * maxcoc * xPPResolution_rcp; - const float3 center_color = texture_prefilter[DTid.xy]; + const float3 center_color = max(0, texture_prefilter[DTid.xy]); const float3 center_presort = texture_presort[DTid.xy]; const float center_coc = center_presort.r; const float center_backgroundWeight = center_presort.g; @@ -28,6 +28,8 @@ void main(uint3 DTid : SV_DispatchThreadID) const float2 uv = (DTid.xy + 0.5f) * xPPResolution_rcp; + float seed = 12345; + float4 background = center_backgroundWeight * float4(center_color.rgb, 1); float4 foreground = center_foregroundWeight * float4(center_color.rgb, 1); for (uint j = 0; j < ringCount; ++j) @@ -35,8 +37,8 @@ void main(uint3 DTid : SV_DispatchThreadID) for (uint i = ringSampleCount[j]; i < ringSampleCount[j + 1]; ++i) { const float offsetCoc = disc[i].z; - const float2 uv2 = uv + ringScale * disc[i].xy; - const float4 color = float4(texture_prefilter.SampleLevel(sampler_point_clamp, uv2, 0), 1); + const float2 uv2 = uv + ringScale * disc[i].xy * (1 + rand(seed, uv) * 0.15); + const float4 color = float4(max(0, texture_prefilter.SampleLevel(sampler_point_clamp, uv2, 0)), 1); const float3 presort = texture_presort.SampleLevel(sampler_point_clamp, uv2, 0).rgb; const float coc = presort.r; const float spreadCmp = SpreadCmp(offsetCoc, coc, spreadScale); diff --git a/WickedEngine/depthoffield_postfilterCS.hlsl b/WickedEngine/depthoffield_postfilterCS.hlsl index df46ec8a7..c99317e73 100644 --- a/WickedEngine/depthoffield_postfilterCS.hlsl +++ b/WickedEngine/depthoffield_postfilterCS.hlsl @@ -5,10 +5,120 @@ TEXTURE2D(texture_main, float3, TEXSLOT_ONDEMAND0); RWTEXTURE2D(output_postfilter, float3, 0); +float min3(float a, float b, float c) +{ + return min(min(a, b), c); +} + +float max3(float a, float b, float c) +{ + return max(max(a, b), c); +} + +float med3(float a, float b, float c) +{ + return max(min(a, b), min(max(a, b), c)); +} + +float2 min3(float2 a, float2 b, float2 c) +{ + return float2(min3(a.x, b.x, c.x), min3(a.y, b.y, c.y)); +} + +float3 min3(float3 a, float3 b, float3 c) +{ + return float3(min3(a.x, b.x, c.x), min3(a.y, b.y, c.y), min3(a.z, b.z, c.z)); +} + +float4 min3(float4 a, float4 b, float4 c) +{ + return float4(min3(a.x, b.x, c.x), min3(a.y, b.y, c.y), min3(a.z, b.z, c.z), min3(a.w, b.w, c.w)); +} + +float2 max3(float2 a, float2 b, float2 c) +{ + return float2(max3(a.x, b.x, c.x), max3(a.y, b.y, c.y)); +} + +float3 max3(float3 a, float3 b, float3 c) +{ + return float3(max3(a.x, b.x, c.x), max3(a.y, b.y, c.y), max3(a.z, b.z, c.z)); +} + +float4 max3(float4 a, float4 b, float4 c) +{ + return float4(max3(a.x, b.x, c.x), max3(a.y, b.y, c.y), max3(a.z, b.z, c.z), max3(a.w, b.w, c.w)); +} + +float2 med3(float2 a, float2 b, float2 c) +{ + return float2(med3(a.x, b.x, c.x), med3(a.y, b.y, c.y)); +} + +float3 med3(float3 a, float3 b, float3 c) +{ + return float3(med3(a.x, b.x, c.x), med3(a.y, b.y, c.y), med3(a.z, b.z, c.z)); +} + +float4 med3(float4 a, float4 b, float4 c) +{ + return float4(med3(a.x, b.x, c.x), med3(a.y, b.y, c.y), med3(a.z, b.z, c.z), med3(a.w, b.w, c.w)); +} + +float min4(float4 values) +{ + return min(min3(values.x, values.y, values.z), values.w); +} + +float max4(float4 values) +{ + return max(max3(values.x, values.y, values.z), values.w); +} + +static const float2 squareOffsets[] = +{ + { -1.0, -1.0 }, + { 0.0, -1.0 }, + { 1.0, -1.0 }, + { -1.0, 0.0 }, + { 0.0, 0.0 }, + { 1.0, 0.0 }, + { -1.0, 1.0 }, + { 0.0, 1.0 }, + { 1.0, 1.0 }, +}; + +static const float2 circleOffsets[] = +{ + { 0.7071, -0.7071 }, + { -0.7071, 0.7071 }, + { -1.0000, 0.0000 }, + { 1.0000, 0.0000 }, + { 0.0000, 0.0000 }, + { -0.7071, -0.7071 }, + { 0.7071, 0.7071 }, + { -0.0000, -1.0000 }, + { 0.0000, 1.0000 }, +}; + +void sort3(in out float3 p1, in out float3 p2, in out float3 p3) +{ + float3 minValue = min3(p1, p2, p3); + float3 medValue = med3(p1, p2, p3); + float3 maxValue = max3(p1, p2, p3); + + p1 = minValue; + p2 = medValue; + p3 = maxValue; +} + [numthreads(POSTPROCESS_BLOCKSIZE, POSTPROCESS_BLOCKSIZE, 1)] void main(uint3 DTid : SV_DispatchThreadID) { float3 color = 0; + +#if 0 // simple average + color += texture_main[DTid.xy + int2(-1, -1)]; color += texture_main[DTid.xy + int2(0, -1)]; color += texture_main[DTid.xy + int2(1, -1)]; @@ -20,6 +130,39 @@ void main(uint3 DTid : SV_DispatchThreadID) color += texture_main[DTid.xy + int2(1, 1)]; color /= 9.0f; +#else // median + + // See [Smith1996] Implementing median filters in XC4000E FPGAs + + const float2 uv = DTid.xy + 0.5f; + + float3 p[9]; + + p[0] = texture_main.SampleLevel(sampler_linear_clamp, (uv + circleOffsets[0]) * xPPResolution_rcp, 0); + p[1] = texture_main.SampleLevel(sampler_linear_clamp, (uv + circleOffsets[1]) * xPPResolution_rcp, 0); + p[2] = texture_main.SampleLevel(sampler_linear_clamp, (uv + circleOffsets[2]) * xPPResolution_rcp, 0); + sort3(p[0], p[1], p[2]); + + p[3] = texture_main.SampleLevel(sampler_linear_clamp, (uv + circleOffsets[3]) * xPPResolution_rcp, 0); + p[4] = texture_main.SampleLevel(sampler_linear_clamp, (uv + circleOffsets[4]) * xPPResolution_rcp, 0); + p[5] = texture_main.SampleLevel(sampler_linear_clamp, (uv + circleOffsets[5]) * xPPResolution_rcp, 0); + sort3(p[3], p[4], p[5]); + + p[6] = texture_main.SampleLevel(sampler_linear_clamp, (uv + circleOffsets[6]) * xPPResolution_rcp, 0); + p[7] = texture_main.SampleLevel(sampler_linear_clamp, (uv + circleOffsets[7]) * xPPResolution_rcp, 0); + p[8] = texture_main.SampleLevel(sampler_linear_clamp, (uv + circleOffsets[8]) * xPPResolution_rcp, 0); + sort3(p[6], p[7], p[8]); + + p[6] = max3(p[0], p[3], p[6]); + p[2] = min3(p[2], p[5], p[8]); + + sort3(p[1], p[4], p[7]); + sort3(p[2], p[4], p[6]); + + color = p[4]; + +#endif + output_postfilter[DTid.xy] = color; //output_postfilter[DTid.xy] = texture_main[DTid.xy]; } \ No newline at end of file diff --git a/WickedEngine/depthoffield_prepassCS.hlsl b/WickedEngine/depthoffield_prepassCS.hlsl index 9d701b552..bae073018 100644 --- a/WickedEngine/depthoffield_prepassCS.hlsl +++ b/WickedEngine/depthoffield_prepassCS.hlsl @@ -25,6 +25,7 @@ void main(uint3 DTid : SV_DispatchThreadID) output_presort[DTid.xy] = float3(coc, alpha * depthcmp.x, alpha * depthcmp.y); + float seed = 54321; const float2 ringScale = 2 * coc * xPPResolution_rcp; const float3 center_color = input.SampleLevel(sampler_point_clamp, uv, 0).rgb; @@ -32,7 +33,7 @@ void main(uint3 DTid : SV_DispatchThreadID) for (uint i = ringSampleCount[0]; i < ringSampleCount[1]; ++i) { const float offsetCoc = disc[i].z; - const float2 uv2 = uv + ringScale * disc[i].xy; + const float2 uv2 = uv + ringScale * disc[i].xy * (1 + rand(seed, uv) * 0.1); const float depth = texture_lineardepth.SampleLevel(sampler_linear_clamp, uv2, 0); const float3 color = input.SampleLevel(sampler_point_clamp, uv2, 0).rgb; const float weight = saturate(abs(depth - center_depth) * g_xCamera_ZFarP * 2); diff --git a/WickedEngine/depthoffield_upsampleCS.hlsl b/WickedEngine/depthoffield_upsampleCS.hlsl index 064606991..ba28b1add 100644 --- a/WickedEngine/depthoffield_upsampleCS.hlsl +++ b/WickedEngine/depthoffield_upsampleCS.hlsl @@ -15,15 +15,19 @@ void main(uint3 DTid : SV_DispatchThreadID) const float2 uv = (DTid.xy + 0.5f) * xPPResolution_rcp; const float center_depth = texture_lineardepth[DTid.xy]; - const float maxcoc = neighborhood_mindepth_maxcoc[DTid.xy / DEPTHOFFIELD_TILESIZE].y; + const float2 mindepth_maxcoc = neighborhood_mindepth_maxcoc[DTid.xy / DEPTHOFFIELD_TILESIZE]; + const float mindepth = mindepth_maxcoc.x; + const float maxcoc = mindepth_maxcoc.y; float4 fullres = input[DTid.xy]; const float3 halfres = texture_postfilter.SampleLevel(sampler_linear_clamp, uv, 0); const float alpha = texture_alpha.SampleLevel(sampler_linear_clamp, uv, 0); const float coc = dof_scale * abs(1 - dof_focus / (center_depth * g_xCamera_ZFarP)); + float depthDelta = saturate(1.0 - g_xCamera_ZFarP * 0.2 * (center_depth - mindepth)); + const float backgroundFactor = coc; - const float foregroundFactor = maxcoc; + const float foregroundFactor = lerp(maxcoc, coc, pow(depthDelta, 1.0f / 2.2f)); const float combinedFactor = saturate(lerp(backgroundFactor, foregroundFactor, alpha)); diff --git a/WickedEngine/wiVersion.cpp b/WickedEngine/wiVersion.cpp index dc09e68f4..0944eda7e 100644 --- a/WickedEngine/wiVersion.cpp +++ b/WickedEngine/wiVersion.cpp @@ -9,7 +9,7 @@ namespace wiVersion // minor features, major updates const int minor = 36; // minor bug fixes, alterations, refactors, updates - const int revision = 30; + const int revision = 31; long GetVersion()