如何在Unity中自定义光源,包含URP管线和Build in 管线(一)

众所周知,光照在游戏画面效果上占了很大比例,一个游戏画面好不好,用最简单的理解来说,就是看游戏画面亮不亮,当然这个亮不是不是直接曝光那种刺眼的白,具体的可以参考下刺客信条奥德赛,只狼。废话不多说了,因为我也是菜鸟,只知道一个全局光照计算(GI)方式会影响ta,写个帖子,也是为了学习和记录一下独立开发的一些过程(大佬们轻点喷,欢迎指点江山,真的很需要你们的指引)。

点光源的核心:光衰减公式: float atten = 1.0 / (a1 + a2 * fDistance + pow(a3, 2) * fDistance);

fDistance=顶点世界坐标到光源的距离。

Build In管线

我们先创建一个shader 头文件 Cginc或者Hlsl 都可以 至于为啥是头文件,就可能需要你百度一下了,现在的shader 代码 更偏向于面向对象的思路,使用头文件,大大提高复用性,你总不想每个shader中要这个效果,就复制一遍代码过去把!可以理解为编程里面的一些静态方法,可以给其他的脚本使用。

1.自定义光照肯定不太可能只有一盏灯,所以初始化的数据结构一定要想好。(上述衰减公式参考的龙书,有兴趣可以去看看,我英语太差,看得太慢了,可以说是直接面向有道编程。)

2.参考的公式需要四个变量,对光衰减进行计算,那么我们就知道该怎么去声明数据结构了。首先是距离,要知道距离,我们需要两个参数,一个顶点世界坐标,一个光源坐标,顶点世界坐标我们可以在shader中计算,光源坐标就需要我们代码自定义传入了,所以第一个变量声明就是 float4 PointLightPos,对吗?。。。答案是可对可不对,如果你只想自定义增加一个点光,当然可以,但之前说过不太可能只是一盏灯,所以这样声明又是不太正确的,因为这样命名如果以后要加一盏灯 你就需要再声明一个变量float4 PointLightPos+n 其他的参数也是这样,这样的编码习惯是非常不便以后维护的。我们一般会是用数组来储存和接收这些信息,在shader中声明数组一定考虑以后的扩张范围,例如我最多要11盏灯,那我需要声明的数组就应该是vector4 PointLightPos [10]。ok 现在我们知道如何声明变量,接着把剩下的变量也提取出来。a1,a2,a3 为三个float 为了方便使用,这里也可以用float4 FAttenuationValues [10] 虽然会浪费一维的值,个人认为要比三个float[10] 方便点,具体使用看个人吧,性能我倒是没有去对比测试。到这里公式的变量我们已经提取完成了,我们回想一下,一个点光最大的属性我们还没有声明吧,所以我们还需要一个float4 PointLightColors [10] 来接受光的颜色。ok 头文件的变量我们暂时已经搞定了,我们该写计算函数了。

3.计算函数我们也是写作头文件中,方便调用。之前的距离计算需要一个顶点世界坐标,我们在头文件里面无法直接获取每个shader实例中的顶点信息,所以我们需要通过传值的方式,从外部获取需要的参数,大概样子下图这样。index 我们用来指定获取某一盏灯的信息,worldNormal 有基础的童鞋一定知道啦,就是用来做背面剔除的啦,防止光穿透到背面去了,当然这也是一个效果,根据需求变换吧。

unity自发光shader unity自发光 urp_unity3d

4,计算方法我们已经写好了,现在去shader中,应用就ok了,直接看代码吧!

unity自发光shader unity自发光 urp_unity3d_02

最终效果:

unity自发光shader unity自发光 urp_unity3d_03

Unity自定义点光Shader 这边暂时就是这些了!有经验的童鞋应该知道怎么去改进和实现了,欢迎大家指出不足,共同进步,下一期我还是会写关于C#端如何与shader端关联的事项的。喜欢能帮到你们一点。