遊戲中往往需要多個光源來提升場景的真實感

  • 火把
  • 技能
  • 室內燈光
  • 燈塔

Unity中自帶的點光源存在一些問題

  • 最多只能支持4個像素光
  • 烘培的物件必須通過addpass才能接收點光源,性能太低,多一個點光,範圍稍大cpu和gpu的開銷就瘋狂上升
  • 動態物件走的是頂點光照,不能使用normalmap,效果一般
  • unity移動端上一般不使用延遲渲染,forward+什麼的也暫不考慮,所以我們就打算自己實現一套點光源和聚光燈

首先我們要使用新的光源系統,就需要把舊的光源系統屏蔽,把sh部分的代碼都刪了,把addpass的代碼都刪了,前提是必須用vf寫shader,不能用surf

我們需要一個點光源的計算公式,參數如下

  • 頂點normal
  • 頂點worldPos
  • 光源pos
  • 光源range
  • 光源idensity
  • 光源color

聚光燈額外有

  • 光源angle
  • 光源direction

點光源核心衰減公式

fixed atten = pow(((pow(PointLightRange, 2) - pow(fDistance, 2)) / pow(PointLightRange, 2)), 2) * pow(PointLightIntensity/2,3);

PointLightRange是光源範圍

fDistance是worldPos到光源的距離

pointLightIndensity是光源強度

聚光燈其實只是在點光源的基礎上約束了一下範圍(注意, 這裡僅是模擬, 很難做到完全和原生的一樣, 原生的聚光燈是基於LUT的)

float3 vecLP = normalize(worldPos - PointLightPos);
float dotLP = dot(normalize(SpotLightForward), vecLP);
float radiusOffset = SpotLightAngle * 3.1415926 / 180 - acos(dotLP);
if (radiusOffset < 0)
{
atten = 0 ;
}
else
{
atten *= radiusOffset;
}

然後在shader裡面封裝一個pointlight和spotlight介面,傳入normal和worldpos就可以了,這樣在各個shader中都可以用了,能做到通用, 直接把代碼調用加在平行光的計算shader中就OK了

c#層主要做一個給shader傳參數的管理器就ok了

由於是項目功能, 具體的完整的代碼就不給出了, 效果就是文章開頭的效果

說到底技術上並沒有什麼突破, 只是在移動端的一種提升性能的trick.

推薦閱讀:

相关文章