Shader 學習之路-渲染隊列、Zwrite、ZTest(十)

第一篇

【顏色緩沖區(qū)】

顏色緩沖區(qū)(COLOR_BUFFER)就是幀緩沖區(qū)(FRAME_BUFFER),你需要渲染的場景最終每一個像素都要寫入該緩沖區(qū),然后由它在渲染到屏幕上顯示.

【深度緩沖區(qū)】

深度緩沖區(qū)(DEPTH_BUFFER)與幀緩沖區(qū)對應,用于記錄上面每個像素的深度值,通過深度緩沖區(qū),我們可以進行深度測試,從而確定像素的遮擋關系,保證渲染正確.

【模板緩沖區(qū)】

模版緩沖(STENCIL_BUFFER)與深度緩沖大小相同,通過設置模版緩沖每個像素的值,我們可以指定在渲染的時候只渲染某些像素,從而可以達到一些特殊的效果.

深度緩沖區(qū)的作用就是區(qū)分顏色所在的層次,防止把被遮擋住的顏色顯示出來。

當一個像素第二次被繪制時– 例如當一個物體在另一個物體之后被繪制- 深度緩沖要么保留前面的深度值,要么使用第二個像素的深度值替換當前深度值。那個深度保留哪個深度拋棄取決于你選擇的深度函數。例如,如果當前深度函數是CompareFunction.LessEqual時,只有小于等于當前深度值的值才會被保留,而大于當前深度值的值會被拋棄。這叫做深度測試,每次繪制像素時都會進行深度測試。當對一個像素進行深度測試時,它的顏色會被寫入渲染目標,而深度被寫入深度緩沖

深度緩沖區(qū)原理以及為什么要用它

----------------參考資料《OpenGL編程指南》

1.在開始介紹深度緩存之前,先了解一下隱藏表面消除。隱藏表面消除(hidden-surface removal)就是消除實心物體被其他物體所遮擋的那部分。實現隱藏表面消除最簡單方法就是使用深度緩沖區(qū)(又叫Z緩沖區(qū))。

2.深度緩沖區(qū)原理深度緩沖區(qū)原理就是把一個距離觀察平面(近裁剪面)的深度值(或距離)與窗口中的每個像素相關聯。首先,使用glClear(GL_DEPTH_BUFFER_BIT),把所有像素的深度值設置為最大值(一般是遠裁剪面)。然后,在場景中以任意次序繪制所有物體。硬件或者軟件所執(zhí)行的圖形計算把每一個繪制表面轉換為窗口上一些像素的集合,此時并不考慮是否被其他物體遮擋。其次,OpenGL會計算這些表面和觀察平面的距離。如果啟用了深度緩沖區(qū),在繪制每個像素之前,OpenGL會把它的深度值和已經存儲在這個像素的深度值進行比較。新像素深度值<原先像素深度值,則新像素值會取代原先的;反之,新像素值被遮擋,他顏色值和深度將被丟棄。為了啟動深度緩沖區(qū),必須先啟動它,即glEnable(GL_DEPTH_TEST)。每次繪制場景之前,需要先清除深度緩沖區(qū),即glClear(GL_DEPTH_BUFFER_BIT),然后以任意次序繪制場景中的物體。

第二篇

openGL里常出現深度測試,一直不清楚。今天就來弄清楚。


1、深度

? ???所謂深度,就是在openGL坐標系中,像素點Z坐標距離攝像機的距離。攝像機可能放在坐標系的任何位置,那么,就不能簡單的說Z數值越大或越小,就是越靠近攝像機。

2、深度緩沖區(qū)

????? 深度緩沖區(qū)原理就是把一個距離觀察平面(近裁剪面)的深度值(或距離)與窗口中的每個像素相關聯。

????? 首先,使用glClear(GL_DEPTH_BUFFER_BIT),把所有像素的深度值設置為最大值(一般是遠裁剪面)。

????? 然后,在場景中以任意次序繪制所有物體。硬件或者軟件所執(zhí)行的圖形計算把每一個繪制表面轉換為窗口上一些像素的集合,此時并不考慮是否被其他物體遮擋。

????? 其次,OpenGL會計算這些表面和觀察平面的距離。如果啟用了深度緩沖區(qū),在繪制每個像素之前,OpenGL會把它的深度值和已經存儲在這個像素的深度值進行比較。新像素深度值<原先像素深度值,則新像素值會取代原先的;反之,新像素值被遮擋,他顏色值和深度將被丟棄。

????? 為了啟動深度緩沖區(qū),必須先啟動它,即glEnable(GL_DEPTH_TEST)。每次繪制場景之前,需要先清除深度緩沖區(qū),即glClear(GL_DEPTH_BUFFER_BIT),然后以任意次序繪制場景中的物體。

? ??? 數學基礎:

? ??? 待渲染的照相機空間中的深度經常定義為近距?near?到遠距?far?之間的?z?值,Z坐標和X、Y坐標一樣。在變換、裁減和透視除法后,Z的范圍為-1.0~1.0。DepthRange映射指定Z坐標的變換,這與用于將XY映射到窗口坐標的視口變換類似,在透視變換之后,得到新的?z'?值:

?????其中??是照相機空間的值,它有時候也表示為?w?或者?w'

????? 結果?z'?是在?-1??1?之間歸一化之后的值,其中近距?near?平面位于?-1?處,遠距?far?平面位于?1?處。在這個范圍之外的相應點在視圖體之外,不需要進行渲染。

?????為了實現深度緩沖,在整個屏幕空間上的對當前多邊形頂點之間進行插值來計算?z'?的值,通常這些中間數值在深度緩沖區(qū)中用定點數格式保存。距離近距?near?平面越近,z'?值越密;距離越遠,z'?值越稀。這樣距離照相機越近精度越高。near?平面距離照相機越近,則遠距離位置的精度越低。near?平面距離照相機太近是在遠距離物體產生人為誤差的一個常見因素。

? ?3、深度測試

? ? ? ?OpenGL中的深度測試是采用深度緩存器算法,消除場景中的不可見面。在默認情況下,深度緩存中深度值的范圍在0.01.0之間,這個范圍值可以通過函數:

??????? glDepthRange (nearNormDepth, farNormalDepth);

? ? ? ?將深度值的范圍變?yōu)?b>nearNormDepth到farNormalDepth之間。這里nearNormDepthfarNormalDepth可以取0.01.0范圍內的任意值,甚至可以讓nearNormDepth > farNormalDepth。這樣,通過glDepthRange函數可以在透視投影有限觀察空間中的任意區(qū)域進行深度測試。

? ? ? ?另一個非常有用的函數是:

??????? glClearDepth (maxDepth);

? ? ? ?參數maxDepth可以是0.01.0范圍內的任意值。glClearDepthmaxDepth對深度緩存進行初始化,而默認情況下,深度緩存用1.0進行初始化。由于在進行深度測試中,大于深度緩存初始值的多邊形都不會被繪制,因此glClearDepth函數可以用來加速深度測試處理。這里需要注意的是指定了深度緩存的初始化值之后,應調用:

??????? glClear(GL_DEPTH_BUFFER_BIT); ??完成深度緩存的初始化。

? ? ? ?在深度測試中,默認情況是將需要繪制的新像素的z值與深度緩沖區(qū)中對應位置的z值進行比較,如果比深度緩存中的值小,那么用新像素的顏色值更新幀緩存中對應像素的顏色值。這種比較測試的方式可以通過函數:

??????? glDepthFunc(func);

進行修改。其中參數func的值可以為GL_NEVER(沒有處理)、GL_ALWAYS(處理所有)、GL_LESS(小于)、GL_LEQUAL(小于等于)、GL_EQUAL(等于)、GL_GEQUAL(大于等于)、GL_GREATER(大于)或GL_NOTEQUAL(不等于),其中默認值是GL_LESS。這些測試可以在各種應用中減少深度緩存處理的的計算。

那么,重點來了:

1、ZWriteOn時,ZTest通過時,該像素的深度才能成功寫入深度緩存,同時因為ZTest通過了,該像素的顏色值也會寫入顏色緩存。

2、ZWriteOn時,ZTest不通過時,該像素的深度不能成功寫入深度緩存,同時因為ZTest不通過,該像素的顏色值不會寫入顏色緩存。

3、ZWriteOff時,ZTest通過時,該像素的深度不能成功寫入深度緩存,同時因為ZTest通過了,該像素的顏色值會寫入顏色緩存。

4、ZWriteOff時,ZTest不通過時,該像素的深度不能成功寫入深度緩存,同時因為ZTest不通過,該像素的顏色值不會寫入顏色緩存。

可以看到,像素的深度能否成功寫入深度緩存,條件是ZWriteOn,ZTest通過;

寫入深度緩存的作用就是為ZTest的比較做準備。

因為ZWrite默認值為On,ZTest默認值為LEqual,所以這很好地解釋了為什么在unity中,距離相機近的東西會阻擋住距離相機遠的東西。如果我們先繪制一個距離較近的物體,再繪制距離較遠的物體,則距離遠的物體因為后繪制,會把距離近的物體覆蓋掉,這時我們可以通過修改ZWrite和ZTest來改變物體的遮擋關系!

測試環(huán)境(藍色方塊距離相機較近,注意這個不是Game視圖):

測試的Shader代碼(兩個方塊的shader代碼起始都是一樣的,測試時修改的是測試區(qū)里的代碼):

Shader "Custom/ZTest" {

Properties {

_MainTex("Base(RGB)",2D)= "white" {}

}

SubShader {

Tags { "RenderType"="Opaque" }

LOD 200

/////////////////////////////////////////測試區(qū)

Tags{ "Queue" = "Geometry" }

? ? //ZWrite Off

? //ZTest Off

/////////////////////////////////////////測試區(qū)

CGPROGRAM

#pragma surface surf Lambert


sampler2D _MainTex;


struct Input {

float2 uv_MainTex;

};


void surf(Input IN,inout SurfaceOutput o){

half4 c = tex2D(_MainTex,IN.uv_MainTex);

o.Albedo = c.rgb;

o.Alpha = c.a;

}

ENDCG

}?

FallBack "Diffuse"

}

渲染順序:先藍色方塊再白色方塊(以下簡稱藍,白)

注意ZWrite默認值為On,ZTest默認值為LEqual,沒有渲染物體時,深度緩存中的深度可以理解為無限大

1.

/////////////////////////////////////////藍色方塊測試區(qū)

Tags{ "Queue" = "Geometry+200" }

? ? ? ? ZWrite Off

//ZTest Off

/////////////////////////////////////////藍色方塊測試區(qū)

/////////////////////////////////////////白色方塊測試區(qū)

Tags{ "Queue" = "Geometry+300" }

//ZWrite Off

? ? ? ? //ZTest Off

/////////////////////////////////////////白色方塊測試區(qū)

結果:白在前面

分析:藍沒有將像素寫進深度緩存中,ZTest通過了,顏色緩存中存放了藍的顏色值

白將像素寫進深度緩存中,ZTest通過了,顏色緩存的值變?yōu)榘椎模燥@示白

2.

/////////////////////////////////////////藍色方塊測試區(qū)

Tags{ "Queue" = "Geometry+200" }

? ? ? ? //ZWrite Off

//ZTest Off

/////////////////////////////////////////藍色方塊測試區(qū)

/////////////////////////////////////////白色方塊測試區(qū)

Tags{ "Queue" = "Geometry+300" }

//ZWrite Off

? ? ? ? //ZTest Off

/////////////////////////////////////////白色方塊測試區(qū)

結果:藍在前面

分析:藍將像素寫進深度緩存中,ZTest通過了,顏色緩存中存放了藍的顏色值

而白的像素深度大于藍的,既沒有成功將像素寫進深度緩存,同時ZTest不通過,像素被舍棄,所以顯示藍

3.

/////////////////////////////////////////藍色方塊測試區(qū)

Tags{ "Queue" = "Geometry+200" }

? ? ? ? ZWrite Off

ZTest Off

/////////////////////////////////////////藍色方塊測試區(qū)

/////////////////////////////////////////白色方塊測試區(qū)

Tags{ "Queue" = "Geometry+300" }

//ZWrite Off

? ? ? ? //ZTest Off

/////////////////////////////////////////白色方塊測試區(qū)

結果:白在前面

分析:藍沒有將像素寫進深度緩存中,ZTest通過了,顏色緩存中存放了藍的顏色值

白將像素寫進深度緩存中,ZTest通過了,顏色緩存中存放為白的顏色值

4.

/////////////////////////////////////////藍色方塊測試區(qū)

Tags{ "Queue" = "Geometry+200" }

? ? //ZWrite Off

//ZTest Off

/////////////////////////////////////////藍色方塊測試區(qū)

/////////////////////////////////////////白色方塊測試區(qū)

Tags{ "Queue" = "Geometry+300" }

//ZWrite Off

? ? ZTest Off

/////////////////////////////////////////白色方塊測試區(qū)

結果:白在前面

分析:藍將像素寫進了深度緩存中

白將像素寫進了深度緩存中,ZTest通過了,白將顏色緩存中的藍的像素顏色值替換了。

5.

/////////////////////////////////////////藍色方塊測試區(qū)

Tags{ "Queue" = "Geometry+200" }

? ? ? ? //ZWrite Off

//ZTest Off

/////////////////////////////////////////藍色方塊測試區(qū)

/////////////////////////////////////////白色方塊測試區(qū)

Tags{ "Queue" = "Geometry+300" }

ZWrite Off

? ? ? ? ZTest Off

/////////////////////////////////////////白色方塊測試區(qū)

結果:白在前面

分析:藍將像素寫進了深度緩存中

白沒能將像素寫進了深度緩存中(ZWrite為off),但ZTest通過了,此時顏色緩存的值變?yōu)榘椎?,但是深度緩存的值是藍的

6.

/////////////////////////////////////////藍色方塊測試區(qū)

Tags{ "Queue" = "Geometry+200" }

? ? ? ? //ZWrite Off

ZTest Off

/////////////////////////////////////////藍色方塊測試區(qū)

/////////////////////////////////////////白色方塊測試區(qū)

Tags{ "Queue" = "Geometry+300" }

//ZWrite Off

? ? ? ? ZTest Off

/////////////////////////////////////////白色方塊測試區(qū)

結果:白在前面

分析:藍將像素寫進了深度緩存中

白將像素寫進了深度緩存中,ZTest通過了,此時顏色緩存的值變?yōu)榘椎?/p>

7.

/////////////////////////////////////////藍色方塊測試區(qū)

Tags{ "Queue" = "Geometry+200" }

? ? ? ? ZWrite Off

//ZTest Off

/////////////////////////////////////////藍色方塊測試區(qū)

/////////////////////////////////////////白色方塊測試區(qū)

Tags{ "Queue" = "Geometry+300" }

ZWrite Off

? ? ? ? //ZTest Off

/////////////////////////////////////////白色方塊測試區(qū)

結果:白在前面

分析:白、藍都沒有將像素寫入深度緩存中,所以深度緩存中的深度值為無窮大,最后因為白中ZTest默認值的原因,所以顯示白

8.

/////////////////////////////////////////藍色方塊測試區(qū)

Tags{ "Queue" = "Geometry+200" }

ZWrite Off

ZTest Off

/////////////////////////////////////////藍色方塊測試區(qū)

/////////////////////////////////////////白色方塊測試區(qū)

Tags{ "Queue" = "Geometry+300" }

ZWrite Off

ZTest Off

/////////////////////////////////////////白色方塊測試區(qū)

結果:白在前面

?著作權歸作者所有,轉載或內容合作請聯系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容