GraphicsLab Project 之 Screen Space Planar Reflection
2020-06-28 22:30
585 查看
uint2 SrcPosPixel = uint2(DepthPos.x, DepthPos.y); uint2 ReflPosPixel = ReflPosUV * uint2(ReflectWidth, ReflectHeight); int Hash = SrcPosPixel.y << 16 | SrcPosPixel.x; int dotCare = 0; InterlockedMin(HashResult[ReflPosPixel], Hash, dotCare);Encode and Sort
孔洞
根据先前算法的描述,我们知道,我们先要根据 Depth 信息和 Screen Position 信息计算出 World Positon,然后镜像之后,在转化为新的屏幕坐标。在这一系列操作中,由于数值计算的不精确性,导致有些地方没有存储到有效的反射点位置信息,从而导致最终显示时画面上有孔洞的情况,如下图所示:
uint Hash = HashTexture[id.xy].x; if (Hash == 0x0FFFFFFF) Hash = HashTexture[uint2(id.x, id.y + 1)].x; if (Hash == 0x0FFFFFFF) Hash = HashTexture[uint2(id.x, id.y - 1)].x; if (Hash == 0x0FFFFFFF) Hash = HashTexture[uint2(id.x + 1, id.y)].x; if (Hash == 0x0FFFFFFF) Hash = HashTexture[uint2(id.x - 1, id.y)].x; if (Hash != 0x0FFFFFFF) { uint x = Hash & 0xFFFF; uint y = Hash >> 16; ReflectionTexture[id.xy] = ColorTexture[uint2(x, y)]; } else { ReflectionTexture[id.xy] = float4(0.0f, 0.0f, 0.0f, 0.0f); }Hole 如下是修正孔洞之后的效果:
// Each #kernel tells which function to compile; you can have many kernels #pragma enable_d3d11_debug_symbols #pragma kernel SSPRClear_Main #pragma kernel SSPRHash_Main #pragma kernel SSPRResolve_Main //----------------------------------------------------------------- float4x4 VPMatrix; float4x4 InvVPMatrix; uint Width; uint Height; uint ReflectWidth; uint ReflectHeight; //-------------------------------------------------------------------- RWTexture2D<int> ClearHashTexture; [numthreads(8, 8, 1)] void SSPRClear_Main(uint3 id : SV_DispatchThreadID) { if (id.x < ReflectWidth && id.y < ReflectHeight) { ClearHashTexture[id.xy] = 0x0FFFFFFF; } } //--------------------------------------------------------------- Texture2D<float> DepthTex; RWTexture2D<int> HashResult; #define DownSampleFactor (1) float3 Unproject(float3 clip) { float4 clipW = float4(clip, 1.0f); clipW = mul(InvVPMatrix, clipW); clipW.xyz = clipW.xyz / clipW.w; return clipW.xyz; } float2 Project(float3 world) { float4 worldW = float4(world, 1.0f); worldW = mul(VPMatrix, worldW); worldW.xy = worldW.xy / worldW.w; worldW.xy = (worldW.xy + float2(1.0f, 1.0f)) / 2.0f; return worldW.xy; } [numthreads(8, 8, 1)] void SSPRHash_Main(uint3 id : SV_DispatchThreadID) { for (uint i = 0; i < DownSampleFactor; i++) { for (uint j = 0; j < DownSampleFactor; j++) { uint2 DepthPos = uint2(id.x * DownSampleFactor + i, id.y * DownSampleFactor + j); if (DepthPos.x < Width && DepthPos.y < Height) { float depth = DepthTex.Load(int3(DepthPos.x, DepthPos.y, 0)).x; if (depth > 0.0f) { float2 uv = (DepthPos.xy * 1.0f) / float2(Width, Height); uv = uv * 2.0f - float2(1.0f, 1.0f); uv.y = -uv.y; float3 PosWS = Unproject(float3(uv, depth)); if (PosWS.y > 0.0f) { float3 ReflPosWS = float3(PosWS.x, -PosWS.y, PosWS.z); float2 ReflPosUV = Project(ReflPosWS); uint2 SrcPosPixel = uint2(DepthPos.x, DepthPos.y); uint2 ReflPosPixel = ReflPosUV * uint2(ReflectWidth, ReflectHeight); int Hash = SrcPosPixel.y << 16 | SrcPosPixel.x; int dotCare = 0; InterlockedMin(HashResult[ReflPosPixel], Hash, dotCare); } } } } } } //------------------------------------------------------------------------------ Texture2D<int> HashTexture; Texture2D<float4> ColorTexture; RWTexture2D<float4> ReflectionTexture; [numthreads(8, 8, 1)] void SSPRResolve_Main(uint3 id : SV_DispatchThreadID) { if (id.x < ReflectWidth && id.y < ReflectHeight) { uint Hash = HashTexture[id.xy].x; if (Hash == 0x0FFFFFFF) Hash = HashTexture[uint2(id.x, id.y + 1)].x; if (Hash == 0x0FFFFFFF) Hash = HashTexture[uint2(id.x, id.y - 1)].x; if (Hash == 0x0FFFFFFF) Hash = HashTexture[uint2(id.x + 1, id.y)].x; if (Hash == 0x0FFFFFFF) Hash = HashTexture[uint2(id.x - 1, id.y)].x; if (Hash != 0x0FFFFFFF) { uint x = Hash & 0xFFFF; uint y = Hash >> 16; ReflectionTexture[id.xy] = ColorTexture[uint2(x, y)]; } else { ReflectionTexture[id.xy] = float4(0.0f, 0.0f, 0.0f, 0.0f); } } }ScreenSpacePlanarReflection
结论
本文只是探索这个方法的可能性,更加复杂的实现,更加高效的优化可以参考文献[4][5],这也是本文主要参考的对象。相比于传统的绘制场景两边的方法来说,这个方案的性能更加高效,同时也没有 SSR 那样的高需求。在条件满足的情况下,使用该方案能够带来显著的效果提升,推荐可以尝试。
完整代码在这里:https://github.com/idovelemon/UnityProj/tree/master/ScreenSpacePlanarReflection
参考文献
[4] Screen Space Planar Reflection
[5] Optimized Pixel Projected Reflections for Planar Reflectors
相关文章推荐
- GraphicsLab Project之Screen Space Ambient Occlusion(SSAO)
- Screen Space Reflection
- Screen Space Reflection 学习笔记
- 高级屏幕空间反射: Screen Space Reflection (SSR)
- GraphicsLab Project 之 Curl Noise
- GraphicsLab Project之辉光(Glare,Glow)效果
- 魔兽世界的Screen Space Local Reflection
- GraphicsLab Project学习项目
- GraphicsLab Project之Parallel Split Shadow Map(PSSM)
- GraphicsLab Project之Normal Mapping
- 高级屏幕空间反射: Screen Space Reflection (SSSR)
- Screen Space Reflection 2
- 在Unity中实现屏幕空间反射Screen Space Reflection(1)
- 在Unity中实现屏幕空间反射Screen Space Reflection(4)
- GraphicsLab Project之HDR渲染
- 在Unity中实现屏幕空间反射Screen Space Reflection(2)
- 在Unity中实现屏幕空间反射Screen Space Reflection(3)
- Screen Space Reflections in Unity 5
- 【Space Shoot Project】Shooting shots
- Mathematics for 3D Game Programming and Computer Graphics - Planes in 3D Space