I've transposed from OpenGL to DX11 a SSR ray marching shader (code found here : https://community.khronos.org/t/screen-space-reflections/69987). It seems to work well but I have had an initial problem of final scale for the mirrored stuff (see picture left). The first shader used is below.
(NOTE: i'm reconstructing at the moment the position from the depthmap (txPosition) which is slowing down a lot and I calculate on the fly the view normal as being camera position - pixel world position (InvLightProj.xyz - dPL.xyz in PS_PostDeferredReflex) . Also the mirrored stuff is just the albedo (txDiffuse) for now):
static const float rayStep = 0.25f;
static const float minRayStep = 0.1f;
static const int maxSteps = 5;
static const float searchDist = 5.0f;
static const float searchDistInv = 0.2f;
static const int numBinarySearchSteps = 5;
static const float maxDDepth = 1.0f;
static const float maxDDepthInv = 1.0f;
float3 BinarySearch(float3 dir, inout float3 hitCoord, out float dDepth)
{
float depth;
float4 projectedCoord;
for(int i = 0; i < 3; i++)
{
projectedCoord = mul(float4(hitCoord, 1.0), ViewProj);//use the projection matrix
projectedCoord.xy /= projectedCoord.w;
projectedCoord.xy = projectedCoord.xy * 0.5 + 0.5;
float D = txPosition.Sample(samPoint, projectedCoord.xy).r; if ( D == 1 ) return float3(0,0,0);
float4 dPL = float4(projectedCoord.x*2-1, (1-projectedCoord.y)*2-1, D, 1);
dPL.xyz = float3(InvProj.x*dPL.x,InvProj.y*dPL.y, 1)/(InvProj.z*dPL.z+1);
dPL = mul(dPL, InvView);depth = dPL.z;
dDepth = hitCoord.z - depth;
hitCoord += (dDepth > 0.0)?dir:0;
dir *= 0.5;
hitCoord -= dir;
}
projectedCoord = mul(float4(hitCoord, 1.0),ViewProj);
projectedCoord.xy /= projectedCoord.w;
projectedCoord.xy = projectedCoord.xy * 0.5 + 0.5;
return float3(projectedCoord.xy, depth);
}
static const float reflectionSpecularFalloffExponent = 3.0;
float4 RayCast(float3 dir, inout float3 hitCoord, out float dDepth)
{
dir *= rayStep;
float depth;float4 projectedCoord;
float4 Ray = float4(0.0f, 0.0f, 0.0f, 0.0f);
for(int i = 0; i < maxSteps; i++)
{
hitCoord += dir;
projectedCoord = mul(float4(hitCoord, 1.0),ViewProj);
projectedCoord.xy /= projectedCoord.w;
projectedCoord.xy = projectedCoord.xy * 0.5 + 0.5;
float D = txPosition.Sample(samPoint, projectedCoord.xy).r; if ( D == 1 ) return float4(0,0,0,0);;
float4 dPL = float4(projectedCoord.x*2-1, (1-projectedCoord.y)*2-1, D, 1);
dPL.xyz = float3(InvProj.x*dPL.x,InvProj.y*dPL.y, 1)/(InvProj.z*dPL.z+1);
dPL = mul(dPL, InvView);depth = dPL.z;
dDepth = hitCoord.z - depth;
Ray = float4(BinarySearch(dir, hitCoord, dDepth), 1.0);
if(dDepth < 0.0) return Ray;
}
return Ray;
}
float4 PS_PostDeferredReflex(PS_INPUTQUAD Input) : SV_TARGET
{
float3 specular = txDiffuse.Sample(samPoint, Input.Tex).rgb;
if(specular.r+specular.g+specular.b == 0.0) return float4(0.0, 0.0, 0.0, 0.0);
float D = txPosition.Sample(samPoint, Input.Tex).r; if ( D == 1 ) return float4(0,0,0,0);
float4 dPL = float4(Input.Tex.x*2-1, (1-Input.Tex.y)*2-1, D, 1);
dPL.xyz = float3(InvProj.x*dPL.x,InvProj.y*dPL.y, 1)/(InvProj.z*dPL.z+1);
dPL = mul(dPL, InvView);
if ( dPL.y > 1 ) return float4(0,0,0,0);
float3 viewPos = InvLightProj.xyz;
float3 viewNormal = (InvLightProj.xyz-dPL.xyz);
// Reflection vector
float3 reflected = normalize(reflect(normalize(viewPos), normalize(viewNormal)));
// Ray cast
float3 hitPos = viewPos;
float dDepth;
float4 coords = RayCast(reflected * max(minRayStep, -viewPos.z), hitPos, dDepth);
float2 dCoords = abs(float2(0.5, 0.5) - coords.xy);
float screenEdgefactor = clamp(1.0 - (dCoords.x + dCoords.y), 0.0, 1.0);
// Get color
float3 Color = txDiffuse.Sample(samPoint, coords.xy).rgb;
float Spec = 1;//pow(specular, reflectionSpecularFalloffExponent);
float EFactor = screenEdgefactor * clamp(-reflected.z, 0.0, 1.0);
float Search = clamp((searchDist - length(viewPos - hitPos)) * searchDistInv, 0.0, 1.0) * coords.w;
return float4(Color, Spec*EFactor*Search);
}
new code for my mirror shader
static const float UVInc = 0.015f;
static const float UVIncL = UVInc*0.45f;
float4 PS_PostDeferredReflex(PS_INPUTQUAD Input) : SV_TARGET
{
float D = txPosition.Load(int3(int(Input.Tex.x*ScreenX), int(Input.Tex.y*ScreenY),0)).r;
if ( D == 1 ) return float4(0,0,0,0);
float2 TexProj = float2(Input.Tex.x*2-1,1-2*Input.Tex.y);
float4 PosVRef = float4(TexProj, D, 1);
PosVRef.xyz = float3(InvProj.x*PosVRef.x,InvProj.y*PosVRef.y, 1)/(InvProj.z*PosVRef.z+1);
float4 PosWRef = mul(PosVRef, InvView);
if ( PosWRef.y > 1 ) return float4(0,0,0,0);
float2 TexHit = Input.Tex;
float2 Tex;
float hit = 0;
float2 TexProjCur = TexProj;
TexProj = Input.Tex;
float A = 0.5f;
for (int i = 0; i < 150; i++)
{
TexProjCur.y+=UVInc;
if ((TexProjCur.y < -1) || (TexProjCur.y > 1)) break;
Tex = mad(TexProjCur, float2(0.5f, -0.5f), 0.5f);
float D = txPosition.Load(int3(int(Tex.x*ScreenX), int(Tex.y*ScreenY),0)).r;
if ( D < 1 )
{
float4 PosV = float4(TexProjCur, D, 1);
PosV.xyz = float3(InvProj.x*PosV.x,InvProj.y*PosV.y, 1)/(InvProj.z*PosV.z+1);
float4 PosWorldPix = mul(PosV, InvView);
if ( PosWorldPix.y > 0 )
{
float4 MirrorPix = mul(PosWorldPix, Reflex_View_World);
{
MirrorPix/=MirrorPix.w;
MirrorPix.xy = mad(MirrorPix.xy, float2(0.5f, -0.5f), 0.5f);
MirrorPix.y-=0.011f;//correction for PosWorldPix.y = 0 alignment default
if (abs(MirrorPix.y - TexProj.y) <= UVIncL)
{
hit = 1;
TexHit = Tex;
// A = 0.5f-clamp(PosWorldPix.y/100, 0, 1);//activate to fade with height
break;
}
}
}
}
}
if ( hit < 1 ) return float4(0,0,0,0);
float3 Color = txDiffuse.Load(int3(int(TexHit.x*ScreenX), int(TexHit.y*ScreenY),0)).rgb;
return float4(Color,A);
}