Stochastic Screen Space Reflections(三):實現與優化
必須在延遲管線下渲染,且在不透明後,半透明前渲染
本文在Xerxes1138的基礎上進行改進
實現
Xerxes1138的實現比Siggraph2015的步驟省略了不少內容
少了Tile分類和Hi-Z Trace
首先逐個pass來看他的實現過程
Recursive Pass
//uv-速度(回到上一幀uv) float2 prevUV = uv - velocity; //上一幀渲染結果 float4 sceneColor = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex,prevUV); return sceneColor;
返回上一幀著色結果,包括上一幀的StoSSR結果,這樣就能模擬出多Bounces的結果,接下來的RayTrace取樣就是用這張RT
RayCast Pass
該Pass返回RayTrace hit到的點的位置為一張RT,RayMask為另一張RT表示沒有反射到物體的情況
此處用的RayTrace型別只有一種,就是RayMarch獲取hit點,這個方法精度是不如Hi-Z的,原文的步驟有一個塊的分類,對重要的部分採用Hi-Z取樣
Hi-Z
關於hierarchical tracing,在GPU Pro5中有詳細介紹,
需要生成一個visible buffer的Mip Chain([Hermanns15])
在Sig15裡面的介紹:
整體來講就是一個先加速後減速的trace過程,這個過程減少了每步都是一小步進行檢測的消耗,結果也比較準確基本和每步一小步結果一樣
MipMapBlur Pass
這一步就是構造一個Mip Chain,來模擬不同粗糙度的反射結果,使用5個Mip級別與Surge中相同
Xerxes1138中橫向Blur一次+縱向Blur一次算一個Mip,相當於10次Pass,此處可以直接用mipmap處理比較省
Resolve Pass
此步驟使用Trace返回的hit點的位置與Mip chain根據粗糙度進行最終顏色處理,生成反射顏色
如果開啟ReUse,那麼就用相鄰點(Xerxes1138中是4個)混合,來模擬Cone Trace
Temporal Pass
該步驟做TAA處理,可以大量降低噪聲
原理就是與前一幀渲染結果(CPU傳入,不是UV算的)做混合,前一陣渲染結果需要過濾,需要clamp在周圍8個取樣點包括當前點一共9個點的明暗範圍之內
//
//pass:temporal(第五步)
//返回:TAA後結果
//與前一幀渲染結果做混合,前一陣渲染結果需要過濾,需要clamp在周圍8個取樣點包括當前點一共9個點的明暗範圍之內
//
void temporal (VaryingsDefault i, out half4 reflection : SV_Target)
{
float2 uv = i.texcoordStereo;
//獲取資訊
//深度/螢幕空間位置/速度/_RayCast?
float depth = GetDepth(/*_CameraDepthTexture,*/ uv);
float3 screenPos = GetScreenPos(uv, depth);
float2 velocity = GetVelocity(uv); // 5.4 motion vector
float2 hitPacked = SAMPLE_TEXTURE2D_LOD(_RayCast, sampler_RayCast, uv,0);// tex2Dlod(_RayCast, float4(uv, 0.0, 0.0));
float2 averageDepthMin = min(hitPacked, velocity);
float2 averageDepthMax = max(hitPacked, velocity);
//velocity = clamp(velocity, averageDepthMin, averageDepthMax);
//獲取上一幀UV
float2 prevUV = uv - velocity;
//當前RT
float4 current =SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex,uv);
//上一幀RT,用上一幀UV取
float4 previous = SAMPLE_TEXTURE2D(_PreviousBuffer, sampler_PreviousBuffer,prevUV);
//一個畫素長寬
float2 du = float2(1.0 / _ScreenSize.x, 0.0);
float2 dv = float2(0.0, 1.0 / _ScreenSize.y);
//一個點周圍8個取樣
float4 currentTopLeft =SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex,uv.xy - dv - du);
float4 currentTopCenter =SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, uv.xy - dv);
float4 currentTopRight = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex,uv.xy - dv + du);
float4 currentMiddleLeft = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex,uv.xy - du);
float4 currentMiddleCenter = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex,uv.xy);
float4 currentMiddleRight = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, uv.xy + du);
float4 currentBottomLeft = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex,uv.xy + dv - du);
float4 currentBottomCenter = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex,uv.xy + dv);
float4 currentBottomRight = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex,uv.xy + dv + du);
//取最暗取樣點
float4 currentMin = min(currentTopLeft, min(currentTopCenter, min(currentTopRight, min(currentMiddleLeft, min(currentMiddleCenter, min(currentMiddleRight, min(currentBottomLeft, min(currentBottomCenter, currentBottomRight))))))));
//取最明取樣點
float4 currentMax = max(currentTopLeft, max(currentTopCenter, max(currentTopRight, max(currentMiddleLeft, max(currentMiddleCenter, max(currentMiddleRight, max(currentBottomLeft, max(currentBottomCenter, currentBottomRight))))))));
float scale = _TScale;
//平均混合最明和最暗
float4 center = (currentMin + currentMax) * 0.5f;
//縮放明暗差
currentMin = (currentMin - center) * scale + center;
currentMax = (currentMax - center) * scale + center;
//將上一幀Buffer clamp到 當前取樣點 min max範圍內
previous = clamp(previous, currentMin, currentMax);
//混合當前RT和移動前RT顏色,/velocity移動距離(速度)越大,約接近當前RT值/velocity移動距離(速度)越小,約接近移動前RT值
reflection = lerp(current, previous, saturate(_TResponse * (1 - length(velocity) * 8)) );
}
Combine Pass
混合場景顏色和反射顏色
根據mask混合_CameraReflectionsTexture和反射計算結果的值 再加上 (場景顏色-_CameraReflectionsTexture)
float4 sceneColor = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex,uv);//tex2D(_MainTex, uv);
//場景色-cubeMap顏色
sceneColor.rgb = max(1e-5, sceneColor.rgb - cubemap.rgb);
//最終結果,混合反射結果和cubemap值
sceneColor.rgb += lerp(cubemap.rgb, reflection.rgb, mask);
此處的場景顏色為當前幀渲染source
問題
射線ReUse產生Artifact
此處可以加個判斷,如果鄰居點與當前點法線角度差太多就不混合結果。因為如果是粗糙表面,cone trace也有一個角度範圍限制的,模擬一個面的反射,不會角度相差很多。
但是如果相鄰點在角度差別不大的兩個物體,依然會有artifact產生
參考:
1.[Hermanns15] Lukas Hermanns "Screen space cone tracing for glossy reflections"
http://publica.fraunhofer.de/documents/N-336466.html
----- by wolf96 https://blog.csdn.net/wolf96