文章目录
- 前言
- 一、额外灯中聚光灯的角度衰减
- 二、AngleAttenuation函数的传入参数
- 1、参数:spotDirection.xyz
- 2、_AdditionalLightsSpotDir
- 3、参数:lightDirection
- 4、参数:distanceAndSpotAttenuation.zw
- 5、_AdditionalLightsAttenuation
- 三、AngleAttenuation函数的程序体
- 1、我们先来看一下SdotL的结果
- 2、cosOuterAngle:聚光灯外圈与聚光灯夹角的余弦值
- 3、cosInnerAngle:聚光灯内圈与聚光灯夹角角的余弦值
- 4、最后,就可以使用公式来计算了
- 5、但是,我们在程序体中,看见的却是这样一句话
- 6、最终、Unity还对其做了平方处理,目的是加强角度衰减效果
前言
在上一篇文章中,我们推导了URP下额外灯的距离衰减。
- Unity中URP下额外灯的距离衰减
在这篇文章中,我们推导一下URP下额外灯的角度衰减。角度衰减只有在聚光灯中才有用。
一、额外灯中聚光灯的角度衰减
- 衰减包括:距离衰减 和 角度衰减
- 我们这篇文章主要分析 角度衰减,角度衰减是聚光灯独有的。
AngleAttenuation1(spotDirection.xyz, lightDirection, distanceAndSpotAttenuation.zw);
二、AngleAttenuation函数的传入参数
- 调用
AngleAttenuation1(spotDirection.xyz, lightDirection, distanceAndSpotAttenuation.zw);
1、参数:spotDirection.xyz
-
该参数是通过内置变量获取的
-
该内置变量是C#提前计算好的
2、_AdditionalLightsSpotDir
- 我们来看一下C#中怎么计算得出该参数
- 一开始会赋值一个聚光灯方向默认值
- k_DefaultLightSpotDirection,默认值为(0,0,1,0)
- 非平行灯下,在对距离衰减修改后,还会判断是否是聚光灯
- 是聚光灯,则会修改聚光灯方向的默认值
- 修改时,会获取聚光灯方向,并对其取反
3、参数:lightDirection
- 之前计算出的,额外光方向的单位向量
4、参数:distanceAndSpotAttenuation.zw
- 该参数是读取的内置参数
- 该内置变量是C#提前计算好的
5、_AdditionalLightsAttenuation
- 我们来看一下C#中,怎么计算该参数
三、AngleAttenuation函数的程序体
-
角度衰减公式: a n g l e A t t e n u a t i o n = S d o t L − c o s O u t e r A n g l e c o s I n n e r A n g l e − c o s O u t e r A n g l e angleAttenuation=\frac{SdotL - cosOuterAngle} {cosInnerAngle - cosOuterAngle} angleAttenuation=cosInnerAngle−cosOuterAngleSdotL−cosOuterAngle
-
我们先看一下这些参数分别代表什么
-
SdotL:S(聚光灯方向的相反方向)点积 L(指向聚光灯方向单位向量)
-
cosOuterAngle:聚光灯外圈与聚光灯夹角的余弦值
-
cosInnerAngle :聚光灯内圈与聚光灯夹角角的余弦值
1、我们先来看一下SdotL的结果
- 我们可以看出目标点越靠近聚光灯中心,我们的结果越趋向 1,则越亮
2、cosOuterAngle:聚光灯外圈与聚光灯夹角的余弦值
- C#中提前把角度取Unity传入的一半,然后转弧度,再计算余弦值
- 取一半的原因是,我们传入的值是需要的角的两倍
3、cosInnerAngle:聚光灯内圈与聚光灯夹角角的余弦值
- C#中提前把角度取Unity传入的一半,然后转弧度,再计算余弦值
- 取一半的原因是,我们传入的值是需要的角的两倍
- 我们主要看非特效情况下
4、最后,就可以使用公式来计算了
-
角度衰减公式: a n g l e A t t e n u a t i o n = S d o t L − c o s O u t e r A n g l e c o s I n n e r A n g l e − c o s O u t e r A n g l e angleAttenuation=\frac{SdotL - cosOuterAngle} {cosInnerAngle - cosOuterAngle} angleAttenuation=cosInnerAngle−cosOuterAngleSdotL−cosOuterAngle
-
该公式其实只是起到了 平滑曲线过渡的作用
-
该公式的作用:限制最后余弦值的结果,还达到了平滑过渡的效果
-
当 targetPos 夹角大于 outerDir 的夹角时,余弦值反而小了,则取outerDir夹角余弦值来替代
-
当 targetPos 夹角小于 innerDir 的夹角时,余弦值反而大了,则取innerDir夹角余弦值来替代
5、但是,我们在程序体中,看见的却是这样一句话
- 原因在于,这是Unity为了节省性能,对该公式进行了化简
a n g l e A t t e n u a t i o n = S d o t L − c o s O u t e r A n g l e c o s I n n e r A n g l e − c o s O u t e r A n g l e angleAttenuation=\frac{SdotL - cosOuterAngle} {cosInnerAngle - cosOuterAngle} angleAttenuation=cosInnerAngle−cosOuterAngleSdotL−cosOuterAngle
= S d o t L c o s I n n e r A n g l e − c o s O u t e r A n g l e − c o s O u t e r A n g l e c o s I n n e r A n g l e − c o s O u t e r A n g l e =\frac{SdotL } {cosInnerAngle - cosOuterAngle}-\frac{cosOuterAngle} {cosInnerAngle - cosOuterAngle} =cosInnerAngle−cosOuterAngleSdotL−cosInnerAngle−cosOuterAnglecosOuterAngle
= S d o t L ∗ 1 c o s I n n e r A n g l e − c o s O u t e r A n g l e + − c o s O u t e r A n g l e c o s I n n e r A n g l e − c o s O u t e r A n g l e =SdotL*\frac{1} {cosInnerAngle - cosOuterAngle}+\frac{-cosOuterAngle} {cosInnerAngle - cosOuterAngle} =SdotL∗cosInnerAngle−cosOuterAngle1+cosInnerAngle−cosOuterAngle−cosOuterAngle
- Unity在C#中,对其提前进行了计算
- 使 d i s t a n c e A n d S p o t A t t e n u a t i o n . z = 1 c o s I n n e r A n g l e − c o s O u t e r A n g l e distanceAndSpotAttenuation.z=\frac{1} {cosInnerAngle - cosOuterAngle} distanceAndSpotAttenuation.z=cosInnerAngle−cosOuterAngle1
- 使 d i s t a n c e A n d S p o t A t t e n u a t i o n . w = − c o s O u t e r A n g l e c o s I n n e r A n g l e − c o s O u t e r A n g l e distanceAndSpotAttenuation.w =\frac{-cosOuterAngle} {cosInnerAngle - cosOuterAngle} distanceAndSpotAttenuation.w=cosInnerAngle−cosOuterAngle−cosOuterAngle
6、最终、Unity还对其做了平方处理,目的是加强角度衰减效果
return atten * atten;
-
平方前
-
平方后