Shader 中的光源
1、Shader 开发中常用的光源属性
Unity当中一共支持四种光源类型:

- 平行光(Directional)
 - 点光源(Point)
 - 聚光灯(Spot)
 - 面光源(Area)— 面光源仅在烘焙时有用
 
不管光源类型到底是什么,我们在Shader开发当中经常会使用到的光源相关属性有:
 位置、方向、颜色、强度、衰减
 也就是说我们在Shader中处理光照效果时,经常会用到这些光的属性参与到计算当中
2、对比平行光、点光源、聚光灯
2.1 平行光
充当角色:太阳
 照射范围:无限制
 特点:
- 它不存在固定的位置
 - 它的重要属性只有方向(可以通过Transform的Rotation属性来改变方向)
 - 它到场景中所有点的方向都是一样的
 - 由于它没有位置,因此它没有衰减的概念(光的强度不会随着距离而发生变化
 
2.2 点光源
充当角色:灯泡、烛光 等
 照射范围:有限
 特点:
- 它的光是由一个点发出的,向四面八方延伸的光
 - 它的范围由参数Range来决定
 - 它的位置由Transform中的Position来决定
 - 它存在衰减,随着物体离点光源距离决定衰减强弱
 
2.3 聚光灯
充当角色:探照灯、手电筒 等
 照射范围:有限
 特点:
- 它的光范围由空间中的一块锥形区域定义
 - 它的范围由参数Range和Spot Angle 共同决定
 - 它的位置由Transform中的Position来决定
 - 它存在衰减,随着物体离聚光灯距离决定衰减强弱。
 
但是它相对点光源衰减计算公式更复杂,因为需要点是否在锥形范围内
3、判断光源类型
Unity中提供了三个重要的宏,分别是:
- _DIRECTIONAL_LIGHT - 平行光
 - _POINT_LIGHT - 点光源
 - _SPOT_LIGHT - 聚光灯
 
#if defined(_DIRECTIONAL_LIGHT)平行光逻辑
#elif defined (_POINT_LIGHT)点光源逻辑
#elif defined (_SPOT_LIGHT)聚光灯逻辑
#else其他逻辑
#endif 
4、光照衰减
光照衰减通常指的是在渲染过程中考虑光线在空间中传播时的减弱效应,比如:任何光源的光照亮度会随着物体离光源的距离增加而迅速衰减。一般常见的光照衰减计算方式有
- 线性衰减:光强度与距离成线性关系。即光照衰减与光源到被照射表面的距离成正比。
 - 平方衰减:光强度与距离的平方成反比。这种模型更符合现实世界中光照的特性,因为光在空间中的传播过程中通常会遵循平方衰减规律。
 
4.1 Unity中的光照衰减
Unity中为了提升性能,我们一般不会直接通过数学公式计算光照衰减,而是使用一张纹理作为查找表(LUT, lookup table) 在片元着色器中计算逐像素光照的衰减
Unity Shader中有一个内置的纹理类型的变量 _LightTexture0,该纹理中存储了衰减值相关的数据,Unity 内部预先就计算好了相关数据 并存入到该纹理中,避免重复计算,提升性能表现
 其中它的对角线上的纹理颜色值,表明了光源空间中不同位置的点对应的衰减值
纹理中的对角线,起点(0, 0) 位置,表示和光源重合的点的衰减值;终点(1,1) 位置,表示在光源空间中离光源距离最远的点的衰减值
一般我们直接从 _LightTexture0 中进行纹理采样后,利用其中的 UNITY_ATTEN_CHANNEL 宏来得到衰减值所在的分量:
tex2D(_LightTexture0, 对应纹理uv坐标).UNITY_ATTEN_CHANNEL 
注意:如果光源存在cookie,也就是灯光遮罩,那么衰减查找纹理便是 _LightTextureB0
4.2 光源空间变换矩阵
Unity Shader中 内置的 光源空间变换矩阵是用于将世界空间下的位置转换到光源空间下(光源位置为原点)
- 老版本:_LightMatrix0
 - 新版本:unity_WorldToLight
 
由于我们需要从 _LightTexture0 光照纹理中取出对应的衰减数据,因此我们需要将顶点位置从世界空间中转换到光源空间中,然后再来从其中取得衰减数据,我们可以通过矩阵运算将世界空间下的点转换到光源空间下
mul(unity_WorldToLight, float4(worldPos, 1)); 
4.3 点光源的衰减计算
注意:一般点光源不会为其添加cookie光照遮罩,一般想要使用光照遮罩都会在聚光灯中使用
步骤:
(1)将顶点从世界空间转换到光源空间
float3 lightCoord = mul(unity_WorldToLight, float4(worldPos, 1)).xyz; 
lightCoord 是光源坐标系下顶点根据光源的范围range规范化后的坐标,相当于是一个模长为0~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
- 为了避免开平方带来性能消耗
 - 采用这种平方衰减更符合现实世界中光照的特性
 
因为人眼对亮部不敏感,而对暗部敏感,这样我们就可以将 衰减值的精度 集中在比较远的地方
 (distance是0.5时,distance2是0.25,这样LUT查找表中大部分值都会留给比较远的部分)
4.4 聚光灯衰减计算
灯光组件中有一个Cookie参数,是用来关联光照遮罩图片的,对于平行光和点光源,默认是不会提供任何光照遮罩信息的,但是对于聚光灯来说,Unity会默认为它提供一个Cookie光照遮罩,主要是用于模拟聚光灯的区域性,而此时光照纹理中
- _LightTexture0 存储的是Cookie纹理信息
 - _LightTextureB0 存储的是光照纹理信息,里面包含衰减值
 
因此,获取聚光灯衰减值时,需要从_LightTextureB0中进行采样;获取遮罩范围相关数据时,需要从_LightTexture0中进行采样
(1)将顶点从世界空间转换到光源空间
 float4 lightCoord = mul(unity_WorldToLight, float4(i.worldPos, 1)); 
注意:这里我们转换后和点光源不同的是,点光源只会获取其中的xyz,而聚光灯会获取其中的xyzw,这是因为在聚光灯光源空间下的w值有特殊含义,会参与后续的计算
(2)利用光源空间下的坐标信息
 我们会通过3个步骤去获取聚光灯的衰减信息
  
fixed atten = (lightCoord.z > 0) * //第一步tex2D(_LightTexture0, lightCoord.xy / lightCoord.w + 0.5).w * //第二步tex2D(_LightTextureB0, dot(lightCoord, lightCoord).rr).UNITY_ATTEN_CHANNEL; //第三步 
我们首先分析和点光源相同的部分——第三步
tex2D(_LightTextureB0, dot(lightCoord, lightCoord).rr).UNITY_ATTEN_CHANNEL; 
这一步的规则和点光源规则一致,直接根据距离光源原点距离的平方从光照纹理中获取衰减值
 需要注意的是
- 聚光灯的光照衰减纹理为_LightTextureB0
 - dot函数只会计算xyz,w不会计算
 
接着我们来分析用于进行范围判断的部分——第一、二步
第一步:(lightCoord.z > 0)
 CG语法中没有显示的bool类型,一般情况下 0 表示false,1表示true,也就是说lightCoord.z > 0的返回值,条件满足时为1,条件不满足为0
 这里的z代表的其实是 目标点 相对于 聚光灯照射面 距离,如果 lightCoord.z <= 0 证明在聚光灯照射方向的背面,就不应该受到聚光灯的影响, 也就是说这一步的主要作用,是用来决定顶点是否受到聚光灯光照的影响
第二步:tex2D(_LightTexture0, lightCoord.xy / lightCoord.w + 0.5).w
 我们以前在进行纹理采样时都会进行一个 先缩放 后 平移 的操作,比如:
uv = v.texcoord.xy * _MainTex_ST.xy + _MainTex_ST.zw; 
而第二步中的 lightCoord.xy / lightCoord.w + 0.5 其实也是在做这样的一个操作,这样做的主要目的是因为:
我们需要把uv坐标映射到0~1的范围内再从纹理中采样,lightCoord.xy / lightCoord.w 进行缩放后 x, y的取值范围是-0.5~0.5之间,再加上0.5后,x,y的取值范围就是0~1之间,便可以进行正确的纹理采样了,而 lightCoord.xy / lightCoord.w 是因为聚光灯有很多横截面,我们需要把各横截面映射到最大的面上进行采样
总结一下:看似复杂的聚光灯光照衰减计算方式,其实就是由 “遮罩衰减” 和 距离衰减 共同决定的
- 第一步:判断是否能有机会照到光 看得到为1,看不到为0:fixed atten = (lightCoord.z > 0)
 - 第二步:缩放平移,映射到遮罩纹理采样 根据遮罩纹理的信息决定衰减叠加:tex2D(_LightTexture0, lightCoord.xy / lightCoord.w + 0.5).w *
 - 第三步:从光照衰减纹理中取出按距离得到的衰减值:tex2D(_LightTextureB0,dot(lightCoord, lightCoord).rr).UNITY_ATTEN_CHANNEL;
 
相关文章:
Shader 中的光源
1、Shader 开发中常用的光源属性 Unity当中一共支持四种光源类型: 平行光(Directional)点光源(Point)聚光灯(Spot)面光源(Area)— 面光源仅在烘焙时有用 不管光源类型到…...
【django】局域网访问django启动的项目
目录 一、现象 二、django的settings.py配置 三、启动django项目 四、获取本机IP 五、局域网机器访问 前言:本机使用pycharm启动的项目,局域网其他机器访问 一、现象 django开发了接口,想给其他同志访问接口测试,无法通过I…...
【计算机组成原理】主存储器深度解析
📢博客主页:https://blog.csdn.net/2301_779549673 📢欢迎点赞 👍 收藏 ⭐留言 📝 如有错误敬请指正! 📢本文由 JohnKi 原创,首发于 CSDN🙉 📢未来很长&#…...
docker在基础镜像上,比如rockylinux,如何配置yum仓库
在基础镜像rockylinux上 启动的容器,没有yum仓库,就执行不了一些命令 ~]docker run -itd --name linux rockylinux:8.5~]# docker exec -it linux bash /]# ifconfig bash: ifconfig: command not found/]# vim bash: vim: command not found …...
libtorch落地AI项目的一些总结
总结 1. 为啥C 写AI C 是一个非常强大的编程语言,它具有非常强大的计算能力,可以处理非常大的数据集,并且可以非常快速地完成计算。很多项目需要嵌入式部署,C 是一个非常适合的编程语言。C 可以非常快速地完成计算,并…...
ffmpeg面向对象——参数配置秘密探索及其设计模式
目录概览 0.参数配置对象流程图0.1 用到的设计模式0.2 与朴素思想的对比 1.参数传递部分1.1 AVDictionary字典容器类1.1.1 类定义及类图1.1.2 构造函数1.1.3 析构函数1.1.4 设置/读取等配置参数 1.2 参数配置实例 2.参数配置生效部分2.1参数过滤模块2.1.1 AVOption类2.1.1.1 类…...
华为eNSP使用详解
eNSP(Enterprise Network Simulation Platform)是华为提供的一款网络仿真平台,它允许用户在没有真实设备的情况下进行网络实验和学习网络技术。eNSP可以模拟各种网络设备,如交换机、路由器、防火墙等,并支持创建多种网…...
一文入门生成式AI(理解ChatGPT的原理)
一、什么是生成式AI? 以ChatGPT为代表的生成式AI,是对已有的数据和知识进行向量化的归纳,总结出数据的联合概率。从而在生成内容时,根据用户需求,结合关联字词的概率,生成新的内容。 可以这么联想&#x…...
C# 中Faker
在 C# 中,Faker 类通常用于生成模拟数据(也称为虚拟数据、测试数据),这对于开发、测试以及演示应用程序非常有用。一个流行的库叫做 Faker,它提供了一种简单的方式来生成各种随机数据。 安装 Faker 库 要使用 Faker …...
数据权限的设计与实现系列9——前端筛选器组件Everright-filter集成框架开发2
功能实现  规则转换为 SQL 片段 规则解析 首先我们来构造一个典型的规则,包括两个条件组,每个组由两个条件组成,由且与或两种逻辑关系,如下图: 然后看看生成的规则,如下: {"filt…...
鸿蒙Harmony-Next 徒手撸一个日历控件
本文将介绍如何使用鸿蒙Harmony-Next框架实现一个自定义的日历控件。我们将创建一个名为CalendarView的组件(注意,这里不能叫 Calendar因为系统的日历叫这个),它具有以下功能: 显示当前月份的日历支持选择日期显示农历日期可以切换上一月和下一月 组件…...
直播音频解决方案
音频解决方案公司具体解决的是什么样的问题?什么样的客户需要找音频方案公司?相信还是有很多人不是很了解。音频解决方案公司工作就像是为音频设备“量身定制衣服”,帮助客户解决各种音频相关的问题。无论你是音响制造商、会议设备商、耳机品…...
Git基本用法总结
设置全局用户名 git config --global user.name xxx #设置全局用户名 设置全局邮箱地址 git config --global user.email xxxxxx.com #设置全局邮箱地址 查看所有的 Git 配置,包括用户信息 git config --list #查看所有的 Git 配置,包括用户信…...
SQLite的入门级项目学习记录(四)
性能评估和测试 规划项目 1、框架选择:前端交互和线程控制用pyside,SQLite作为数据库支持。 2、预估数据量:每秒10个数据,每个月约26000000(26M)条。 3、压力测试:首先用python脚本创建一个数据…...
Docker工作目录迁移
文章目录 前言一、迁移步骤1.停掉docker服务2.创建存储目录3.迁移docker数据4.备份5.添加软链接6.重启docker服务,测试 总结 前言 安装docker,默认的情况容器的默认存储路径会存储系统盘的 /var/lib/docker 目录下,系统盘一般默认 50G&#…...
【多维动态规划】64. 最小路径和(面试真题+面试官调整后的题目)
64. 最小路径和 难度:中等 力扣地址:https://leetcode.cn/problems/minimum-path-sum/description/ 1. 原题以及解法 1.1 题目 给定一个包含非负整数的 m x n 网格 grid ,请找出一条从左上角到右下角的路径,使得路径上的数字总和…...
Web后端开发技术:RESTful 架构详解
RESTful 是一种基于 REST(表述性状态转移,Representational State Transfer)架构风格的 API 设计方式,通常用于构建分布式系统,特别是在 Web 应用开发中广泛应用。REST 是一种轻量级的架构模式,利用标准的 …...
【Fastapi】参数获取,json和query
【Fastapi】参数获取,json和query 前言giteegithub query形式json传递同步方法使用json 前言 花了半个月的时间看了一本小说,懈怠了…今天更新下fastapi框架的参数获取 gitee https://gitee.com/zz1521145346/fastapi_frame.git github https://git…...
【Node.js】初识微服务
概述 Node.js 的微服务架构是一种通过将应用程序分解为独立的、松耦合的小服务的方式进行系统设计。 每个微服务负责处理一个特定的业务功能,并且这些服务可以独立开发、部署、扩展和管理,并且可以通讯。 它的核心思想就是解耦。 微服务和微前端是类…...
React项目实战(React后台管理系统、TypeScript+React18)
### 项目地址:(线上发布) (1)别人的项目地址 gitgitee.com:zqingle/lege-react-management.git (2)我自己的项目地址 gitgitee.com:huihui-999/lege-react-management.git ### B站讲解视频地址 https://www.bilibili.com/video/BV1FV4y157Zx?p37&spm_id_frompageDrive…...
接口测试中缓存处理策略
在接口测试中,缓存处理策略是一个关键环节,直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性,避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明: 一、缓存处理的核…...
网络六边形受到攻击
大家读完觉得有帮助记得关注和点赞!!! 抽象 现代智能交通系统 (ITS) 的一个关键要求是能够以安全、可靠和匿名的方式从互联车辆和移动设备收集地理参考数据。Nexagon 协议建立在 IETF 定位器/ID 分离协议 (…...
【力扣数据库知识手册笔记】索引
索引 索引的优缺点 优点1. 通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性。2. 可以加快数据的检索速度(创建索引的主要原因)。3. 可以加速表和表之间的连接,实现数据的参考完整性。4. 可以在查询过程中,…...
理解 MCP 工作流:使用 Ollama 和 LangChain 构建本地 MCP 客户端
🌟 什么是 MCP? 模型控制协议 (MCP) 是一种创新的协议,旨在无缝连接 AI 模型与应用程序。 MCP 是一个开源协议,它标准化了我们的 LLM 应用程序连接所需工具和数据源并与之协作的方式。 可以把它想象成你的 AI 模型 和想要使用它…...
前端导出带有合并单元格的列表
// 导出async function exportExcel(fileName "共识调整.xlsx") {// 所有数据const exportData await getAllMainData();// 表头内容let fitstTitleList [];const secondTitleList [];allColumns.value.forEach(column > {if (!column.children) {fitstTitleL…...
家政维修平台实战20:权限设计
目录 1 获取工人信息2 搭建工人入口3 权限判断总结 目前我们已经搭建好了基础的用户体系,主要是分成几个表,用户表我们是记录用户的基础信息,包括手机、昵称、头像。而工人和员工各有各的表。那么就有一个问题,不同的角色…...
Python实现prophet 理论及参数优化
文章目录 Prophet理论及模型参数介绍Python代码完整实现prophet 添加外部数据进行模型优化 之前初步学习prophet的时候,写过一篇简单实现,后期随着对该模型的深入研究,本次记录涉及到prophet 的公式以及参数调优,从公式可以更直观…...
【C语言练习】080. 使用C语言实现简单的数据库操作
080. 使用C语言实现简单的数据库操作 080. 使用C语言实现简单的数据库操作使用原生APIODBC接口第三方库ORM框架文件模拟1. 安装SQLite2. 示例代码:使用SQLite创建数据库、表和插入数据3. 编译和运行4. 示例运行输出:5. 注意事项6. 总结080. 使用C语言实现简单的数据库操作 在…...
IoT/HCIP实验-3/LiteOS操作系统内核实验(任务、内存、信号量、CMSIS..)
文章目录 概述HelloWorld 工程C/C配置编译器主配置Makefile脚本烧录器主配置运行结果程序调用栈 任务管理实验实验结果osal 系统适配层osal_task_create 其他实验实验源码内存管理实验互斥锁实验信号量实验 CMISIS接口实验还是得JlINKCMSIS 简介LiteOS->CMSIS任务间消息交互…...
鸿蒙DevEco Studio HarmonyOS 5跑酷小游戏实现指南
1. 项目概述 本跑酷小游戏基于鸿蒙HarmonyOS 5开发,使用DevEco Studio作为开发工具,采用Java语言实现,包含角色控制、障碍物生成和分数计算系统。 2. 项目结构 /src/main/java/com/example/runner/├── MainAbilitySlice.java // 主界…...
