9.多种光源-点光源光照衰减计算
9.1 知识点
重要知识回顾
在Shader中进行光照衰减处理时,通常通过从纹理中获取衰减数据。
- 不使用灯光遮罩时:从
_LightTexture0
纹理中获取衰减数据。 - 使用灯光遮罩时:从
_LightTextureB0
纹理中获取衰减数据。
在纹理采样之前,我们需要将顶点坐标从世界空间转换到光源空间。用于变换的矩阵如下:
- 老版本:
_LightMatrix0
- 新版本:
unity_WorldToLight
点光源衰减计算
一般情况下,点光源不会为其添加cookie光照遮罩。光照遮罩通常在聚光灯中使用。因此,我们通常不需要考虑cookie纹理的问题。
将顶点从世界空间转换到光源空间
float3 lightCoord = mul(unity_WorldToLight, float4(worldPos, 1)).xyz;
lightCoord
是光源坐标系下的顶点,经过光源的范围(range)规范化后的坐标。这个坐标的模长在0~1之间。如果顶点在光源范围之外,模长为1,且不会为负数。
利用光源空间坐标计算离光源的距离
fixed atten = tex2D(_LightTexture0, dot(lightCoord, lightCoord).xx).UNITY_ATTEN_CHANNEL;
dot(lightCoord, lightCoord)
是点乘操作,计算得到的结果是distance²
(离光源的距离的平方),即x² + y² + z² = 离光源距离 distance².xx
是一种特殊的写法,用于构建一个float2
类型的UV坐标。这里的UV坐标相当于(distance², distance²)
。UNITY_ATTEN_CHANNEL
宏用于获取衰减值所在的分量。这就像在颜色中选取一个分量(如r
、g
)。使用宏的原因是,不同平台的分量对应关系不同,使用宏可以确保在各个平台上都能得到正确的分量。- 为什么使用
distance²
而非distance
?这是因为:- 避免开平方带来性能消耗。
- 采用平方衰减更符合现实中的光照特性:人眼对亮部不敏感,而对暗部更为敏感。这样可以将衰减值的精度集中在较远的地方。
- 例如,当
distance
为 0.5 时,distance²
为 0.25,这样LUT查找表中的大部分值会集中在远离光源的部分。相当于使用二次函数拉长暗部的范围,压缩亮部的范围。想大于把亮的地方压缩了,越远就越多不亮的地方。
9.2 知识点代码
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Lesson09_多种光源_点光源光照衰减计算 : MonoBehaviour
{
void Start()
{
#region 重要知识回顾
//在Shader中进行光照衰减处理时
//我们是通过从纹理中取出衰减数据
//不使用灯光遮罩时,从 _LightTexture0 纹理中获取
//使用时,从 _LightTextureB0 纹理中获取
//在纹理采样之前
//我们需要将顶点坐标从世界空间中转换到光源空间中
//变换矩阵为:
//老版本:_LightMatrix0
//新版本:unity_WorldToLight
#endregion
#region 知识点 点光源衰减计算
//注意:一般点光源我们不会为其添加cookie光照遮罩
// 一般想要使用光照遮罩都会在聚光灯中使用
// 因此我们不用考虑cookie纹理的问题
//1.将顶点从世界空间转换到光源空间
// float3 lightCoord = mul(unity_WorldToLight, float4(worldPos, 1)).xyz;
// lightCoord 是光源坐标系下顶点根据光源的范围range规范化后的坐标
// 相当于是一个模长为0~1之间的向量 假如顶点在范围range外 那么模长就是1 不会为负数的
//2.利用该光源空间下的坐标来计算离光源的距离
// 并利用距离参数,从光源纹理中采样
// fixed atten = tex2D(_LightTexture0, dot(lightCoord, lightCoord).xx).UNITY_ATTEN_CHANNEL;
// dot(LightCoord, LightCoord).xx 中
// dot(LightCoord, LightCoord) 是为了通过点乘得到 结果 x² + y² + z² = 离光源距离 distance²
// xx是一种特殊写法,目的是构建一个 float2 代表uv坐标
// 这里的 uv坐标 相当于是 (distance², distance²)
// 用distance²做uv坐标,而不是distance
// 1.为了避免开平方带来性能消耗
// 2.采用这种平方衰减更符合现实世界中光照的特性
// 因为人眼对亮部不敏感,而对暗部敏感,这样我们就可以将 衰减值的精度 集中在比较远的地方
// distance是0.5时,distance²是0.25,这样LUT查找表中大部分值都会留给比较远的部分
// 相当于用二次函数 把暗部的范围拉长 亮部范围被压缩
// UNITY_ATTEN_CHANNEL这个宏 得到衰减值所在的分量
// 可以就理解像颜色为取一个分量一样 比如取rgba中的r值 g值
// 为什么用这个宏而不用写死的rgba这样的分量呢?
// 是因为在不同平台分量对应的不同 使用了宏可以保证得到对应的分量
#endregion
}
}
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com