OpenGL,或者D3D 的深度緩存都存在精度問題,在最新的Nvidia GF8 系列顯卡中已經(jīng)開始應(yīng)用float point depth buffer. 而在此之間,深度緩存其實只有位平面的概念. 這隨API的不同,都需要指定后緩存深度緩存精度, Depth ,我一般使用24位,也就是D3D中常見的 D24S8. 但除非你是用浮點(diǎn),否則都會有精度損失的問題,這種情況總是發(fā)生在2個幾乎共面的片面,他們投影在后裁減平面時都會被賦予一個深度(當(dāng)然,如果深度緩存可寫的話),而上面已經(jīng)說過,目前來說,深度只是位平面, 你可以把他假設(shè)為這樣的形勢
depth w
0 [near_clip, near_clip + 0.1]
1 [near_clip + 0.1, near_clip +0.2]
2 [near_clip + 0.3 , near_clip +0.4]
........
max [far_clip - 0.1, far_clip]
上面假設(shè)硬件的最小深度單元 r = 0.1
那么將會出現(xiàn)這樣的問題.
當(dāng)2個片元距離近裁減平面 w 落在同一個區(qū)間的時候,他們的深度是相等的. 最終你所看到的結(jié)果,就是下面的這種樣子:

注意到藍(lán)色線框里面.
要解決這個問題, 你只要google 或者去 beyond3d,等論壇,搜索 depth fighting ,得到的答案往往就是設(shè)置深度偏移. OpenGL : Polygon offset. D3D: Depth Bais.
拿OpenGL 來說,就是對有存在深度沖突的2個 Mesh Object A,B如下方式渲染.
A.Render();
glEnable(GL_POLYGON_OFFSET_FILL);
glPolygonOffset(0.0f,-1.0f);
B.Render();
glDisable(GL_POLYGON_OFFSET_FILL);
這是一個不錯的方法,但是實際操作起來很麻煩,而且沒有效率. 注意到,你必須一先一后的渲染這2個對象, 拿上圖來說,我需要在MAX 中把手套和手臂脫離,形成一個獨(dú)立的節(jié)點(diǎn),然后我起碼需要新建立2個頂點(diǎn)緩存,并在渲染的過程中設(shè)置2次.這對于帶寬是個不小的代價.所以我不是很贊成這樣去處理,當(dāng)然,有的時候無法避免了,也會如此..
如果避免發(fā)生Z-Fighting 才是關(guān)鍵. 注意到上面的depth - w 的位平面對應(yīng)關(guān)系. 由于硬件都只能支持一定的深度格式,也就是說,Depth bits 是一定的,假為 D.而頂點(diǎn)的投影深度則毫無限制,他可以是 near_clip ---> far_clip 的任意一個浮點(diǎn)數(shù).因此
dw/D
= (far_clip - near_clip)/near_clip;
從上面可以看出, 要想dw 更精確,那么 near_clip 必然要更大(適用范圍是far_clip >> near_clip).
上面那張存在depth-fighting 的截圖當(dāng)時的情況是 near_clip :0.0001 far_clip : 64000.0
下面的是在near_clip 0.1 far_clip 不變.

繼續(xù)提高定點(diǎn)投影深度,也不會出現(xiàn)難看的深度沖突了.
