After lot of efforts I have an almost nice shader doing SSR with HiZ. The shader is provided below. Some parameters are tunable and you can speed up things but the difficulty in my scene (picture) are the spheres that limit the coarsiness of the ray marching. So the benefit of HiZ is not as high as expected for this scene but there’s some (130 FPS instead of 110-120, 960x540).
I'm using a HiZ loop working only with increasing Mip level and a second one is used to get finer result as at that point I did not understand fully how the cell boundary calculations work.
Unfortunately there is a last annoying problem I was not able to solve in this SSR HiZ shader. The problem is shown in green on the left picture and on right what I have without HiZ. It is annoying because I did not have this problem with my regular SSR shader whitout HiZ. I have tried a thickness test like in the McGuirre method but it is not working.
e.g : if abs ( ray.z-zbuff)< thickness.
So if someone can help below is my shader. enjoy if you're interested.
The shader is below
//parameter for finer or coarser primary while results
#define offset0 0.005
#define offsetR 2
//my initial resolution (Mip=0)
static const int2 Resolution = {960, 540};
//uv offset1 : critical to ensure correct uv sampling. modulate to see effect
static const float2 offset1 = {1, 1.015};
//parameter for finer or coarser secondary while results
#define offset2 1.15
//parameter for final dicotomic refinement
#define refinemax 3
//parameter for removing vertical artifact for objects not on ground
//based on the normal of the object
#define dot3falloff 0.00005
#define falloff 0.00003
float4 PS_PostDeferredReflex(PS_INPUTQUAD Input) : SV_TARGET
{
float D = txDepth1.SampleLevel(samPoint, Input.Tex, 0).r;
if ( D == 1 ) return float4(0,0,0,0);
float4 ColorOut = txDiffuse1.SampleLevel(samPoint, Input.Tex, 0);
if ( ColorOut.a <0.9) return ColorOut;
float3 PosV = float3(InvProj.x*(Input.Tex.x*2-1),InvProj.y*(1-Input.Tex.y*2), 1)/(InvProj.z*D+1);
if ( txDiffuse1.SampleLevel(samPoint, Input.Tex, 0).a == 0) return ColorOut;
float3 VSDir = normalize(reflect(normalize(PosV.xyz),txNormal1.SampleLevel(samPoint, Input.Tex, 0).rgb*2-1));
if ( VSDir.z < 0 ) return ColorOut;
float4 SSEnd = mul(float4(PosV + VSDir*200, 1), Proj);
SSEnd/= SSEnd.w;
SSEnd.xy = SSEnd.xy*float2(0.5,-0.5)+float2(0.5,0.5);
float3 SSray = float3(Input.Tex, D);
float3 SSDir = normalize(SSEnd.xyz-SSray);
float dSS;
if ( abs(SSDir.x) < abs(SSDir.y) ) dSS = abs(SSDir.y); else dSS = abs(SSDir.x);
SSDir/=dSS;//"normalize" SSDir according to longest x or y
SSDir*=offset0;//modulate step size
int Mip = 0;//you can start at higher Mip level but I don't see improvements
float ZBufferVal=1;
float2 CurResol;
float3 curSSDir = SSDir*pow(2,Mip)*offsetR;//pow useless at Mip=0
//primary while : move ray with Mip-dependant increasing steps
//until ray.z > zbuffer
float rayZmin = 0;
float3 poslast = SSray;
int i=0;
float4 Color ;
while ((Mip<10)&&(i<20))//my resolution corresponds to 10 miplevel
{
i++;
rayZmin = SSray.z;
poslast = SSray;
float2 MipSize = (Resolution>>Mip);
SSray+=curSSDir;
//use Load like below to have better sampling than
//SampleLevel(samPoint,SSray.xy,Mip).r;
ZBufferVal = txDepth1.Load(int3(SSray.xy*MipSize*offset1, Mip)).r;
if ( ZBufferVal==0 ) ZBufferVal=1; //avoid disappearing reflexions at bottomscreen
if (SSray.z > ZBufferVal) break;
if ( Mip < 9 )
{
Mip++;
curSSDir*=2;
}
}
if (poslast.z>=1) return ColorOut;
//secondary while : move ray from last position (z<zbuffer) now only at level Mip = 0
//until ray.z > zbuffer
SSDir=normalize(SSDir)*0.02;
i=0;
SSray = poslast;
while (i<40)
{
i++;
ZBufferVal = txDepth1.SampleLevel(samPoint, SSray.xy, 0).r;
if (SSray.z > ZBufferVal)
{
float3 MinRay = poslast;
float3 MaxRay = SSray;
for(int j = 0; j < refinemax; j++)
{
poslast = (MinRay+MaxRay)*0.5f;
ZBufferVal = txDepth1.SampleLevel(samPoint, poslast.xy, 0).r;
if ( poslast.z > ZBufferVal) MaxRay = poslast; else MinRay = poslast;
}
float3 N = txNormal1.SampleLevel(samPoint, poslast.xy,0).rgb*2-1;
float Dot3 = ( N.x+N.y+N.z>2.99f)?dot3falloff:(dot(-VSDir, N)<0)?0:dot3falloff;
if (abs(poslast.z-ZBufferVal)<Dot3)
{
Color = float4(txDiffuse1.SampleLevel(samPoint, poslast.xy, 0).rgb, 1-abs(poslast.z-D)*500);
return lerp(Color,ColorOut,1-Color.a);
}
return ColorOut;
}
poslast = SSray;
SSray += SSDir;
}
return ColorOut;
}