如何解决修复屏幕空间反射中的伪影
我正在尝试实现 SSR(屏幕空间反射)。我设法获得了基本效果,但您可以从下面的图像和视频中看到一些伪影。首先我想解决这些视觉问题,然后如果可能的话,我想尝试提高算法的性能。
SSR 工件:https://youtu.be/LFBAJHa_mFM
我的 SSR 实现基于此 tutorial。
您可以在下面找到生成反射贴图(或反射 UV 贴图)的像素着色器的代码,在这里您可以找到 full implementation。如您所见,除了少量更改外,它与教程 (screen-space-reflection.frag) 的代码实际上相同:
- 我不将每个像素的 3D 位置存储在离屏纹理中,而是根据函数
GetFullViewPosition
中的视图空间深度重建 3D 位置。 - 当我将片段 NDC 转换为纹理坐标时,我乘以
float2(+0.5f,-0.5f)
而不是float2(+0.5f,+0.5f)
。 - 我添加了一个检查,如果当前位置超出屏幕空间,则会停止光线追踪。
SSRReflectionsMapComputePS.hlsl
cbuffer ConstantBuffer : register(b0)
{
float4 gFrustumFarCorner[4];
float4x4 gProj;
};
struct VertexOut
{
float4 PositionH : SV_POSITION;
float3 ToFarPlane : TEXCOORD0;
float2 TexCoord : TEXCOORD1;
};
Texture2D gnormalDepthMap : register(t0);
SamplerState gnormalDepthSamplerState : register(s2);
float3 GetFullViewPosition(float2 uv,float z)
{
// bilinear interpolation
float4 p0 = lerp(gFrustumFarCorner[0],gFrustumFarCorner[3],uv.x);
float4 p1 = lerp(gFrustumFarCorner[1],gFrustumFarCorner[2],uv.x);
float3 ToFarPlane = lerp(p0.xyz,p1.xyz,1 - uv.y);
// reconstruct full view space position (x,y,z)
// find t such that p = t*pin.tofarplane
// p.z = t*pin.tofarplane.z ==> t = p.z / pin.tofarplane.z
return (z / ToFarPlane.z) * ToFarPlane;
}
float3 GetFullViewPosition(float2 uv)
{
float4 normalDepth = gnormalDepthMap.SampleLevel(gnormalDepthSamplerState,uv,0);
return GetFullViewPosition(uv,normalDepth.w);
}
// https://lettier.github.io/3d-game-shaders-for-beginners/screen-space-reflection.html
// https://github.com/lettier/3d-game-shaders-for-beginners/blob/master/demonstration/shaders/fragment/screen-space-reflection.frag
float4 main(VertexOut pin) : sv_target
{
// view space normal and depth (z-coord) of this pixel
float4 normaldepth = gnormalDepthMap.SampleLevel(gnormalDepthSamplerState,pin.TexCoord,0);
float3 n = normaldepth.xyz;
float pz = normaldepth.w;
//float3 p = (pz / pin.tofarplane.z) * pin.tofarplane;
float3 p = GetFullViewPosition(pin.TexCoord,pz);
float maxdistance = 100;
float resolution = 1;
int steps = 10;
float thickness = 0.5f;
float2 texsize;
gnormalDepthMap.GetDimensions(texsize.x,texsize.y);
float2 texcoord = pin.PositionH.xy / texsize;
float3 positionfrom = p;
float3 positionfromunit = normalize(positionfrom);
float3 normal = normalize(n);
float3 pivot = normalize(reflect(positionfromunit,normal));
float3 positionto = positionfrom;
float4 uv = 0;
float3 viewstart = positionfrom + pivot * 0;
float3 viewend = positionfrom + pivot * maxdistance;
float4 fragstart = float4(viewstart,1);
fragstart = mul(gProj,fragstart);
fragstart.xy /= fragstart.w;
fragstart.xy = fragstart.xy * float2(+0.5f,-0.5f) + 0.5f;
fragstart.xy *= texsize;
float4 fragend = float4(viewend,1);
fragend = mul(gProj,fragend);
fragend.xy /= fragend.w;
fragend.xy = fragend.xy * float2(+0.5f,-0.5f) + 0.5f;
fragend.xy *= texsize;
float2 frag = fragstart.xy;
uv.xy = frag / texsize;
float deltax = fragend.x - fragstart.x;
float deltay = fragend.y - fragstart.y;
float usex = abs(deltax) >= abs(deltay) ? 1 : 0;
float delta = lerp(abs(deltay),abs(deltax),usex) * clamp(resolution,1);
float2 increment = float2(deltax,deltay) / max(delta,0.001f);
float search0 = 0;
float search1 = 0;
int hit0 = 0;
int hit1 = 0;
float viewdistance = viewstart.z;
float depth = thickness;
for (int i = 0; i < int(delta); ++i)
{
frag += increment;
uv.xy = frag / texsize;
// do not sample outside the screen space
if (any(uv.xy < float2(0,0)) || any(uv.xy > float2(1,1))) break;
positionto = GetFullViewPosition(uv.xy);
search1 = lerp((frag.y - fragstart.y) / deltay,(frag.x - fragstart.x) / deltax,usex);
search1 = clamp(search1,1);
viewdistance = (viewstart.z * viewend.z) / lerp(viewend.z,viewstart.z,search1);
depth = viewdistance - positionto.z;
if (depth > 0 && depth < thickness)
{
hit0 = 1;
break;
}
else
{
search0 = search1;
}
}
search1 = search0 + ((search1 - search0) / 2);
steps *= hit0;
for (int i = 0; i < steps; ++i)
{
frag = lerp(fragstart.xy,fragend.xy,search1);
uv.xy = frag / texsize;
// do not sample outside the screen space
if (any(uv.xy < float2(0,1))) break;
positionto = GetFullViewPosition(uv.xy);
viewdistance = (viewstart.z * viewend.z) / lerp(viewend.z,search1);
depth = viewdistance - positionto.z;
if (depth > 0 && depth < thickness)
{
hit1 = 1;
search1 = search0 + ((search1 - search0) / 2);
}
else
{
float temp = search1;
search1 = search1 + ((search1 - search0) / 2);
search0 = temp;
}
}
float visibility = hit1 *
(1 - max(dot(-positionfromunit,pivot),0)) *
(1 - clamp(depth / thickness,1)) *
(1 - clamp(length(positionto - positionfrom) / maxdistance,1)) *
(uv.x < 0 || uv.x > 1 ? 0 : 1) *
(uv.y < 0 || uv.y > 1 ? 0 : 1);
return float4(uv.xy,saturate(visibility));
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。