1. 程式人生 > >Stochastic Screen Space Reflections(三):實現與優化

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