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)。
效果: