一墩難求?莫慌!Cocos Creator 帶你30分鐘擁有一只專屬冰墩墩

看到了沒,看到了沒,看到了沒?
上面這只被套在塑料殼里,也擋不住它繼續(xù)蹦噠的“熊貓”,就是這次的冬奧會的吉祥物:冰墩墩。
小萌新一出道,就迅速火爆全網(wǎng)。
這幾天總是聽到有人在唱:“我只想要一只冰墩墩……”,看來,還真是一墩難求啊。
既然買不到(起),那做一個不行嗎?要做就要做一個下面這樣的:

今天麒麟子就手把手,教大家用 Cocos Creator 制作一只屬于自己的冰墩墩。
本次的 DEMO 麒麟子共做了10個小時左右,迫不及待想要上(白)手(嫖)的朋友,可以滾動到文末點擊【閱讀原文】下載(免費的喲)。
一、去搞個 3D 模型
首先去網(wǎng)上找一個冰墩墩 3D 模型,如果有格式方面的問題,可以放入 Blender 等軟件中調(diào)整,大概找到的模型和下圖中的差不多。

二、導(dǎo)入 Cocos Creator
調(diào)整好模型之后,導(dǎo)出為引擎可識別的模型格式(本文用的是 *.glb 格式)。
將導(dǎo)出的文件導(dǎo)入到 Cocos Creator 中(麒麟子目前用的 v3.4.1 版本)。本文使用的冰墩墩 3D 模型由3個部分組成。
身體 胸圈 外殼
如下圖所示:

不要忘了設(shè)置天空盒,并開啟 IBL。
三、調(diào)整材質(zhì)
默認的材質(zhì)已經(jīng)很適合身體和胸圈了,所以,我們重點要處理的是外殼效果。
新建一個材質(zhì),將材質(zhì)的 technique 切換為 transparent 。 調(diào)節(jié) Albedo 的顏色和 Alpha 值,使外殼透明度和顏色值是自己看上去覺得喜歡的。 調(diào)節(jié) roughness 和 matellic 參數(shù),形成高光和反射 并按下圖中調(diào)節(jié)參數(shù)(具體參數(shù)根據(jù)個人喜好,不需要嚴格遵守)。
可能的效果如下圖所示:

四、搭配場景
1、新建了一個圓柱體,調(diào)節(jié)適合的大小,并將我們制作好的冰墩墩放到上面。如下圖所示:

2、新建幾個 Quad,經(jīng)過一系列的縮放、旋轉(zhuǎn)、平移后,選兩個面貼上貼圖,就可以得到下面這樣的臺歷:

麒麟子還寫了一個簡單的腳本,用于定時切換臺歷貼圖,大家可以在 DEMO 源碼中找到。
五、光影與視覺調(diào)節(jié)
1、開啟 ShadowMap 并調(diào)整光源方向,使之與環(huán)境貼圖的光線方向吻合。

2、調(diào)整好攝像機位置。
這里麒麟子寫了一個腳本讓攝像機圍繞著冰墩墩旋轉(zhuǎn)。
最終效果如下圖所示:

好了,我們的冰墩墩就做好了。?我知道騙不了人民群眾雪亮的眼睛,所以自己先把這話刪了。
疑惑三連:
桌子上的倒影呢? 冰墩墩身上的 Blingbling 呢? 冰墩墩邊緣看上去的輪廓效果呢?
六、桌子上的倒影
桌子上的倒影采用的是實時反射效果進行渲染的。核心思路如如下:
1、渲染反射的攝像機
在中學(xué)時,我們學(xué)過上圖中的平面鏡成像原理。
根據(jù)這一原理我們知道,要想獲得平面鏡中的內(nèi)容,只需要計算出物體關(guān)于鏡面對稱的空間數(shù)據(jù)(坐標、旋轉(zhuǎn))即可。
但整個世界的對象非常多,更高效的方法是計算出攝像機關(guān)于鏡面的空間數(shù)據(jù),生成鏡像攝像機,并用這個攝像機進行渲染。
渲染反射的攝像機需要將內(nèi)容輸出到渲染紋理。
關(guān)于鏡像矩陣的推導(dǎo),請看?
Mirror.ts?。
2、自定義用戶裁剪面
當攝像機鏡像翻轉(zhuǎn)后,可能遇上某物體處于鏡面后,且剛好在鏡像攝像機視野內(nèi)的情況。
這種情況下,會渲染出不應(yīng)該被渲染的物體(我們只想要鏡面前方的物體),嚴重情況下,攝像機會被物體遮擋,無法看到(渲染)前面的物體,此時就要用到自定義用戶裁剪面。
自定義用戶裁剪面的基本邏輯是:若一個像素處于某平面之前,則保留,若處于平面之后,則丟棄(discard)。
關(guān)于 3D 編程中的平面相關(guān)內(nèi)容不屬于本文范圍,大家可自行搜索,或等麒麟子后面的教程分享。
3、全局 Uniform
由于所有參與渲染的物體都需要進行用戶自定義裁剪面的判斷,而目前引擎版本沒有提供自定義全局 Uniform 的機制。
當鏡面發(fā)生改變時,需要遍歷所有物體找到材質(zhì),設(shè)置相關(guān) uniform 參數(shù)。
為了解決這樣的麻煩事,麒麟子靈光一閃:不讓新增,還不讓借嗎?空閑的全局變量是否可以借來用用?
在查閱了相關(guān)代碼后,麒麟子找到了幾個空閑的全局變量分量:
cc_time.w cc_fogBase.w cc_fogAdd.w cc_nearFar.zw
Shader代碼中如下使用:
void?checkClipPlane(){
??vec4?clipPlane?=?vec4(0.0,0.0,0.0,0.0);
??clipPlane.w?=?cc_time.w;
??clipPlane.x?=?cc_fogBase.w;
??clipPlane.y?=?cc_nearFar.z;
??clipPlane.z?=?cc_nearFar.w;
??bool?enabled?=?(clipPlane.x?!=?0.0)?||?(clipPlane.y?!=?0.0)?||?(clipPlane.z?!=?0.0);
??float?dist?=?dot(v_position,clipPlane.xyz)?+?clipPlane.w;
??if(?enabled?&&?dist?<=?0.0?){
????discard;
??}
}與之協(xié)作的 TypeScript 代碼請查看 Demo 中的 GlobalUniformMgr.ts、Mirro.ts。
最終我們得到的紋理內(nèi)容如下:

可以很明顯看出來,它是倒著的。
4、投影紋理映射
投影紋理映射是一個專有名詞,它的原理其實非常簡單:在進行紋理映射時,不采用頂點的 uv 坐標信息,而使用頂點投影到屏幕上的位置信息。
當頂點 Pl(x,y,z,1)經(jīng)過 WVP 變換后,進入裁剪坐標系,得到點 Pc(x,y,z,w),Pc 已經(jīng)是一個屏幕空間的坐標了。
Pc 經(jīng)過透視除法后,可以得到 NDC 坐標系中的點 Pndc(x/w,y/w,z/w,1)。
而 NDC 坐標系中 x,y 的取值為[-1,1],z的取值為[0,1]或者[-1,1](視圖形 API 環(huán)境而定)。
//計算屏幕空間坐標?通常在?vs?中進行
v_screenPos?=?cc_matProj?*?(cc_matView?*?matWorld)?*?In.position;
//計算屏幕空間 uv 坐標,?需要在 fs 中進行,否則會出現(xiàn)精度問題。
vec2?screenUV?=?v_screenPos.xy?/?v_screenPos.w?*?0.5?+?0.5;
screenUV?=?vec2(1.0?-?screenUV.x,screenUV.y);上面源碼示例中的 screenUV 就是需要用到的 uv 值,用它進行反射貼圖采樣,即可得到我們想要的鏡面反射效果,如下圖所示:

詳細代碼請參考 Mirror.ts、effect-mirror.effect。
七、Blingbling 與輪廓

先給我們的冰墩墩來個特寫吧。
上圖中的冰墩墩外殼看起來晶瑩剔透的主要原因,是因為渲染走的是折射機制,并不是普通的 Alpha 混合。
這個機制和把大象裝進冰箱一樣簡單,只需三步:
第一步
使用一個專門的攝像機,渲染非透明物體到一張 RenderTexture 上,如下圖所示:

第二步
切換到主攝像機,正常渲染場景物體。
第三步
在渲染半透明物體時,使用投影紋理技術(shù)對非透明物體 RenderTexture。核心代碼如下:
#if?AS_REAL_TRANSPARENT
??vec3?V?=?normalize(v_position?-?cc_cameraPos.xyz);
??vec3?N?=?normalize(s.normal);
??float?fresnel?=?1.0?-?dot(?-V,?N);
??fresnel?=?pow(fresnel,fresnelPower);
??
??vec3?R?=?V?-?2.0?*?N?*?dot(N,V);
??
??vec2?offset?=?-v_normal_view.xy?*?refrIntensity;
??
??vec2?screenUV?=?v_screenPos.xy?/?v_screenPos.w?*?0.5?+?0.5;
??vec3?sceneColor?=?texture(sceneMap,screenUV?+?offset).rgb;
??vec4?temp?=?texture(envMap,R);
??vec3?reflectionColor?=?unpackHDRI(temp);
??s.albedo.rgb?=?mix(sceneColor,?reflectionColor?*?reflIntensity,fresnel);
??s.metallic?=?0.1;
#endif當攝像機轉(zhuǎn)動的時候,可以清晰地感知到折射造成的扭曲效果。

冰墩墩身體邊緣也會出現(xiàn)這樣的效果。

目前版本的折射并未使用折射率進行計算,而是使用攝像機空間的法線方向進行采樣偏移。
八、添加參數(shù)控制面板
為了所見即所得的調(diào)出滿意的效果,參數(shù)控制面板是必須的,如下圖所示:

九、最終效果與源碼

點擊文末【閱讀原文】即可下載 DEMO。
特別提醒:本 DEMO 中使用的冰墩墩 3D 模型來自網(wǎng)絡(luò)素材庫,本文僅供學(xué)習(xí),不涉及商業(yè)用途,如有侵權(quán)請與我們聯(lián)系。



