第十一章 螢幕後處理效果(4)

2021-09-21 18:26:39 字數 3985 閱讀 5032

bloom特效是遊戲中常見的一種螢幕效果。這種特效可以模擬真實攝像機的一種影象效果,它讓畫面中較量的區域「擴散」到周圍的區域中,造成一種朦朧的效果。下圖給出了動畫短片《大象之夢》(英文名:elephants dream)中的乙個bloom效果。

本節將會實現乙個基本的bloom特效,在學習完本節後,我們會得到類似下圖的效果。

bloom的實現原理非常簡單:我們首先根據閾值提取出影象中的較亮區域,把它們儲存在一張渲染紋理中,再利用高斯模糊對這張渲染紋理進行模糊處理,模擬光線的擴散效果,最後再將其和原影象進行混合,得到最終的效果。

指令碼:(1)首先,我們先繼承基類:

public class bloom : posteffectsbase
在上述**中,bloomshader是我們指定的shader。

(3)由於bloom效果是建立在高斯模糊基礎上的,因此指令碼提供的引數和前面幾乎一樣,我們只增加了乙個新的引數luminancethreshold來控制提取較亮區域時使用的閾值大小:

// blur iterations - larger number means more blur.

[range(0, 4)]

public int iterations = 3;

// blur spread for each iteration - larger value means more blur

[range(0.2f, 3.0f)]

public float blurspread = 0.6f;

[range(1, 8)]

public int downsample = 2;

[range(0.0f, 4.0f)]

public float luminancethreshold = 0.6f;

儘管在大多數情況下,影象的亮度值不會超過1。但如果我們開啟了hdr,硬體會允許我們把顏色值儲存在乙個更高精度範圍的緩衝中,此時畫素的亮度值可能會超過1。因此,在這裡我們把luminancethreshold的值規定在[0,4]範圍內。

(4)最後我們需要定義關鍵的onrenderimage函式:

void onrenderimage (rendertexture src, rendertexture dest) 

material.settexture ("_bloom", buffer0);

graphics.blit (src, dest, material, 3);

rendertexture.releasetemporary(buffer0);

} else

}

上面的**和前面進行高斯模糊時使用的**基本相同,但進行了一些修改。我們前面提到,bloom效果需要3個步驟:首先提取影象較量的區域,因此我們沒有像前面那樣對影象進行降取樣,而是通過呼叫graphics.blit(src, buffer0, material, 0)來使用shader的第乙個pass提取影象中的較量區域,提取到的較亮區域將儲存到buffer0中。然後我們進行和前面一樣的高斯模糊迭代處理,這些pass對應了shader的第二個和第三個pass。模糊後的較亮區域將會儲存在buffer0中,此時,我們再把buffer0傳遞給材質中的_bloom紋理屬性,並呼叫graphics.blit (src, dest, material, 3)使用shader中的第四個pass來進行最後的混合,將結果儲存在目標渲染紋理dest中。最後釋放臨時快取。

shader:

(1)首先宣告本例中使用的各個屬性:

properties 

_bloom ("bloom (rgb)", 2d) = "black" {}

_luminancethreshold ("luminance threshold", float) = 0.5

_blursize ("blur size", float) = 1.0

}

_maintex對應了輸入的渲染紋理。_bloom 是高斯模糊後的較亮區域,_luminancethreshold 是用於提取較亮區域使用的閾值,而_blursize和前面的作用相同,用於控制不同迭代之間高斯模糊的模糊區域範圍。

(2)在本節中,我們仍然使用cginclude來組織**。我們在subshader塊中利用cginclude和endcg語義來定義一系列**:

subshader
(3)宣告**中需要使用的各個變數:

sampler2d _maintex;

half4 _maintex_texelsize;

sampler2d _bloom;

float _luminancethreshold;

float _blursize;

(4)我們首先定義提取較亮區域需要使用的頂點著色器和片元著色器:

struct v2f ;	

v2f o;

o.pos = mul(unity_matrix_mvp, v.vertex);

o.uv = v.texcoord;

return o;

} fixed luminance(fixed4 color)

fixed4 fragextractbright(v2f i) : sv_target

頂點著色器和之前的實現完全相同。在片元著色器中,我們將取樣得到的亮度值減去閾值_luminancethreshold,並把結果擷取到0~1範圍內。然後,我們把該值和原畫素值相乘,得到提取後的亮部區域。

(5)然後,我們定義了混合亮部影象和原影象時使用的頂點著色器和片元著色器。

struct v2fbloom ;

v2fbloom o;

o.pos = mul (unity_matrix_mvp, v.vertex);

o.uv.xy = v.texcoord;

o.uv.zw = v.texcoord;

#if unity_uv_starts_at_top

if (_maintex_texelsize.y < 0.0)

o.uv.w = 1.0 - o.uv.w;

#endif

return o;

} fixed4 fragbloom(v2fbloom i) : sv_target

這裡使用的頂點著色器和之前有些不同,我們定義了兩個紋理座標,並儲存在同乙個型別為half4的變數uv中。它的xy分量對應了_maintex,即原影象的紋理座標。而它的zw分量是_bloom,即模糊後的較亮區域的紋理座標。我們需要對這個座標進行平台差異化處理。

(6)接著,我們定義了bloom效果需要的4個pass:

ztest always cull off zwrite off

pass

usepass "unity shaders book/chapter 12/gaussian blur/gaussian_blur_vertical"

usepass "unity shaders book/chapter 12/gaussian blur/gaussian_blur_horizontal"

pass

其中,第二個和第三個pass我們直接使用了前面高斯模糊中定義的兩個pass,這是通過usepass語義指明它們的pass名實現的。需要注意的是,由於unity內部會把所有pass的name轉換成大寫字母表示,因此在使用usepass命令時我們必須使用大寫形式的名字。

(7)最後我們關閉了該shader的fallback:

fallback off

SQL第十一章上機練習4

上機練習4 查詢學生學號 姓名 考試科目名稱及成績 select s.studentno as 學號,s.studentname as 姓名,j.subjectname as 科目,r.studentresult as 成績 from result as r inner join student a...

第十一章 使用資料處理函式

日期和時間處理函式 datetime日期型別 1000到9999年 日期可以比較 select from student where date 日期 between 2005 9 6 and 2014 6 6 substring 列,位置,長度 select id,substring date1,2...

《重構》讀書筆記(十一) 第十一章 處理概括關係

第十一章 處理概括關係 有一批重構手法專門用於處理類的概括關係 generalization,即繼承關係 其中主要是將函式上下移動於繼承體系之中。1 上移字段 pull up field 判斷若干字段是否重複,唯一的辦法就是觀察函式如何使用它們。如果它們被函式使用的方式很相似,你就可以將它們歸納到超...