模型
我們可以明顯看到眼球前方有一個凸起的部位嘿棘,包含了角膜房水等結構劲腿,因此在建模時需要體現(xiàn)出這一效果。
UV映射直接采用了Y軸平面映射鸟妙。
虹膜大小調(diào)整
這里將模型自帶的UV首先轉(zhuǎn)換成關于原點中心對稱焦人,比較方便計算挥吵。然后將UV到原點長度大于設定值的返回鞏膜顏色,小于設定值的我們做虹膜的渲染垃瞧,并且使用一個新的UV(虹膜邊緣UV長度為0.5蔫劣,中心依然為原點)方便之后的計算。
float2 sUV = i.uv - float2(0.5, 0.5);
float2 sUVIris = sUV / _IrisRadius / 2;
虹膜視差效果
由于虹膜和瞳孔的部分是處于角膜下一定距離个从,并且房水和角膜作為介質(zhì)有一定的的折射率脉幢,因此這里我們需要引入一個視差效果來給予眼球立體感。
我將所有的計算首先轉(zhuǎn)換到模型空間下嗦锐。這里如果將虹膜視為一個平面嫌松,(模型采用平面投影UV,不過此處為了讓計算更簡單一點采用表面法線和虹膜平面的交點作為原UV)我們可以得到如下的光路圖:
只要求得了偏移量x以及偏移方向奕污,我們就能得到偏移后的UV萎羔,使用此UV采樣貼圖就可得到折射后產(chǎn)生的視差效果。
具體計算方式是:
在有些情況下這里的UpR可能成為一個負值碳默,不過最終我們得到的偏移量是一個標量贾陷,這個矯正需要用偏移方向向量來做。至于式子中的d嘱根,可以用一個高度紋理采樣髓废,越靠近虹膜邊緣處折射越小,我這里是在shader里直接計算了球面減去平面的高度差该抒。
float cosUpN = dot(objectNormal, float3(0,1,0));
float sinUpN = sqrt(1 - cosUpN * cosUpN);
float cosVN = dot(objectNormal, objectViewDir);
float sinVN = sqrt(1 - cosVN * cosVN);
float sinRN = sinVN / _IOR;
float cosRN = sqrt(1 - sinRN * sinRN);
float cosUpR = sinUpN * sinRN + cosUpN * cosRN;
float2 sUVIris = sUV / _IrisRadius / 2;
float d1 = sqrt(1 - sUVIris.x * sUVIris.x - sUVIris.y * sUVIris.y) - 0.86603;
float d2 = sqrt(0.3025 - sUVIris.x * sUVIris.x - sUVIris.y * sUVIris.y) - 0.22913;
float2 deltaUV = _Distortion * (d2 - d1) * sinRN / cosUpR * uvDirection;
一開始我直接將偏移方向設定為視線方向在虹膜平面上的投影方向向量慌洪,不過這實際上是不對的,因為實際偏移方向也是和眼球表面法線相關的凑保。
如圖所示冈爹,圖中偏移方向應該向左,然而視線在平面上的投影是向右的欧引。這個問題花費了我不少時間排除……最終我使用的計算方式是:
float3 T = cross(objectViewDir,objectNormal);
float3 D = cross(float3(0,1,0),T);
float2 uvDirection = float2(D.x,D.z);
這里采用了叉乘的方式矯正了VN空間關系導致的UV偏移方向反轉(zhuǎn)频伤。
使用得到的偏移量乘以偏移方向作為UVOffset,就能夠產(chǎn)生比較令人信服的折射效果芝此。
最后我們會得到一些虹膜紋理并不存在的UV(UV長度大于0.5)憋肖,于是我們還要引入一張虹膜的遮罩mask讓這些片段去采樣鞏膜紋理,以形成自然過渡的虹膜邊緣癌蓖。
瞳孔大小調(diào)節(jié)
我們需要對偏移后的虹膜UV做一定的remap處理達到這個效果瞬哼。首先求UV到原點的長度,以及方向向量租副,然后經(jīng)過一定對長度的處理得到一個新的長度坐慰,乘回方向向量就是我們要的原始UV數(shù)據(jù)。
float2 RemapUV(float2 uv)
{
float lengthUV = length(uv);
float2 uvNormalized = uv / lengthUV ;
float newLength = 0;
if (lengthUV < _PupilRadius)
{
newLength = lengthUV / _PupilRadius * 0.14;
} else
{
newLength = (lengthUV - _PupilRadius) / (0.5 - _PupilRadius) * 0.36 + 0.14;
}
return uvNormalized * newLength;
}
上一段代碼中的0.14是原始紋理中瞳孔的半徑,這和我們采用的虹膜紋理有關结胀,需要手動調(diào)節(jié)赞咙。
高光
這個沒什么好說的,我目前只簡單的在Base Pass和Add Pass中寫了Phong高光公式糟港。