9.点光源光照衰减计算

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 宏用于获取衰减值所在的分量。这就像在颜色中选取一个分量(如rg)。使用宏的原因是,不同平台的分量对应关系不同,使用宏可以确保在各个平台上都能得到正确的分量。
  • 为什么使用 distance² 而非 distance?这是因为:
    1. 避免开平方带来性能消耗。
    2. 采用平方衰减更符合现实中的光照特性:人眼对亮部不敏感,而对暗部更为敏感。这样可以将衰减值的精度集中在较远的地方。
    • 例如,当 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

×

喜欢就点赞,疼爱就打赏