陳翔宇
(華東師范大學(xué) 計算機科學(xué)與技術(shù)學(xué)院,上海200333)
Unity是實時3D互動內(nèi)容創(chuàng)作和運營平臺。包括游戲開發(fā)、美術(shù)、建筑、汽車設(shè)計、影視在內(nèi)的所有創(chuàng)作者,借助Unity將創(chuàng)意變成現(xiàn)實[1]。Unity平臺提供一整套完善的軟件解決方案,可用于創(chuàng)作、運營和變現(xiàn)任何實時互動的2D 和3D 內(nèi)容,支持包括手機、平板電腦、PC、游戲主機、增強現(xiàn)實和虛擬現(xiàn)實設(shè)備,同時支持Windows、Android和Mac等多平臺[2]。
Unity3D 開發(fā)相比于其他游戲引擎,有更多優(yōu)勢特點:1) 支持多種格式導(dǎo)入:整合多種DCC文件格式,包含3dsMax、Maya、Lightwave、Collade 等文檔,可直接拖拽到Unity中,除原有內(nèi)容外,還包含Mesh、多UVs、Vertex、Colors、骨骼動畫等功能,提升游戲制作的資源應(yīng)用[3]。2) 逼真的粒子系統(tǒng):Unity 開發(fā)的游戲可以達到難以置信的運行速度,在良好硬件設(shè)備下,每秒可以運算數(shù)百萬面以上的多邊形。高質(zhì)量的粒子系統(tǒng),內(nèi)置的Shuriken 粒子系統(tǒng),可以控制粒子顏色、大小及粒子運動軌跡,可以快速創(chuàng)建下雨、火焰、灰塵、爆炸、煙花等效果。3) 支持外源制作的各種插件,導(dǎo)入Unity 后方便制作者使用。4) 支持多平臺發(fā)布:Unity3D 游戲開發(fā)支持的平臺,無疑是當(dāng)下較為流行的平臺,滿足絕大部分項目需求。早期的引擎,多以PC 和CONSOLE 為主[4],同時支持了Windows、XBOX、PS2 等平臺。U3D 便利的多平臺發(fā)布特性,也是它成為當(dāng)前性價比最高的引擎的原因之一。5) AssetStore商店提供了大量的資源,使U3D的生態(tài)圈更加穩(wěn)固[5]。用戶可以制作插件網(wǎng)上售賣,賺取一些利益,也可以購買別人的插件,作為使用或者參考。有時候,購買一些插件,可以讓用戶快速脫離當(dāng)前的困境,一個是解決進度問題,一個是解決思路問題,這是之前其他引擎不具備的。
Shader 是運行在GPU 上可編程的圖形程序,在Unity 中可以使用Cg/HLSL 語言編寫頂點著色器和片元著色器。頂點著色器和片元著色器被分離為可編程的單元,兩者都擁有強大的并行計算能力,擅長于矩陣計算(不高于四階),片元著色器可以高速查詢紋理數(shù)據(jù)信息,但頂點著色器不行[6]。頂點著色器(Vert)負責(zé)處理頂點坐標(biāo)轉(zhuǎn)換信息,片元著色器(Frag)負責(zé)處理像素顏色數(shù)據(jù)計算信息,且前者的輸出是后者的輸入。頂點著色程序從GPU 前端模塊(寄存器)中提取圖元信息(頂點位置、法向量、紋理坐標(biāo)等),并完成頂點坐標(biāo)空間轉(zhuǎn)換、法向量空間轉(zhuǎn)換、光照計算等操作,最后將計算好的數(shù)據(jù)傳送到指定寄存器中;然后片元著色程序從中獲取需要的數(shù)據(jù),通常為紋理坐標(biāo)、光照信息等,并根據(jù)這些信息以及從應(yīng)用程序傳遞的紋理信息(如果有)進行每個片元的顏色計算,最后將處理后的數(shù)據(jù)送光柵操作模塊[7]。片元著色程序?qū)γ總€片元進行獨立的顏色計算,最后輸出顏色值的就是該片段最終顯示的顏色,具體渲染流程見圖1。
圖1 Shader渲染流程
ShaderLab 開發(fā)是Unity 內(nèi)置的一段Shader 代碼,在Unity 中賦予材質(zhì)上的Shader 著色器進而實現(xiàn)效果。內(nèi)部結(jié)構(gòu)偏復(fù)雜,詳細闡述易于理解。
1) Properties{}:Properties的{}內(nèi)是定義著色器的相關(guān)屬性,輸入的屬性會呈現(xiàn)在Unity平臺內(nèi)Material下的Inspector 面板下供調(diào)試,定義格式為_Name(“Inspector Name”,type)=Value[option}],其中_Name 表示屬性名,有_NormalMap、_MainTex、_Color、_BumpScale等?!盜nspector Name”代表在Inspector面板下顯示的屬性名?!癟ype”則是屬性類型(Vector、Float、Range(min,max)、Cube、Rect、2D、Color等);Properties面板見圖2。
圖2 Shader下Properties面板
2) SubShader{},SubShader 是子Shader,可以有多個,運行效果時,從第一個SubShader開始[8],如果第一個SubShader的效果都可以實現(xiàn),就使用第一個,如果不可以,就會自動運行下一個SubShader,直到最后的Fallback回滾;
3) pass 塊,隸屬于SubShader 中,一個pass 塊相當(dāng)于一個方法,在它內(nèi)部的CGPROGRAM 至ENDCG 區(qū)域編寫Shaderlab代碼;
4) CGPROGRAM 到ENDCG 部分,這個區(qū)域是Shaderlab 代碼的核心內(nèi)容,必須將屬性塊Properties里需要的屬性值重新定義一遍。區(qū)域的主要內(nèi)容再細分為:①#pragram vertex vert,聲明頂點函數(shù),頂點函數(shù)名為vert,它的基本作用是完成頂點坐標(biāo)從模型空間到剪裁空間的轉(zhuǎn)換(從游戲環(huán)境轉(zhuǎn)換到視野相機屏幕上)。②#pragram fragment frag,聲明片元函數(shù),它的基本作用是返回模型對應(yīng)的屏幕上每一個像素的顏色值[9]。③struct a2v,從應(yīng)用程序傳遞到頂點函數(shù)的結(jié)構(gòu)體。④struct v2f,從頂點函數(shù)傳遞給片元函數(shù)的結(jié)構(gòu)體。⑤v2f vert(a2v v),即頂點函數(shù),內(nèi)部書寫從模型空間轉(zhuǎn)換到剪裁空間的代碼,比如法線、頂點坐標(biāo)、紋理坐標(biāo)等。⑥frag(v2f f),即片元函數(shù),內(nèi)部實現(xiàn)從剪裁空間返回到Unity世界空間的像素值。
當(dāng)前游戲的邏輯模式已經(jīng)完成,原人物角色模型見圖3。本文的主要需求是運用Shaderlab 將場景內(nèi)游戲角色的服裝加上光束的特效以及高光反射的效果,令人物角色在場景中擁有更出色的3D外觀表現(xiàn)。
圖3 場景下原人物角色模型
在游戲場景中,為了給人物角色添加特殊的光束效果,本文創(chuàng)新地采用光照融合疊加原理。
1) 漫反射公式:Diffuse=_LightColor0.rgb*max(dot(normalDir,lightDir),0);
其中,直射光_LightColor0 表示Unity 內(nèi)置環(huán)境光(平行光),其后加上.rgb 則代表的是直射光的顏色值。需要在注入“Lighting.cginc”的條件下再調(diào)出。Max(,)函數(shù)取最大值,dot(,)函數(shù)來進行點乘運算,此處在漫反射公式內(nèi)則是求|normalDir|*|lightDir|*cos<normalDir,LightDir>的乘積值。normalDir 表示法向量的單位向量,lightDir代表入射光方向的單位向量。
2) 高光反射公式:specular=_LightColor.rgb*pow(max(dot(normalDir,halfDir),0),_Gloss)。
公式內(nèi)Pow(a,b) 函數(shù)計算的是ab的值,_Gloss表示的是高光參數(shù)值,值的大小和高光反射的區(qū)域大小成反比。這里的halfDir 是由viewDir(觀察方向單位向量)和lightDir(入射光方向單位向量)的疊加單位向量。
3) 矩陣轉(zhuǎn)換算法:對于頂點從模型空間下坐標(biāo)轉(zhuǎn)換到世界空間的坐標(biāo),需要用到四維矩陣轉(zhuǎn)換,其代碼行為 f.vertex=mul(v.vertex,unity_ObjectToWorld);通過mul 函數(shù)將模型空間下的模型頂點坐標(biāo)v.vertex 作為行向量,與四維矩陣unity_ObjectToWorld 進行乘積,獲得剪裁空間下的模型頂點坐標(biāo)f.vertex[10]。
4) 透明度alpha 值:alpha=min(1,abs(((bottom+top)/2-i.uv.x*tan(_lightAngle))-i.uv.y)/(Length/2));
這一值是實現(xiàn)人物角色自發(fā)光的重點之處,min(,)函數(shù)取括號內(nèi)兩數(shù)之間最小值,abs()函數(shù)取括號內(nèi)數(shù)值的絕對值,tan()函數(shù)求_LightAngle(閃光角度)的正切值,隨后和i.uv.x(紋理坐標(biāo)的X分量)一起計算得出透明度alpha值。
物體角色模型在導(dǎo)入Unity場景時已配有紋理貼圖,對于光束效果來說區(qū)分為逐頂點和逐像素的效果追求。在如3dsMax、Maya等三維模型的繪制中,模型是由無數(shù)個三角形面組成。一個三角形的面是由三條線和三個頂點拼接而成,逐頂點會取三個頂點間的插值來緩和過渡顏色差。而逐像素則是計算每個像素點的精確值后再繪制在世界空間中,圖像上的處理會更精細但相比逐頂點會消耗更多的資源性能。本文中的兩個光束效果都是以逐像素為核心,通過改變片元函數(shù)中像素值來達到特定的效果。
屬性Properties中已經(jīng)定義了_MainTex(主貼圖),2D 類型且默認值為白色,在SubShader 的pass 塊內(nèi)的CGPROGRAM~ENDCG段進行了Sample2D _MainTex的再定義。整體Shaderlab的局部片元函數(shù)代碼如下:
通過(1) 處的Shaderlab 內(nèi)置tex2D 函數(shù)傳入?yún)?shù)_MainTex以及剪裁空間下的f.uv參數(shù),再賦給col,獲得col 的初始顏色值。(2) 處定義一個float 類型的alpha值,通過min 函數(shù)取得每個紋理采樣點之間的最小值再賦予alpha。在(3) 處通過返回系數(shù)為(1-alpha)的RGB 為(0.5,0.5,0.5)的顏色值和系數(shù)為alpha 的紋理顏色值,再與屬性Properties 中已定義的_Color(閃光顏色)進行加法疊加,再賦予col,最后再返還給世界空間下的像素值,實現(xiàn)了人物角色自發(fā)光的特效。
經(jīng)過Shaderlab 代碼的初始區(qū)域的結(jié)構(gòu)體定義以及頂點函數(shù)轉(zhuǎn)換獲取到了f.worldnormal(世界空間下法線)、f.worldvertex(世界空間下頂點)、_MainTex(主貼圖)等。整體Shaderlab的局部片元函數(shù)代碼如下:
(1) 將f.worldnormal 通過normalize 函數(shù)來單位化獲得世界下法線的單位向量(normalDir) 。(2) 將f.worldvertex經(jīng)過世界空間下入射光方向的函數(shù)World-SpaceLightDir 轉(zhuǎn)換來獲取世界空間下每個點對應(yīng)的入射光方向的單位向量(lightDir) 。計算漫反射顏色值見(3)經(jīng)過dot點乘計算出每個點的世界法線向量和入射光方向的cos余弦值,再和0相比較取最大值,再乘以環(huán)境光的顏色值(_LightColor0.rgb) 以及紋理顏色值(texColor) 來得到最終的漫射光顏色值(diffuse) 。(4) 計算視角方向(即攝像機方向),高光反射的重點就在于視角方向。因為人觀察事物某個頂點區(qū)域從不同的角度會有不同的反射效果。將f.worldvertex 傳入世界空間下觀察方向函數(shù)UnityWorldSpaceViewDir 的轉(zhuǎn)換后再通過normalize 函數(shù)單位化后獲得世界空間下的單位視角方向向量。(5) 以局部變量halfDir(半融合向量)接受了經(jīng)過視角方向和入射光方向的疊加后的單位化向量值。(6)隨后以normalDir(世界法線單位向量)和halfDir(半融合單位向量)的點乘余弦值和0比較后的最大值作為pow函數(shù)的底數(shù),再以_Gloss(高光參數(shù))作為函數(shù)的冥次方計算得值,隨后將得到的值和環(huán)境光顏色以及高光顏色值做乘法融合。這里的顏色值之間的乘法融合相比加法疊加會有更少量化值的影響。(7) 最后,將漫射光顏色值(diffuse) 、高光顏色值(specular)、環(huán)境光顏色值(UNITY_LIGHTMODEL_AMBIENT) 與紋理顏色值(texColor)的乘法融合值再相加,最后再返還給世界空間下的像素值,實現(xiàn)了人物角色面部高光反射的特效。
對應(yīng)Unity 場景,在Shaderlab 中對人物角色的自發(fā)光RGB值進行多次更改后,顏色值呈正常相關(guān)變化,主要表現(xiàn)為人物模型保持為紋理原色,但自發(fā)光的顏色會受RGB值的影響,測試結(jié)果見表1。
表1 自發(fā)光測試結(jié)果統(tǒng)計
人物角色面部的高光會受到高光顏色值的直接影響,但主要是由高光參數(shù)決定面部的光澤效果。在實際應(yīng)用中,高光參數(shù)區(qū)域的大小會和高光參數(shù)的值成反比,測試結(jié)果見表2。
表2 高光測試結(jié)果統(tǒng)計
由于對人物角色模型添加了自發(fā)光的Shaderlab,可以看到衣服模型自上向下會有呈周期性變化的閃爍光芒效果,模型的紋理原圖會作為底層紋理與自發(fā)光相互融合產(chǎn)生不錯的特效,具體效果見圖4。
圖4 場景下附加自發(fā)光效果后人物角色模型
相比圖3 的原人物模型,可以發(fā)現(xiàn)人物面部色彩更細膩,面部輪廓也有了明顯的光澤,整體給用戶呈現(xiàn)出了一個更精氣神的角色,Unity場景中展示見圖5。
圖5 場景下附加高光效果后人物角色模型
同時可以調(diào)整場景內(nèi)的渲染顯示質(zhì)量。在菜單欄下Edit 的Project Setting 的Quality 面板進行設(shè)置 ,Pixel Light Count像素?zé)魯?shù)量取標(biāo)準(zhǔn)值4,Texture Quality 紋理質(zhì)量取Full Res(完整分辨率),Shadow Distance 陰影距離值取50,超過這個距離陰影將不會被顯示。這樣可以將渲染的性能開到一個很高的級別,同時也保證了渲染效率的穩(wěn)定,詳細設(shè)置可見圖6。
圖6 渲染顯示Quality設(shè)置
將自發(fā)光和高光效果共同施加在人物角色模型上,呈現(xiàn)在Unity場景中的效果見圖7。
圖7 兩種效果共同附加后人物角色模型
在日常游戲開發(fā)中,不僅看重游戲的可玩程度和邏輯性,也越來越重視游戲的場景特效和三維模型特效。Shader 著色器的應(yīng)運而生為此提供了充分的擴展性,本文通過Unity3D 和Shader 的結(jié)合實現(xiàn)了用戶想要的效果,通過自發(fā)光測試和高光測試也驗證了效果的可行性。在今后的開發(fā)中,不應(yīng)止步于此,還可以通過Shaderlab來書寫各種各樣的渲染特效,與場景搭配融合出令用戶驚嘆贊絕、美輪美奐的游戲畫面。