概念
我們經(jīng)常會(huì)聽(tīng)到立方體貼圖、經(jīng)緯圖啃憎、全景圖這樣的概念乏梁,它們描繪的都是一種能從四周觀(guān)察到周?chē)h(huán)境的高動(dòng)態(tài)范圍(HDR)的圖片次洼,統(tǒng)稱(chēng)為環(huán)境貼圖。
環(huán)境貼圖是一種用于模擬高度反射物體表面反映周?chē)h(huán)境的技術(shù)遇骑,常見(jiàn)的環(huán)境貼圖主要有三種:立方體貼圖(CubeMap)卖毁、經(jīng)緯度全景圖(LatLongMap)以及球面環(huán)境圖(SphereMap)。它們之間本質(zhì)上沒(méi)有什么區(qū)別落萎,只不過(guò)排版布局形式不一樣而已亥啦,下面是環(huán)境貼圖常見(jiàn)的集中布局形式。
unity中常用的環(huán)境貼圖是立方體貼圖(CubeMap)练链,它采用的是十字形的布局形式翔脱,
用一個(gè)簡(jiǎn)單的比喻來(lái)解釋立方體貼圖的形成:物體的中心位置架設(shè)一臺(tái)全景相機(jī),在場(chǎng)景中表現(xiàn)為一個(gè)長(zhǎng)方體媒鼓, 長(zhǎng)方體的每個(gè)面都會(huì)拍攝它正前方的場(chǎng)景圖像 届吁, 這樣就以相機(jī)為中心错妖,就能獲取到它上、下疚沐、前暂氯、后、左亮蛔、右六個(gè)方向的圖像痴施, 這六張圖片會(huì)被存儲(chǔ)為一個(gè)立方體貼圖(CubeMap),提供給具有反射材質(zhì)的物體使用究流。
設(shè)置
unity中新建立方體貼圖有兩種方法:第一種是將hdr格式的全景圖片導(dǎo)入項(xiàng)目中晾剖,設(shè)置圖片的Texture Shape 為cube,這種方式是最方便快捷的梯嗽。
第二種使用一種最古老的方式:create/Legacy/Cubemap齿尽,這種方式需要準(zhǔn)備六張同一位置不同方向角度(前后、上下灯节、左右)的圖片循头,指定后unity會(huì)為自動(dòng)生成一張立方體貼圖。
采樣
環(huán)境貼圖的采樣過(guò)程也很好理解炎疆,一束光照射到物體表面時(shí)會(huì)產(chǎn)生反射卡骂,反射光線(xiàn)會(huì)與立方體的其中一個(gè)面產(chǎn)生一個(gè)交點(diǎn),只需要對(duì)這個(gè)交點(diǎn)進(jìn)行采樣形入,就能得到頂點(diǎn)的顏色像素值全跨。
立方體貼圖有六個(gè)面,首先需要判斷頂點(diǎn)的反射光線(xiàn)與哪個(gè)面相交亿遂,這個(gè)判斷方法非常簡(jiǎn)單:頂點(diǎn)坐標(biāo)哪個(gè)分量的絕對(duì)值最大浓若,頂點(diǎn)反射光就與哪個(gè)面相交。
比如頂點(diǎn)坐標(biāo)V(-0.5,0.3,-0.1)蛇数,分量絕對(duì)值最大是-5挪钓,因此這個(gè)頂點(diǎn)的反射光與-x指向的面相交。
知道了相交面耳舅,下一步就是求相交點(diǎn)碌上,相交面標(biāo)準(zhǔn)化,它的其中一個(gè)面的分量值是確定的浦徊。比如馏予,立方體貼圖-x軸指向的面,它的x軸坐標(biāo)是-1盔性,那么只要讓反射矢量的坐標(biāo)乘以某個(gè)標(biāo)量霞丧,讓矢量的x分量也等于-1,矢量的yz分量就是交點(diǎn)的yz值纯出。
舉個(gè)例子反射矢量是(-0.5,0.3,-0.1)蚯妇,乘以2后等于(-1,0.6,-0.2)敷燎,那么相交點(diǎn)的坐標(biāo)就是(-1,0.6,-0.2)。
由于立方體貼圖采樣只關(guān)注方向而忽略了位置箩言,因此它在平坦反射表面上的效果很不真實(shí)硬贯,相對(duì)的,它在曲面上可以取得較好的視覺(jué)效果陨收。
代碼
下面就來(lái)看看在代碼中如何實(shí)現(xiàn)立方體貼圖的采樣饭豹。根據(jù)采樣原理的理解,要獲取到頂點(diǎn)的切線(xiàn)空間坐標(biāo)务漩、光源方向拄衰、法線(xiàn)方向和反射方向。具體代碼如下:
half3 normal_dir = normalize(i.normal_world);
half3 normalData = UnpackNormal(tex2D(_NormalMap,i.uv));
//切線(xiàn)方向
half3 tangent_dir = normalize(i.tangent_world);
// 雙切線(xiàn)方向
half3 binormal_dir = normalize(i.binormal_world);
// 法線(xiàn)方向
normal_dir = normalize(tangent_dir * normalData.x + binormal_dir * normalData.y + normal_dir*normalData.z);
// 觀(guān)察方向
half3 view_dir = normalize(_WorldSpaceCameraPos.xyz - i.pos_world);
// 反射方向
half3 reflect_dir = reflect(-view_dir, normal_dir);
得到反射方向后饵骨,直接使用texCUBE方法翘悉,傳入反射矢量,對(duì)貼圖進(jìn)行采樣
// properties
_CubeMap("Cube Map", Cube) = "white"{}
//var
samplerCUBE _CubeMap;
float4 _CubeMap_HDR;
//frag
half4 colorCubeMap = texCUBE(_CubeMap,reflect_dir);
half3 env_color = DecodeHDR(colorCubeMap,_CubeMap_HDR);
通過(guò)以上兩步居触,基本能實(shí)現(xiàn)對(duì)立方體貼圖采樣的功能妖混。
立方體貼圖擁有豐富的顏色細(xì)節(jié),直接采樣產(chǎn)生的效果可能會(huì)過(guò)曝轮洋,因此通常會(huì)配合Bloom 制市、ACES ToneMapping等后期技術(shù)來(lái)使用。
反射探針
講了這么多立方體貼圖底層技術(shù)的實(shí)現(xiàn)弊予,但實(shí)際項(xiàng)目中可能并不需要我們這么做祥楣。在Unity項(xiàng)目中,我們可以為物體添加反射探針(ReflectionProbe)來(lái)實(shí)現(xiàn)物體的反射效果汉柒,反射探針就是根據(jù)立方體貼圖的技術(shù)原理封裝而成的误褪。
默認(rèn)情況下,Unity設(shè)置了一個(gè)全局反射探針竭翠,我們只需要在window-rendering-light這里點(diǎn)擊"Generate Lighting"振坚,項(xiàng)目就會(huì)自動(dòng)烘焙一張?zhí)炜蘸凶拥牧⒎襟w貼圖保存在場(chǎng)景目錄下
可在Environment中調(diào)節(jié)全局反射探針的效果。
另外斋扰,也可以"右鍵/light/reflection Probe"中添加局部反射探針,點(diǎn)擊Bake啃洋,此時(shí)反射探針會(huì)自動(dòng)生成一個(gè)天空盒子的環(huán)境貼圖传货。
但此時(shí),反射探針并不能反射周?chē)渌矬w宏娄,如果要反射其他物體问裕,那么其他物體需要勾選“reflection Probe Statics”,然后重新Bake
在優(yōu)先級(jí)上孵坚,局部反射探針的優(yōu)先級(jí)別要高于全局反射探針粮宛。