Tessellation技術,或者說曲面細分技術,是由ATI在2001年開發的,一直以來都是AMD-ATI的專屬技術。最早應用在微軟XBOX 360游戲機上,在PC上沒有廣泛采用。從ATI R600(Radeon HD2000系列)核心以來,曲面細分單元一直集成在AMD-ATI的GPU內部,不過并沒有引起廣泛關注,直到微軟將其采納,加入DirectX11 。這也是AMD將HD6000系列顯卡中的曲面細分單元稱為“第八代曲面細分技術”的原因。
事實上,在更早的DirectX 8時代,ATI就已經和微軟聯手開發了TruForm(N-Patch)技術,也就是Tessellation的雛形,并被納入DirectX8.1。但由于該技術有一些不可控制的BUG,因此被DirectX9和DirectX10無情的拋棄了。
Tessellation之所以未成氣候,就是因為此前的技術還不夠完善,另外GPU處理能力不足也是一大因素,因此ATI即便有微軟的鼎力相助,也未能將該技術發揚光大。到了DX10時代,ATI雖然在全線GPU當中整合了Tessellator模塊,無奈孤掌難鳴,并沒有得到游戲開發商的支持。
直到DirectX11時代,GPU自身的性能有了長足的進步,硬件上真正具備了細分曲面的實力,再加上微軟重新改寫API渲染流程,專為Tessellation開辟了新的著色器,這才讓Tessellation技術得以重見天日。Tessellation技術,或者說曲面細分技術,是由ATI在2001年
開發的,一直以來都是AMD-ATI的專屬技術。最早應用在微軟XBOX 360游戲機上,在PC上沒有廣泛采用。從ATI R600(Radeon HD2000系列)核心以來,曲面細分單元一直集成在AMD-ATI的GPU內部,不過并沒有引起廣泛關注,直到微軟將其采納,加入DirectX11 。這也是AMD將HD6000系列顯卡中的曲面細分單元稱為“第八代曲面細分技術”的原因。
事實上,在更早的DirectX 8時代,ATI就已經和微軟聯手開發了TruForm(N-Patch)技術,也就是Tessellation的雛形,并被納入DirectX8.1。但由于該技術有一些不可控制的BUG,因此被DirectX9和DirectX10無情的拋棄了。
Tessellation之所以未成氣候,就是因為此前的技術還不夠完善,另外GPU處理能力不足也是一大因素,因此ATI即便有微軟的鼎力相助,也未能將該技術發揚光大。到了DX10時代,ATI雖然在全線GPU當中整合了Tessellator模塊,無奈孤掌難鳴,并沒有得到游戲開發商的支持。
直到DirectX11時代,GPU自身的性能有了長足的進步,硬件上真正具備了細分曲面的實力,再加上微軟重新改寫API渲染流程,專為Tessellation開辟了新的著色器,這才讓Tessellation技術得以重見天日。
DirectX 11 Tessellation (曲面細分)—什么是 Tessellation (曲面細分) ?它為什么能夠起到如此重要的作用?
隨著最近人們對 DirectX 11 的議論紛紛,你可能已經聽說了有關 DirectX 11 最大新特性 Tessellation (曲面細分) 的大量介紹。作為一個概念, Tessellation (曲面細分) 非常直截了當,就是處理一個多邊形分成諸多小碎片。但是為什么這樣的處理方式能夠備受矚目呢?它是如何幫助提升游戲畫質的呢?本文中,我們將分析 Tessellation (曲面細分) 之所以能夠為 PC 3D 圖形帶來深刻變革的原因,并闡釋一下 NVIDIA? GeForce? GTX 400 系列 GPU 如何提供突破性的 Tessellation (曲面細分) 性能。
從本質上來講, Tessellation (曲面細分) 是一種將多邊形分解成更加細小的碎片以提升幾何逼真度的方法。例如,如果處理一個正方形并將其沿對角線切開,那么實際上就是將這一正方形“曲面細分”成為兩個三角形。就其本身而言, Tessellation (曲面細分) 并不能提升半點逼真度。例如,在游戲中,一個正方形被渲染成為兩個三角形還是兩千個三角形都是無關緊要的。只有在使用新三角形來描述新信息時, Tessellation (曲面細分) 才能提升逼真度。
當一個置換貼圖 (左) 應用到平面上時,所生成的表面 (右) 就會表現出置換貼圖中所編碼的高度信息。
運用新三角形最簡單、最流行的方式就是有“ Displacement Mapping (貼圖置換) ”之稱的技術。置換的貼圖就是一個存儲高度信息的紋理。當應用到某一表面上時,該貼圖讓這一表面的頂點能夠根據高度信息調高或調低。 例如,使用一塊大理石板,圖形藝術家能夠通過“置換”頂點的方法打造雕刻效果。另一種流行技術是將置換的貼圖應用到地形上,以雕琢出彈坑、峽谷以及山峰。
正如 Tessellation (曲面細分) 一樣, Displacement Mapping (貼圖置換) 已經存在很長一段時間了。但是直到最近,它才真正流行起來。究其原因,是因為想要讓 Displacement Mapping (貼圖置換) 有效,表面必須由大量頂點構成才行。以大理石雕刻為例,如果大理石塊由八個頂點構成,那么在它們之間便沒有可以生成龍形浮雕的相對置換量了。只有在基礎網格中具備足夠多的頂點用以描繪新形狀時才能夠生成細致的浮雕。從本質上來講, Displacement Mapping (貼圖置換) 需要 Tessellation (曲面細分) ,反之亦然。
隨著 DirectX 11 的問世, Tessellation (曲面細分) 與 Displacement Mapping (貼圖置換) 終于實現了珠聯璧合,廣大開發商已經加入到這一陣營當中。像《Alien vs. Predator》以及《地鐵2033》這樣的流行游戲均采用了 Tessellation (曲面細分) 來生成外觀平滑的模型,而開發商Valve公司與 id Software 已經完成了一些前景看好的工作,將這些技術應用到其現有的游戲人物身上。
當一個粗糙的模型 (左) 經過 Tessellation (曲面細分) 處理后,就會生成平滑的模型 (中間)。當應用了貼圖置換之后 (右),游戲人物便接近電影般的逼真度了。 ? Kenneth Scott、id Software版權所有。2008
因為DirectX 11 Tessellation (曲面細分) 流水線是可編程的,因此可以用它來解決大量圖形問題。讓我們來看一看四個實例。
完美凹凸貼圖
從本質上來講,Displacement Mapping (貼圖置換) 可被用作現有凹凸貼圖技術的臨時替代技術。例如法線貼圖等當前的技術通過更佳的像素渲染,能夠創造出凹凸表面的假象。所有這些技術都只在特定情況下有效,并且在其起效時并不是全都那么逼真。下面以凹凸貼圖中較為先進的視差遮蔽貼圖為例進行說明。雖然它能夠生成重疊的幾何假象,但是它只能在平面上以及物體內部起作用 (見上圖)。真正的 Displacement Mapping (貼圖置換) 不存在這些問題,能夠從所有視角生成精確的結果。
更加平滑的人物
無需藝術家手工輸入,PN-Triangles 可實現游戲人物的自動平滑。幾何與光照逼真度均能夠得到提升。
細化算法是 Tessellation (曲面細分) 的另一個自然搭檔。細化算法可處理粗糙模型,借助于 Tessellation (曲面細分) ,該算法可創建外觀更加平滑的模型。PN-Triangles (也稱作N-patches) 就是一個流行的實例。PN-Triangles算法能夠將低分辨率模型轉化為彎曲表面,該表面然后可以被重新繪制成由“高精曲面細分”的三角形所組成的網格。在當今游戲中,我們認為理所當然的大量視覺假象都可以借助此類算法來消除。這些視覺假象包括人物關節處呈現塊狀圖案、汽車輪子呈多邊形外觀以及面部特征粗糙。例如,《Stalker: Call of Pripyat》中就使用了 PN-Triangles 來生成外表更平滑、更自然的人物。
無縫的精細度
在具有大型、開放式環境的游戲當中,用戶可能會注意到,遠處的物體經常會時而出現、時而消失無。這是由于游戲引擎正在不同精細度 (LOD) 之間進行切換,以限制幾何工作負荷。因為需要為同一模型或環境保存多個版本的數據,所以直到那個時候,都還沒有一種簡單的方法能夠連續改變精細度。動態 Tessellation (曲面細分) 通過即時改變精細度,解決了這一問題。例如,當遠處的建筑物首次映入眼簾時,也許僅使用10個三角形來渲染它。隨著用戶視野的拉近,該建筑物的顯著特征開始浮現,更多三角形則被用來描繪窗子和屋頂等細節。當你最終到達門口時,單單舊式銅質門把手一項就動用了一千個三角形來進行渲染;Displacement Mapping (貼圖置換) 細致地雕刻出了每一道凹槽。由于消除了動態 Tessellation (曲面細分) 對象的時隱時現,因此游戲環境現在可以擴展至幾乎無限的幾何精細度。
收放自如的藝術品
對開發商來說, Tessellation (曲面細分) 大幅提升了其內容創作流水線的效率。在描述其使用 Tessellation (曲面細分) 的動機時,Valve 公司的 Jason Mitchell 表示:“我們對能夠編輯游戲內容這一點很感興趣,因為這樣就讓我們能夠實現縮放了。也就是說,我們想要只制作一次模型,然后便能夠將其提升至電影畫質…反之,我們想要能夠自然地降低游戲內容的畫質,以滿足在特定系統上實現實時渲染的需要。”這種僅創建一次模型便可在各種平臺上使用的能力意味著縮短了開發時間。對PC游戲玩家來說,這意味著在其GPU上能夠實現最高的圖像畫質。
GeForce? GTX 400 GPU(圖形處理器)如何處理 Tessellation (曲面細分)
傳統的GPU(圖形處理器)設計采用單個幾何引擎來執行 Tessellation (曲面細分) 任務。這種方法是類似早期的GPU設計,此類設計均使用利用單個像素流水線來執行像素著色。在認識到像素流水線是如何從一個單元發展為多個并行單元以及這一進展是如何在3D逼真度方面大放異彩之后,我們便從一開始就設計了自己的并行 Tessellation (曲面細分) 架構。
GeForce? GTX 400 GPU (圖形處理器) 擁有最多15個 Tessellation (曲面細分) 單元,每一個單元都具備針對頂點拾取、 Tessellation (曲面細分) 以及坐標變換的專用硬件。它們利用4個并行光柵引擎來進行運算,這些引擎可將新近曲面細分的三角形轉換成精細像素流以便用于著色。這樣一來, Tessellation (曲面細分) 的性能便實現了巨大突破,持久性能達每秒16億三角形以上。與最快的同類產品相比,GeForce? GTX 480 的速度最高可達7.8倍。這一數據由獨立網站Bjorn3D所測得。
結語
經過多年的反復試驗, Tessellation (曲面細分) 終于在PC上獲得了成功。《地鐵 2033》等優秀游戲已經展現了 Tessellation (曲面細分) 的潛力。最終, Tessellation (曲面細分) 將成為同像素著色一樣關鍵、一樣必不可少的技術。由于意識到了 Tessellation (曲面細分) 的重要性,NVIDIA? 公司從一開始便打造并行 Tessellation (曲面細分) 架構,推動這一進程。成果就是 GeForce? GTX 400 系列 GPU (圖形處理器)—幾何逼真度與 Tessellation (曲面細分) 性能的真正突破。
下圖描述了細分的基本思想,每次細分都是在每條邊上插入一個新的頂點,可以看到隨著細分次數的增加,折線逐漸變成一條光滑的曲線。曲面細分需要有幾何規則和拓撲規則,幾何規則用于計算新頂點的位置,拓撲規則用于確定新頂點的連接關系。下面介紹兩種網格細分方法:Catmull-Clark細分和Loop細分。
Catmull-Clark subdivision:
Catmull-Clark細分是一種四邊形網格的細分法則,每個面計算生成一個新的頂點,每條邊計算生成一個新的頂點,同時每個原始頂點更新位置。下圖為Catmull-Clark細分格式的細分掩膜,對于新增加的頂點位置以及原始頂點位置更新規則如下:
1.網格內部F-頂點位置:
設四邊形的四個頂點為v0、v1、v2、v3,則新增加的頂點位置為v = 1/4*(v0?+ v1?+ v2?+ v3)。
2.網格內部V-頂點位置:
設內部頂點v0的相鄰點為v1、v2,…,v2n,則該頂點更新后位置為
,其中α、β、γ分別為α = 1 - β - γ。
3.網格邊界V-頂點位置:
設邊界頂點v0的兩個相鄰點為v1、v2,則該頂點更新后位置為v = 3/4*v0?+ 1/8*(v1?+ v2)。
4.網格內部E-頂點位置:
設內部邊的兩個端點為v0、v1,與該邊相鄰的兩個四邊形頂點分別為v0、v1、v2、v3和v0、v1、v4、v5,則新增加的頂點位置為v = 1/4*(v0?+ v1?+ vf1?+ vf2) = 3/8*(v0?+ v1) + 1/16*(v2?+ v3?+ v4?+ v5)。
5.網格邊界E-頂點位置:
設邊界邊的兩個端點為v0、v1,則新增加的頂點位置為v = 1/2*(v0?+ v1)。
效果:
function [VV, FF, S] = CC_subdivision(V, F, iter)
? ? % Catmull_Clark subdivision
? ? if~exist('iter','var')
? ? ? ? iter =1;
? ? end
? ? VV = V;
? ? FF = F;
? ? fori =1:iter
? ? ? ? nv = size(VV,1);
? ? ? ? nf = size(FF,1);
? ? ? ? O = outline(FF);
? ? ? ? original =1:nv;
? ? ? ? boundary = O(:,1)';interior = original(~ismember(original, boundary));
? ? ? ? no = length(original);
? ? ? ? nb = length(boundary);
? ? ? ? ni = length(interior);
? ? ? ? %% Sv
? ? ? ? Etmp = sort([FF(:,1) FF(:,2);FF(:,2) FF(:,3);FF(:,3) FF(:,4);FF(:,4) FF(:,1)],2);
? ? ? ? [E, ~, idx] = unique(Etmp,'rows');
? ? ? ? Aeven = sparse([E(:,1) E(:,2)], [E(:,2) E(:,1)],1, no, no);
? ? ? ? Aodd = sparse([FF(:,1) FF(:,2)], [FF(:,3) FF(:,4)],1, no, no);
? ? ? ? Aodd = Aodd + Aodd';? ? ? ?
? ? ? ? val_even = sum(Aeven,2);
? ? ? ? beta =3./(2*val_even);
? ? ? ? val_odd = sum(Aodd,2);
? ? ? ? gamma =1./(4*val_odd);
? ? ? ? alpha =1- beta - gamma;
? ? ? ? Sv = sparse(no,no);
? ? ? ? Sv(interior,:) = ...
? ? ? ? ? ? sparse(1:ni, interior, alpha(interior), ni, no) + ...
? ? ? ? ? ? bsxfun(@times, Aeven(interior,:), beta(interior)./val_even(interior)) + ...
? ? ? ? ? ? bsxfun(@times, Aodd(interior,:), gamma(interior)./val_odd(interior));
? ? ? ? Sboundary = ...
? ? ? ? ? ? sparse([O(:,1);O(:,2)],[O(:,2);O(:,1)],1/8,no,no) + ...
? ? ? ? ? ? sparse([O(:,1);O(:,2)],[O(:,1);O(:,2)],3/8,no,no);
? ? ? ? Sv(boundary,:) = Sboundary(boundary,:);
? ? ? ? %% Sf
? ? ? ? Sf =1/4.* sparse(repmat((1:nf)',1 ,4), FF, 1);i0 = no + (1:nf)';%% Se
? ? ? ? flaps = sparse([idx;idx], ...
? ? ? ? ? ? ? ? ? ? ? [FF(:,3) FF(:,4);FF(:,4) FF(:,1);FF(:,1) FF(:,2);FF(:,2) FF(:,3)], ...
? ? ? ? ? ? ? ? ? ? ? 1);
? ? ? ? onboundary = (sum(flaps,2) ==2);
? ? ? ? flaps(onboundary,:) =0;
? ? ? ? ne = size(E,1);
? ? ? ? Se = sparse( ...
? ? ? ? ? ? ? ? [1:ne1:ne]', ...[E(:,1); E(:,2)], ...
? ? ? ? ? ? ? ? [onboundary;onboundary].*1/2+ ~[onboundary;onboundary].*3/8, ...
? ? ? ? ? ? ? ? ne, ...
? ? ? ? ? ? ? ? no) + ...
? ? ? ? ? ? ? ? flaps*1/16;
? ? ? ? %%newfaces &new vertices
? ? ? ? i1 = no +? nf + (1:nf)';i2 = no +2*nf + (1:nf)';i3 = no +3*nf + (1:nf)';i4 = no +4*nf + (1:nf)';? ? ? ?
? ? ? ? FFtmp = [i0 i4 FF(:,1) i1; ...
? ? ? ? ? ? ? ? i0 i1 FF(:,2) i2; ...
? ? ? ? ? ? ? ? i0 i2 FF(:,3) i3; ...
? ? ? ? ? ? ? ? i0 i3 FF(:,4) i4];
? ? ? ? reidx = [(1:no)'; no+(1:nf)'; no+nf+idx];
? ? ? ? FF = reidx(FFtmp);
? ? ? ? S = [Sv; Sf; Se];
? ? ? ? VV = S*VV;
? ? end
end
Loop subdivision:
Loop細分是一種三角形網格的細分法則,它按照1-4三角形分裂,每條邊計算生成一個新的頂點,同時每個原始頂點更新位置。下圖為Loop細分格式的細分掩膜,對于新增加的頂點位置以及原始頂點位置更新規則如下:
1.網格內部V-頂點位置:
設內部頂點v0的相鄰點為v1、v2,…,vn,則該頂點更新后位置為
,其中
。
2.網格邊界V-頂點位置:
設邊界頂點v0的兩個相鄰點為v1、v2,則該頂點更新后位置為v = 3/4*v0?+ 1/8*(v1?+ v2)。
3.網格內部E-頂點位置:
設內部邊的兩個端點為v0、v1,相對的兩個頂點為v2、v3,則新增加的頂點位置為v = 3/8*(v0?+ v1) + 1/8*(v2?+ v3)。
4.網格邊界E-頂點位置:
設邊界邊的兩個端點為v0、v1,則新增加的頂點位置為v = 1/2*(v0?+ v1)。
效果: