Animoji模型優化方案總結

Animoji已在上線,第一個版本完成了表情跟蹤、模型變換矩陣動態更新、光照優化、骨骼動畫與關鍵變形動畫等技術,但Animoji模型仍然存在兩個凸出的問題:

  1. 模型體積大。如BabyQ有23M(包括靜態模型、表情、動畫、貼圖),壓縮后仍有8.7M。
  2. 表面不光滑。在模型做表情時,會出現坑坑洼洼的情況,最終只能靠光照和貼圖優化來彌補,但導致表情不夠生動。
  3. 色彩不夠真實。由于過度依賴貼圖彌補上一個不足,模型無法實現動態的真實陰影與色彩變化。

針對在三個問題,本期對黃臉、多福兩個模型使用了新的優化方案。

優化結果

體積優化結果

優化后模型大小

表情與靜態文件減小85.2%,同時得益于動態增加三角面的技術,貼圖也減小了78.4%。
除此以外,由于優化了變形動畫的存儲方式與模型文件的壓縮方式,使得表情文件的大小在上面的基礎上減小了30%。
最終多福的壓縮后體積為1.9M(多福的貼圖會多一些),而之前BabyQ的壓縮后體積是8.7M。

模型表面優化結果

優化后模型

由于哈士奇的模型表情光滑,在方向光源下產生的陰影非常尷尬,最后不得不是用高強度點光源與陰影貼圖(在貼圖上畫假陰影)、法線貼圖這么一套復雜的組合消除這些尷尬的陰影。
多福采用了幾何著色器,在渲染管線圖元裝配之后,動態增添三角面以獲得更加光滑的表面。由于這種方法在渲染管線的前端就改造了幾何體,所以不影響骨骼動畫和后續的著色,能夠兼容現有的實現方案。

視覺效果優化結果

對比蘋果的Animoji,我們發現,即使在我們獲得了光滑的模型,做表情時依然有顏色死板的感覺,視覺上質感不夠,動畫形象不夠靈動。
研究發現,蘋果應該是在shader中加入了fresnel效果,同時在shader中放大了光照的影響面積。依此我在shader中加入了這些效果,并依據反射和環境光遮擋貼圖,實現了令人舒適的視覺效果。

添加shader后

技術方案

動態細分技術

在Vertex shader與Fragment shader之間,現代的GPU渲染管線加入了可選的Geometry shader,與Vertex shader不同,它是處理頂點集合,即圖元。他最大的優勢是,它不僅可以更改頂點,還可以增加頂點,由此三角面會增加。

由于它在管線中的位置處于光柵化之前,所以它對模型的處理實際上是在渲染之前就已經完成,所以可以和已有的變形、骨骼動畫相兼容。

普通的分段由于是在渲染管線末端才增加三角面,會導致變形動畫Crash的問題(頂點不一致),這也是哈士奇無法一直無法光滑的原因。

得益于動態細分,下發的模型可以是非常粗糙的幾何體,也因此模型大小大大減小。


渲染管線

但使用Geometry shader細分網格時,若細分算法選擇不佳,依舊會導致模型即使增加三角面后依然不夠光滑。

使用合適的細分算法

原始網格如下,若使用蘋果默認的Catmull-Clark算法,則結果會導致細分后的頂點分布位置,導致三角面分布不均勻。


原始網格

Catmull-Clark算法結果如下。


Catmull-Clark算法細分后

由于Catmull-Clark算法在增加頂點與邊后,會依據他們計算原有頂點的新位置。
原始頂點的新位置

其中F為新增加的面頂點,R為新增加的邊中點,n為相鄰邊數,P為原有頂點位置。計算得到的就是新位置,這在靜態模型上沒有問題,但是在有動畫的模型上,由于三角面不均勻,依然會導致不光滑。


Catmull-Clark細分后仍不光滑

而我想要的結果是三角面均勻分布的細分方案,即網格邊二分法的效果,如下


邊二分法后的網格

遺憾的是蘋果并不提供細分算法的選擇,大量實踐發現,若使用Maya導出的模型是四邊面,雖然蘋果依然會將網格三角面化,但在細分時會選擇邊二分法,這也是個比較Trick的方法,在最新的iOS beta也有效。

動態細分后貼圖的優勢

由于模型已經做到了動態細分,那么貼圖可以選擇低質量的圖片。之前是因為需要在貼圖上畫出細膩的陰影,所以不能過渡壓縮導致模糊。而新模型是使用動態陰影的,所以貼圖壓縮78.4%,且理論上可以進一步壓縮。

自適應與性能提高

動態細分能做到在管線光柵化之前就增加三角面,但這意味每一次渲染都會使用Geometry shader。
而對比發現GPU的使用率提高了9%左右,GPU的性能雖然可以做到無壓力,但進一步的優化也不是無意義的。
由于透視造成的近大遠小,那么離我們較遠時,細分可以盡量低級,在很近是,可以盡量高級。依據此思想,我加入了自適應的細分能力來降低性能損耗。
同時我考慮在模型不使用時,將細分后的模型保存下來,第二次使用時就不用在渲染管線中每一次都細分,但這個需要進一步測試,因為細分后的模型數據量大大增加,對內存和CPU又會有挑戰,如何將CPU與GPU做一個均衡優化也一直是個難題,這里后期跟進。

Shader著色優化

fresnel效果

fresnel效果能夠產生更合理的反射效果,在渲染時會將不同材質的折射考慮進去。強烈的反射會讓材質顯得更通透。
數學公式不復述了,即代碼實現了fresnel公式。

float Mask = _surface.specular.b;
float basis = saturate(dot(_surface.view, _surface.normal));
float fresnel = saturate(pow(1.-fresnelBasis , edgeDark_rimLight.w)) * pow(AO,5.0);

float fresnelDarkening = saturate(pow(1.-fresnelBasis , edgeDark_rimLight.y)) * pow(AO,5.0);
vec3 darkeningcolor = EdgesDarkeningColor.rgb;
color = mix(color, color * darkeningcolor, fresnelDarkening * lightWrapMask * edgeDark_rimLight.x);

改善光照效果

使用AO貼圖和反射貼圖,營造更柔和的光照效果。這里使用了常用的圖形模糊掩膜,讓反射效果更柔和。

vec4 Wrap = vec4(0,0,0,0);

float diffuse =  saturate(dot(_surface.normal, _light.direction) );
diffuse = pow(diffuse, Wrap.x + 1);



vec3 halfVec = normalize(_light.direction + _surface.view);

// the roughness texture control the shininess :

float roughness = _surface.specular.g;
float shininess = mix (_surface.shininess, 15.0 + Wrap.z, roughness);
vec3 specular = pow(max(dot(_surface.normal, halfVec), 0.0), 0.1);
specular =max(dot(_surface.normal, halfVec), 0.0);
specular = pow(specular, shininess) * _light.intensity.rgb;
specular *= _surface.specular.r;

_lightingContribution.diffuse.rgb = _light.intensity.rgb  * diffuse  * (1.4 + Wrap.y)+ _lightingContribution.ambient;

_lightingContribution.specular = specular;

總結

Animoji模型優化后達到了工業級使用的級別,但渲染方案依然有優化的空間,而跨平臺的實現方案亦在觀察之列。

圖形學博大精深,我時常感覺自己像個小學生對面對的問題不知所措,時常對相關知識閱讀三遍也不能理解。現在我也只是了解了其中冰山一角,工作就像求學,得保持對未知的好奇和渴望,同時要保有敬畏之心。

相關文章

Animoji實現方案分享

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容