在5月18日的Qualcomm驍龍游戲和圖形開發者研討會上,Qualcomm資深工程師張濤就移動平臺上如何創建高級3D特效進行了分享。從卡通渲染、皮膚、衣服、毛皮、景深到隨深度衰減的霧、上帝之光以及復古色等,深度講授繪制各種材質的方法。
卡通渲染
卡通渲染是一類使圖像具有手繪圖風格的技術,換句話說,這種技術可以將渲染圖像“卡通化”。與傳統的真實感渲染技術不同,卡通渲染的光照計算結果被有意離散化,它們被映射到離散的色調中,并且通過突出模型邊緣來產生“勾邊”的效果。
實現
卡通渲染類似手繪圖,它的風格看起來非常簡潔,但算法實現卻比較復雜,需要經過多步渲染才能得到最終結果。具體步驟如下:
- 第一步:得到平坦化、條帶狀的圖像。這是通過把光照計算的結果當成紋理坐標,用于索引一張顏色坡度紋理得到的。光照計算可以采用任意的光照模型。
- 第二步:渲染法向圖。場景模型的法向被渲染到一個臨時的離屏render target上,這個法向圖只是用來做邊緣檢測,并不會對最終結果產生直接影響。
- 第三步:對法向圖進行邊緣檢測,并將其結果與第一步的圖像混合得到最終結果。
皮膚
皮膚渲染是實時計算機圖形學的難題之一,一方面,這是因為皮膚光照的復雜性,另一方面,觀察者對皮膚太熟悉了,一旦結果看起來“不像”,他們就很難接受。關于皮膚的光照模型有幾個,比如Hanrahan和Krueger在1993年的Siggraph上首次將皮膚進行分層模擬計算光照反射。他們的方法看起來非常逼真,但是每個光照計算需要100個指令,這對于實時的要求來說太昂貴。
張濤在實例中展示了一個經過優化過的皮膚渲染算法,它可以運行在移動設備上。這個技術通過在陰影區域的漫反射中加入暖色調來逼近次表面散射。并在漫反射計算中加入Minnaert光照項,能得皮膚看起來柔嫩,最后,通過加入鏡面高光使皮膚看起來富有光澤。
實現
該實現的光照方程如下:
Final color = Ambient color+ Minnaertdiffuse color+ Subsurface scattering color+ Specular highlights
除了傳統的輻射反射,Minnaert光照模型還記錄了從皮膚反射的光輻射度,因此它被用來模擬皮膚的漫反射。它比別的光照模型看起來更柔軟,而且它還可以關閉自陰影,從而讓藝術家可以控制皮膚的“粗糙度”。
// General Minnaertformula:
// Result = Color * (cos(NL)^k * cos(VN)^(1-k))
floatA = saturate( pow( max( 0.02, NL ), g_MinnaertExponent) );
floatB = saturate( pow( VN, 1.0-g_MinnaertExponent) );
gl_FragColor.rgb+= Color.rgb* ( A * B );
衣服
衣服無處不在,通常人體90%的部分被衣服覆蓋,因此想要創建逼真的人物模型的話,一個好的衣服著色器是必不可少的。需要注意的是,即便是最普通衣服上的一塊布料也有著大量的凸起、褶皺和變形扭曲。衣服可以看起來是柔軟的,也可以看起來像閃亮的絲絨。
馬塞爾Minnaert在1941年提出一種各向異性光照模型,這個模型至今在現代計算機圖形學的衣服渲染中仍被廣泛使用。Minnaert渲染使用雙向反射分布函數生成該各向異性光照函數。與其它的光照模型不同,該模型通過考慮視角來計算衣服模型的粗糙度,因此在光線和觀察方向匯聚的時候漫反射顏色不會過飽和,另一方面,從接近模型平行的角度看去的話模型會顯得較黑,看起來有絲絨的感覺。
實現
實例演示中的著色器使用了一個經過修改的Minnaert公式,從而可以得到出高光區域和陰影區域光滑過渡的效果。
// General Minnaertformula:
// Result = Color * (cos(NL)^k * cos(VN)^(1-k))
// float A = saturate( pow( NL, g_Minnaert) );
// float B = saturate( pow( VN, 1.0 -g_Minnaert) );
// float Diffuse = ( A * B );
// Enhanced Minnaert:
floatDiffuse = NL * pow( max( NL * VN, 0.1), 1.0-g_Minnaert);
在兩個公式中,如果g_Minnaert為1.0,這個方程就是標準的Lambertian模型。隨著Minnaert指數的變化,邊緣的顏色會隨之變深。
這個經過修改的公式更好的模擬了像衣服一樣的模型表面,因為它磨平了模型的硬邊。在一般的Minnaert方程中,硬邊在Minnaert參數較小的情況下會出現在NL == 0的地方。這對某些視角或者在有諸如次表面散射等其它光照項存在的情況下很有用,它強化了這種自然過渡的感覺。
毛皮
渲染個人的頭發非常耗時,因此毛皮著色器只能使用逼近的方法。做到這一點的一種方法是在越來越大的同心卷中多次渲染一個表面,并且同時漸縮圖像的細節(創建毛發越靠近端部越稀疏的感覺),這種技術被稱為“脫殼”或“殼紋理”。
實現
這個示例程序的著色器使用shell技術來近似模擬皮毛,頭發長度可以實時調節。
算法如下:
- 打開alpha混合,渲染物體N次;
- 在每一次渲染物體的時候,通過頂點著色器將模型變大一點;
- 同時在每一次渲染的時候將頭發的顏色調深一點。
頭發密度通過漫反射紋理的alpha通道控制,斑點圖通常最為有效,它有助于將“胖”像素(大于一個紋素)在皮毛上逐步變小。如果密度圖的像素太小,毛發看起來像圓柱體而不是錐體,這樣在毛發末梢就會顯得不夠柔軟。
該細化算法減掉從密度圖中取出的值,而不是乘以它們進行縮放,這看起來像是在毛發末梢“雕刻出”小細節。毛皮的絨毛感正是通過這種變薄的過程獲得。
gl_FragColor= vec4( Color.rgb* NL, saturate( Color.w-g_FurThinning);
景深
景深出現在圖像中可以清晰顯示場景的部分,這是因為透鏡只能聚焦在某一個距離。在透鏡每一側的焦距處,隨著距離增加清晰度逐步降低,這是與針孔鏡頭不同的。針孔鏡頭只讓一條光線通過,因此圖像是非常清晰的,在很長的一段時間里,計算機生成的圖像看起來就是這種感覺,現在可以通過模擬諸如景深這樣的透鏡效果來達到更逼真的感覺。
實現
張濤表示,有幾個不同的方法來實時達到景深效果。Qualcomm使用的技術是通過深度緩沖來區分清晰的圖像和經過模糊的圖像,并將它們混合達到最終效果。這種技術具有非常高效的優點,這是因為模糊運算的開銷是固定的,而且還可以通過使用四分之一屏幕的尺寸的render target進行加速。
具體步驟如下:
- 將整個場景渲染到一個離屏render target;
- 選取一個小的render target,對第一步的渲染結果進行模糊處理;
- 利用深度緩沖,將模糊圖像和清晰圖像融合得到最終結果。
隨深度衰減的霧
霧是當云接近地面,能見度下降時發生的自然現象。能見度的衰減程度正比于觀察者到物體的距離,這種衰減效應并不是只在有霧的情況下才有。即使在晴朗的天氣下,遠處的物體也會呈現衰減,一個典型的例子是地平線上的山脈,雖然空氣非常干凈,但它其中仍然含有顆粒物,而光只有在真空中才不會衰減。
實現
與景深類似,這種特效依賴于從深度緩沖區中重建深度值。開發者并不需要通過變換矩陣的逆矩陣來得到變換之前的完整坐標,只需要它的深度值。通過深度緩存的值來計算世界坐標系里深度值的公式如下:
World Depth = (-Zn * Q) / (DepthVal-Q)
Q = Zf/ (Zf-Zn)
其中,DepthVal是深度緩沖區的值,Zn是近平面距離,Zf是遠平面距離。
上帝之光
“上帝之光”是光線經過空氣中的顆粒物散射而成的。它們在日出和日落,山川和云層部分遮擋太陽光的時候最常見,也可以通過人工燈光在朦朧混沌的環境中生成。散射光的計算非常復雜,但它也可以通過把光線按某種模式進行拉伸來近似模擬。這些模式可以通過深度緩沖區和一些關鍵信息產生,光線可以通過按照遠離光源的方向對相應模式進行模糊處理來創建。
實現
這是一種基于屏幕空間創建“上帝之光”的技術,它只需要訪問深度緩沖區和一些臨時render target進行處理。
首先,將場景渲染到一個離屏render target,這個render target的深度緩沖區在下一階段中被當做sampler(GLSL中的紋理采樣對象)來生成遮擋物體形狀。接下來縮小得到的圖像并進行模糊處理,然后把像素按照光源進行radical blur(徑向模糊)處理。
復古色
復古色是一種色彩空間,它用來給圖像一種陳舊或古老的感覺。為了達到好的復古色效果,Qualcomm使用了1953年用來編碼NTSC視頻的YIQ色彩空間,這需要對RGB和YIQ顏色空間進行相互轉化。
實現
可以通過下面的GLSL代碼將RGB變換成Y:
vec3IntensityConverter= vec3(0.299, 0.587, 0.114);
floatY = dot(IntensityConverter, Color.xyz);
通過下面的代碼變換回RGB:
vec4sepiaConvert= vec4(0.191, -0.054, -0.221, 0.0);
gl_FragColor= Y + sepiaConvert;
更多Qualcomm Snapdragon游戲和圖形開發研討會資料,請點擊這里。
更多Qualcomm開發內容請詳見:Qualcomm開發者社區。
評論
查看更多