一天干掉一只Monkey计划(二)——热流扰动,径向模糊
一天干掉一只Monkey計劃(二)——熱流擾動,徑向模糊
懶病又犯了,很多事情,你自以為囫圇吞棗,會了,可其實你不會,但亦有很多事情,你害怕你不會,但其實不妨來個囫圇吞棗先!戒貪戒急,戒驕戒躁,多謝多想多練,得時常打開RM和Word壓壓自己,
好吧,繼續(xù)上篇所講,由于前人已有鋪路,我就偷懶了,僅作實現(xiàn),本篇內(nèi)容同樣轉自逍遙劍客的Blog:
1, 熱流擾動 柏松分布
? 每個人都對自然界中的這種大氣效果很熟悉
? 光線在穿過不同密度的介質(zhì)時會彎曲
熱微光
? 熱空氣密度比冷空氣小
? 密度影響介質(zhì)的折射率
? 熱空氣上升的同時會被冷空氣替代, 這會改變光射入眼睛的路線
折射率的部分改變會導致我們看到的景物發(fā)生扭曲,具體可以參照一下實現(xiàn):
? 渲染場景到RGBA離屏緩存(可渲染的紋理)
? 顏色寫入RGB值
? 扭曲度寫入Alpha通道(這里只是RM下單一渲染效果的QuickTrick,實際中可以使用StencilBuffer來做標記)
? 繪制全屏長方形到后備緩沖區(qū)
? 對離屏緩沖采樣以獲得扭曲度
? 用擾動貼圖來確定擾動向量, 用扭曲度放縮后偏移原始紋理坐標
? 基于擾動紋理坐標的可增長泊松分布(根據(jù)扭曲度來進行偏移)
扭曲度
? 逐像素判斷當前像素被扭曲的程度
? 當光線穿過更多的氣體時, 折射程度也相應增加
? 扭曲隨場景深度增加
– 開始時把渲染目標的Alpha通道清為1.0,表示最大深度
– Pixel shader把每個像素的深度寫入alpha通道
? 深度提供了一個很好的全局扭曲方案, 但是你的美工們希望局部控制
? 熱浪幾何體可以用來定義扭曲范圍, 如熱空氣出口和噴氣發(fā)動機尾
? 熱浪紋理可以使熱浪幾何本上的扭曲動起來
熱度幾何體 & 熱度紋理
? 像素扭曲度來源來熱度紋理
? 扭曲度被深度放大
? 用高度進一步放大 (紋理坐標) 并且 N.V 來避免生硬的邊緣
? 扭曲度被寫入Alpha通道
全屏矩形
? 全屏矩形用離屏緩存(可渲染的紋理)來繪制并且用擾動貼圖作為紋理
擾動貼圖
? 一個2D向量儲存在紅色和綠色通道內(nèi)
? 在全屏矩形兩個方向上卷動貼圖并采樣兩次
? 平均兩次采樣并把值變換到 [-1.0, 1.0] 的范圍內(nèi)
? 用扭曲度放縮向量
? 結果就是扭曲向量
扭曲向量
? 扭曲向量用于偏移原始紋理坐標
? 向量的大小取決于扭曲度
? 這個新的擾動紋理用于讀入離屏緩存
可增長泊松分布
? 模糊中心在擾動紋理坐標的中間
? 偏移基于扭曲度(Perturbation)
扭曲 Shader
| float4 main (PsInput i) : COLOR { // fetch from perturbation map with scrolling texture coords float3 vPerturb0 = tex2D (tPerturbationMap, i.texCoord1); float3 vPerturb1 = tex2D (tPerturbationMap, i.texCoord2);
// scale and bias: (color - 0.5f)*2.0f 轉回到[-1~1]范圍 ?? vPerturb0 = SiConvertColorToVector(vPerturb0); ?? vPerturb1 = SiConvertColorToVector(vPerturb1);
// average perturbation vectors float2 offset = (vPerturb0.xy + vPerturb1.xy) * 0.5f;
// get distortion weight from renderable texture (stored in alpha)存在上一Pass的RT中 float4 cDistWeight = tex2D (tRBFullRes, i.texCoord0);
// square distortion weight ?? cDistWeight.a *= cDistWeight.a;
// compute distorted texture cords fPerturbScale這里是一個預定義的參數(shù),可以當做擾動偏移的強度 ?? offset.xy = ((offset.xy * cDistWeight.a) * fPerturbScale) + i.texCoord0;
// fetch the distorted color float4 o; ?? o.rgb = SiPoissonDisc13RGB(tRBFullRes, offset, 1.0f/screenRes.xy, cDistWeight.a); ?? o.a = 1.0f; return o; } |
PS代碼看到這里可以大體明白,基本過程與上一篇的水體擾動實現(xiàn)方法一致,但就是在最后出現(xiàn)了這個PoissonDiscl處理方法,
數(shù)學課本差不多都還給老實了吧?好吧,首先,讓我們看看什么事泊松分布
根據(jù)囫圇吞棗的精神指引,首先看一下Shader代碼,這里pixelSize應是外部的RT尺寸的倒數(shù),也就是字面意義上的每個像素的uv寬度大小,這里的泊松分布也就是在當前偏移后的uv位置上繼續(xù)偏移,采樣,中和~~
可增長泊松分布 Shader
| float3 SiGrowablePoissonDisc13FilterRGB (sampler tSource, float2 texCoord, float2 pixelSize, float discRadius) { float3 cOut; float2 poisson[12] = {float2(-0.326212f, -0.40581f), float2(-0.840144f, -0.07358f), float2(-0.695914f, 0.457137f), float2(-0.203345f, 0.620716f), float2(0.96234f, -0.194983f), float2(0.473434f, -0.480026f), float2(0.519456f, 0.767022f), float2(0.185461f, -0.893124f), float2(0.507431f, 0.064425f), float2(0.89642f, 0.412458f), float2(-0.32194f, -0.932615f), float2(-0.791559f, -0.59771f)}; // Center tap ?? cOut = tex2D (tSource, texCoord); for (int tap = 0; tap < 12; tap++) ?? { float2 coord = texCoord.xy + (pixelSize * poisson[tap] * discRadius);
// Sample pixel ????? cOut += tex2D (tSource, coord); ?? } return (cOut / 13.0f); } |
2, 徑向模糊
看原理:
http://www.gamerendering.com/2008/12/20/radial-blur-filter/
實現(xiàn)其實很簡單,比上邊的熱流擾動簡單多了,確定一個中心點(如0.5, 0.5), 跟當前像素連一條線. 以當前像素為中心, 在線上的附近像素進行采樣, 最后取一下平均值.
HLSL(感謝逍遙博主的翻譯):
1. // This texture should hold the image to blur.
2. sampler2D Texture0;?
3.
4. // some const, tweak for best look
5. const float fSampleDist;?
6. const float fSampleStrength;??
7.
8.
9. // some sample positions
10. float samples[10] =??
11. {?
12.??? -0.08,?
13.??? -0.05,?
14.??? -0.03,?
15.??? -0.02,?
16.??? -0.01,?
17.??? 0.01,?
18.??? 0.02,?
19.??? 0.03,?
20.??? 0.05,?
21.??? 0.08?
22. };?
23. float4 ps_main( float2 texCoord? : TEXCOORD0 ) : COLOR?
24. {?
25. // 0.5,0.5 is the center of the screen
26. // so substracting uv from it will result in
27. // a vector pointing to the middle of the screen
28.??? float2 dir = 0.5 - texCoord;?
29. // calculate the distance to the center of the screen
30. float dist = length(dir);?
31. // normalize the direction (reuse the distance)
32.??? dir /= dist;?
33.
34. // this is the original colour of this pixel
35. // using only this would result in a nonblurred version
36.??? float4 color = tex2D(Texture0, texCoord);?
37.
38.??? float4 sum = color;?
39. // take 10 additional blur samples in the direction towards
40. // the center of the screen
41. for (int i = 0; i < 10; ++i)?
42.??? {?
43.?????? sum += tex2D(Texture0, texCoord + dir * samples[i] * fSampleDist);?
44.??? }?
45.
46. // we have taken eleven samples
47.??? sum /= 11.0;?
48.
49. // weighten the blur effect with the distance to the
50. // center of the screen ( further out is blurred more)
51. float t = saturate(dist * fSampleStrength);?
52.
53. //Blend the original color with the averaged pixels
54. return lerp(color, sum, t);?
55. }?
兩個參數(shù), 動態(tài)調(diào)整的
比如可以加入RM內(nèi)置根據(jù)Time_X變化的Sin值,使得畫面出現(xiàn)“清晰->模糊->清晰’的加速效果顯示
for (int i = 0; i < 10; ++i)
{
sum += tex2D(Image, texCoord + dir * samples[i] * fSampleDist*abs(fSinTime0_X));
}
怎么樣,效果是不是很贊?!Just do it!
附上這兩篇的RM工程:
后處理 水底擾動(泊松分布暫未做)
/Files/hmxp8/ZephyrTest_01.rar
直接用了ScreenSpaceEffect的fx,徑向模糊在其中的MotionBlur中
/Files/hmxp8/ZephyrTest_02.rar
轉載于:https://www.cnblogs.com/Zephyroal/archive/2011/11/24/2262217.html
總結
以上是生活随笔為你收集整理的一天干掉一只Monkey计划(二)——热流扰动,径向模糊的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 微软企业库5.0 学习之路——Unity
- 下一篇: 智能内存释放工具