游戏中往往需要多个光源来提升场景的真实感

  • 火把
  • 技能
  • 室内灯光
  • 灯塔

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.

推荐阅读:

相关文章