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…...
装饰模式(Decorator Pattern)重构java邮件发奖系统实战
前言 现在我们有个如下的需求,设计一个邮件发奖的小系统, 需求 1.数据验证 → 2. 敏感信息加密 → 3. 日志记录 → 4. 实际发送邮件 装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其…...
VB.net复制Ntag213卡写入UID
本示例使用的发卡器:https://item.taobao.com/item.htm?ftt&id615391857885 一、读取旧Ntag卡的UID和数据 Private Sub Button15_Click(sender As Object, e As EventArgs) Handles Button15.Click轻松读卡技术支持:网站:Dim i, j As IntegerDim cardidhex, …...
关于iview组件中使用 table , 绑定序号分页后序号从1开始的解决方案
问题描述:iview使用table 中type: "index",分页之后 ,索引还是从1开始,试过绑定后台返回数据的id, 这种方法可行,就是后台返回数据的每个页面id都不完全是按照从1开始的升序,因此百度了下,找到了…...
【项目实战】通过多模态+LangGraph实现PPT生成助手
PPT自动生成系统 基于LangGraph的PPT自动生成系统,可以将Markdown文档自动转换为PPT演示文稿。 功能特点 Markdown解析:自动解析Markdown文档结构PPT模板分析:分析PPT模板的布局和风格智能布局决策:匹配内容与合适的PPT布局自动…...
【git】把本地更改提交远程新分支feature_g
创建并切换新分支 git checkout -b feature_g 添加并提交更改 git add . git commit -m “实现图片上传功能” 推送到远程 git push -u origin feature_g...
鱼香ros docker配置镜像报错:https://registry-1.docker.io/v2/
使用鱼香ros一件安装docker时的https://registry-1.docker.io/v2/问题 一键安装指令 wget http://fishros.com/install -O fishros && . fishros出现问题:docker pull 失败 网络不同,需要使用镜像源 按照如下步骤操作 sudo vi /etc/docker/dae…...
2023赣州旅游投资集团
单选题 1.“不登高山,不知天之高也;不临深溪,不知地之厚也。”这句话说明_____。 A、人的意识具有创造性 B、人的认识是独立于实践之外的 C、实践在认识过程中具有决定作用 D、人的一切知识都是从直接经验中获得的 参考答案: C 本题解…...
Python 包管理器 uv 介绍
Python 包管理器 uv 全面介绍 uv 是由 Astral(热门工具 Ruff 的开发者)推出的下一代高性能 Python 包管理器和构建工具,用 Rust 编写。它旨在解决传统工具(如 pip、virtualenv、pip-tools)的性能瓶颈,同时…...
springboot整合VUE之在线教育管理系统简介
可以学习到的技能 学会常用技术栈的使用 独立开发项目 学会前端的开发流程 学会后端的开发流程 学会数据库的设计 学会前后端接口调用方式 学会多模块之间的关联 学会数据的处理 适用人群 在校学生,小白用户,想学习知识的 有点基础,想要通过项…...
解析奥地利 XARION激光超声检测系统:无膜光学麦克风 + 无耦合剂的技术协同优势及多元应用
在工业制造领域,无损检测(NDT)的精度与效率直接影响产品质量与生产安全。奥地利 XARION开发的激光超声精密检测系统,以非接触式光学麦克风技术为核心,打破传统检测瓶颈,为半导体、航空航天、汽车制造等行业提供了高灵敏…...
