Unity SRP 管线【第五讲:自定义烘培光照】
文章目录
- 一、自定义烘培光照
- 1. 烘培光照贴图
- 2. 获取光照贴图
- 3. 获取物体在光照贴图上的UV坐标
- 4. 采样光照贴图
- 二、自定义光照探针
- 三、 Light Probe Proxy Volumes(LPPV)
- 四、Meta Pass
- 五、 自发光烘培
一、自定义烘培光照
细节内容详见catlikecoding.com
这里只做效果展示!!!!
1. 烘培光照贴图
- 在Lighting中设置LightingSettingsAsset,
- 并且将需要烘培的物体设置为ContributeGI
- 将光照设置为Mixed或Baked
- 最后点击GenerateLighting烘培,得到光照贴图

2. 获取光照贴图
通过定义unity_Lightmap纹理即可获取光照贴图,整个场景的光照贴图全部集成在一张贴图中。
TEXTURE2D(unity_Lightmap);
SAMPLER(samplerunity_Lightmap);
因为整个场景的光照贴图都在一张贴图上,所以物体的UV坐标也不再是原本的UV坐标
3. 获取物体在光照贴图上的UV坐标
首先,需要Unity将每个烘培了光照的物体的光照贴图UV发送到GPU。
我们在CameraRenderer中设置drawingSettings 中的perObjectData 为PerObjectData.Lightmaps
var drawingSettings = new DrawingSettings(unlitShaderTagID, sortingSettings)//使用哪个ShaderTagID,以什么一定顺序渲染的设定
{//动态合批enableDynamicBatching = useDynamicBatching,//实例化enableInstancing = useGPUInstancing,//光照贴图UV坐标perObjectData = PerObjectData.Lightmaps,
};
当开启 Lighting 窗口下的Baked Global Illumination按钮时,Unity会对打开Comtribute Global Illumination的物体写入宏_LIGHTMAP_ON

因此需要在需要光照烘培的Shader中定义
#pragma multi_compile _ LIGHTMAP_ON
Unity会将UV坐标作为顶点数据发送到顶点着色器
顶点着色器中作为TEXCOORD1(第二个纹理通道)进行输入
以下定义宏,来避免未开启光照烘培时的UV计算和输入
#if defined(LIGHTMAP_ON)#define GI_ATTRIBUTE_DATA float2 lightMapUV : TEXCOORD1;#define GI_VARYINGS_DATA float2 lightMapUV : VAR_LIGHT_MAP_UV;#define TRANSFER_GI_DATA(input, output) output.lightMapUV = input.lightMapUV;#define GI_FRAGMENT_DATA(input) input.lightMapUV
#else#define GI_ATTRIBUTE_DATA #define GI_VARYINGS_DATA #define TRANSFER_GI_DATA(input, output) #define GI_FRAGMENT_DATA(input) 0.0
#endif
并在着色器输入输出中添加GI_ATTRIBUTE_DATA、GI_VARYINGS_DATA
struct Attributes
{float3 positionOS : POSITION;float2 baseUV : TEXCOORD0;float3 normalOS : NORMAL;GI_ATTRIBUTE_DATAUNITY_VERTEX_INPUT_INSTANCE_ID
};struct Varyings{float4 positionCS : SV_POSITION;float2 baseUV : VAR_BASE_UV;float3 normalWS : VAR_NORMAL;float3 positionWS : VAR_POSITION;GI_VARYINGS_DATAUNITY_VERTEX_INPUT_INSTANCE_ID
};
将UV坐标传入片元着色器
Varyings LitPassVertex(Attributes input)
{Varyings output;....// 全局光照TRANSFER_GI_DATA(input, output);return output;
}
在片元着色器中获取UV坐标
// 全局光照
#if defined(LIGHTMAP_ON)float2 LightMapUV = GI_FRAGMENT_DATA(input);
#endif
然而,这获取的UV并不是该物体在LightMap上的UV,而是LightMap局部空间上的UV。
每个物体均匀且不重叠的按照缩放和偏移放置在这张LightMap中,所以每一个物体都有一个对应的UV缩放和偏移数据。
我们通过在Shader的Input文件中添加unity_LightmapST得到该数据,该数据由Unity直接提供。
CBUFFER_START(UnityPerDraw)...float4 unity_LightmapST;
CBUFFER_END
教程中引入了动态光照贴图UV
float4 unity_DynamicLightmaoST;
防止因为兼容性导致的SRP批处理中断
这里我们不引入 unity_DynamicLightmaoST

4. 采样光照贴图
光照贴图的采样函数由render-pipelines.core提供,因为Unity有可能对:LightMap进行了压缩,所以使用内置函数可以帮我们解决这个问题。
其中,是否压缩LightMap在Light窗口下的Lightmap Compression来设置

设置压缩会在Shader中输入关键字 UNITY_LIGHTMAP_FULL_HDR。
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/EntityLighting.hlsl"
里面有关于
- 球谐采样
- 光照探针采样
- 遮蔽探针采样
- 解码/编码LightMap
- 解码/编码HDR环境贴图
- 采样光照贴图的函数
的函数
其中,使用SampleSingleLightmap,对单一LightMap进行采样
real3 SampleSingleLightmap(TEXTURE2D_LIGHTMAP_PARAM(lightmapTex, lightmapSampler), LIGHTMAP_EXTRA_ARGS, float4 transform, bool encodedLightmap, real4 decodeInstructions)
{// transform is scale and biasuv = uv * transform.xy + transform.zw;real3 illuminance = real3(0.0, 0.0, 0.0);// Remark: baked lightmap is RGBM for now, dynamic lightmap is RGB9E5if (encodedLightmap){real4 encodedIlluminance = SAMPLE_TEXTURE2D_LIGHTMAP(lightmapTex, lightmapSampler, LIGHTMAP_EXTRA_ARGS_USE).rgba;illuminance = DecodeLightmap(encodedIlluminance, decodeInstructions);}else{illuminance = SAMPLE_TEXTURE2D_LIGHTMAP(lightmapTex, lightmapSampler, LIGHTMAP_EXTRA_ARGS_USE).rgb;}return illuminance;
}
我们使用该函数对LightMap进行采样,并根据是否开启LIGHTMAP_ON决定是否调用函数。
float3 SampleLightMap(float2 lightMapUV)
{
#if defined(LIGHTMAP_ON)return SampleSingleLightmap(TEXTURE2D_ARGS(unity_Lightmap, samplerunity_Lightmap), lightMapUV, unity_LightmapST, #if defined(UNITY_LIGHTMAP_FULL_HDR)false,#elsetrue,#endiffloat4(LIGHTMAP_HDR_MULTIPLIER, LIGHTMAP_HDR_EXPONENT, 0.0, 0.0));
#elsereturn 0.0;
#endif
}
返回数据
struct GI{float3 diffuse;
};GI GetGI(float2 lightMapUV){GI gi;gi.diffuse = SampleLightMap(lightMapUV);return gi;
}
在FragmentShader中调用函数,获取LightMap采样的数据。
// 全局光照float2 LightMapUV = GI_FRAGMENT_DATA(input);GI gi = GetGI(LightMapUV);
计算光照
float3 color = GetLighting(surface, brdf, gi);
将全局光照作为基础色
float3 GetLighting(Surface surfaceWS, BRDF brdf, GI gi)
{// 得到表面级联阴影数据CascadeShadowData cascadeShadowData = GetCascadeShadowData(surfaceWS);// 将全局光照作为基础色float3 color = gi.diffuse;// 对可见光照结果进行累加for(int i = 0; i < GetDirectionalLightCount();i++){Light light = GetDirectionalLight(i, surfaceWS, cascadeShadowData);color += GetLighting(surfaceWS, brdf, light);}return color;
}
烘培光照

烘培光照+直接光照

注意:这里烘培光照只计算间接光照,不计算直接光照
但为什么是白色呢,不应该有绿色映射吗??????
将代码中计算GI的光照修改为
float3 color = gi.diffuse * brdf.diffuse;
变为:
间接光照(烘培)

烘培光照(烘培)+直接光照

效果好了,但是仍然没有得到正确的间接光照!
所以光照贴图保存的到底是什么
似乎只是一个强度,但没有颜色!!!

我们将直接光照颜色设为红色,再次查看间接光照数据。

可以看到,间接光照变成了红色,也就是说,光照烘培得到的数据并不是实际光照经过物体表面反射得到的间接光照,而是光照在弹射过程中按照一定比例衰减的结果。
因此,GI最终结果与BRDF相乘得到的才是间接光照的结果(没有反射物体颜色的映射)
如果要获取间接光照,见 4.Meta Pass
二、自定义光照探针
使用光照探针前

使用光照探针后

三、 Light Probe Proxy Volumes(LPPV)
四、Meta Pass
因为间接漫射光从表面反射,它应该受到这些表面漫反射的影响。这种情况目前还没有发生。Unity将我们的表面视为均匀的白色。Unity使用一个特殊的Meta通道来确定烘焙时的反射光。因为我们还没有定义这样的通道,Unity使用默认的通道,它最终是白色的。
增加Meta文件前

增加Meta文件后

间接光照效果

加上动态物体光照探针效果

五、 自发光烘培


相关文章:
Unity SRP 管线【第五讲:自定义烘培光照】
文章目录 一、自定义烘培光照1. 烘培光照贴图2. 获取光照贴图3. 获取物体在光照贴图上的UV坐标4. 采样光照贴图 二、自定义光照探针三、 Light Probe Proxy Volumes(LPPV)四、Meta Pass五、 自发光烘培 一、自定义烘培光照 细节内容详见catlikecoding.c…...
CentOS快速安装Mysql5.7(Alibaba Cloud Linux兼容)
1、安装 在线下载 http://dev.mysql.com/get/mysql57-community-release-el7-10.noarch.rpm 下载rpm安装包 [roottheo bin]# cd /usr/local [roottheo local]# wget http://dev.mysql.com/get/mysql57-community-release-el7-10.noarch.rpm安装rpm [roottheo local]# rpm -iv…...
【css】快速实现鼠标悬浮变色效果
<div class"nav-item"><div class"ic-img"></div><div>切换</div> </div>.nav-item {width: 100rem;height: 45rem;line-height: 45rem;display: flex;text-align: center;justify-content: center;align-items: cent…...
21. Mysql 事件或定时任务,解放双手,轻松实现自动化
文章目录 概念常见操作事件调度器操作查看事件创建事件删除事件启动与关闭事件 精选示例构造实时数据定时统计数据 总结参考资料 概念 Mysql 事件是一种在特定时间点自动执行的数据库操作,也可以称呼为定时任务,它可以自动执行更新数据、插入数据、删除…...
Apache Doris 2.0.2 安装步骤 Centos8
Linux 操作系统版本需求 Linux 系统版本当前系统版本CentOS7.1 及以上CentOS8Ubuntu16.04 及以上- 软件需求 软件版本当前版本Java1.81.8.0_391GCC4.8.2 及以上gcc (GCC) 8.5.0 20210514 (Red Hat 8.5.0-4) 1、查看操作系统版本 方法 1:使用命令行 打开终端或…...
Java学习苦旅(二十五)——哈希表
本篇博客将详细讲解哈希表。 文章目录 哈希表概念冲突概念避免冲突哈希函数设计常见哈希函数 负载因子调节解决冲突闭散列开散列(哈希桶) 和java类集的关系 结尾 哈希表 概念 顺序结构以及平衡树中,元素关键码与其存储位置之间没有对应的关…...
性能分析与调优: Linux 实现 CPU剖析与火焰图
目录 一、实验 1.环境 2.CPU 剖析 3.CPU火焰图 一、实验 1.环境 (1)主机 表1-1 主机 主机架构组件IP备注prometheus 监测 系统 prometheus、node_exporter 192.168.204.18grafana监测GUIgrafana192.168.204.19agent 监测 主机 node_exporter192…...
leetcode动态规划问题总结 Python
目录 一、基础理论 二、例题 1. 青蛙跳台阶 2. 解密数字 3. 最长不含重复字符的子字符串 4. 连续子数组的最大和 5. 最长递增子序列 6. 最长回文字符串 7. 机器人路径条数 8. 礼物的最大价值 一、基础理论 动态规划其实是一种空间换时间的基于历史数据的递推算法&…...
strtok函数的介绍
_str指被分解的字符串 delim指分隔符字符串 返回类型是指针 strtok()用来将字符串分割成一个个片段。参数s指向欲分割的字符串,参数delim则为分割字符串中包含的所有字符。当strtok()在参数s的字符串中发现参数delim中包含的分割字符时,则会将该字符改为\0 字符…...
CF1909_C. Heavy Intervals题解
CF1909_C. Heavy Intervals题解 题目传送门(Problem - C - CodeforcesCodeforces. Programming competitions and contests, programming communityhttps://codeforces.com/contest/1909/problem/C)。 题目翻译如下:(图片来源&a…...
【Python机器学习】理论知识:决策树
决策树是广泛用于分类和回归任务的模型,本质上是从一层层if/else问题中进行学习,并得出结论。这些问题类似于“是不是”中可能问到的问题。 决策树的每个结点代表一个问题或一个包含答案的终结点(叶结点)。树的边奖问题的答案与将…...
天软特色因子看板 (2024.01 第2期)
该因子看板跟踪天软特色因子A04001(当日趋势强度),该因子为反映股价走势趋势强弱,用以反映股价走势趋势强弱,abs(值)越接近1,趋势 性越强,符号代表涨跌方向 今日为该因子跟踪第2期,跟踪其在SH000905 (中证5…...
java智慧医院互联网智慧3D导诊系统源码,经由智慧导诊系统多维度计算,准确推荐科室
什么是智慧导诊系统? 简单地说,智慧导诊系统是一种利用人工智能技术,为医生提供帮助的系统。它可以通过分析患者的症状和病史为医生提供疾病诊断和治疗方案的建议。 系统介绍: 医院智慧导诊系统是在医院中使用的引导患者自助就诊挂号&…...
WiFi7: MLD寻址
原文:MLD使用MLD MAC address唯一的标识本MLD。 MLD下的STA(s)使用与之不同的MAC address。 NOTE MLD MAC address可以和其下的某个STA的MAC address相同或者不同于任一MAC Address。 原文:对于individually addressed 帧。以下规则适用: Address 2(TA)设置为STA的MAC Add…...
laravel-admin之 浏览器自动填充密码(如果需要渲染数据库密码的话,首先确认数据库密码是否可以逆向解密)
参考 https://blog.51cto.com/u_10401840/5180106 为什么浏览器端保存的密码一直自动写入到$form->password 解决办法 2、在页面进入的时候,默认表单的type值为text;推荐指数:2颗星 5、设置表单的readonly属性;推荐指数:4颗…...
jquery图形验证码
效果展示 js图形随机验证码(表单验证) html代码片段 <form class"formwrap"><div class"item"><input type"text" id"code_input" value"" placeholder"请输入验证码"/>…...
dp专题10 目标和
本题链接:. - 力扣(LeetCode) 题目: 思路: 根据这道题,可以通过暴力的方法进行取 号或者 - 号 两个操作,通过当刚好得到 target 的时候 答案 1,但是通过长度是 20 ,操…...
详解 docker 镜像制作的两种方式
概要 制作Docker镜像一般有2种方法: 通过Dockerfile,完成镜像的创建使用仓库中已有的镜像,安装自己使用的软件环境后完成新镜像创建 docker 常用命令 docker build: 用于构建 Docker 镜像。该命令可以从 Dockerfile 构建镜像,…...
selenium元素单击不稳定解决方法
selenium自动化测试过程中,经常会发现某一元素单击,很不稳定,有时候执行了点击没有反映。 以下总结两种解决方法:都是通过js注入的方式去点击。 1.F12查一看,要点击的按钮,或连接,有没有οncl…...
vue3中vite使用sass
引用:https://blog.csdn.net/weiliang_66/article/details/132469597 npm install sass -d配置vite.config.js: css: {preprocessorOptions: {scss: {additionalData:import "/assets/styles/main.scss";}}}创建对应的 main.sass...
Python|GIF 解析与构建(5):手搓截屏和帧率控制
目录 Python|GIF 解析与构建(5):手搓截屏和帧率控制 一、引言 二、技术实现:手搓截屏模块 2.1 核心原理 2.2 代码解析:ScreenshotData类 2.2.1 截图函数:capture_screen 三、技术实现&…...
华为云AI开发平台ModelArts
华为云ModelArts:重塑AI开发流程的“智能引擎”与“创新加速器”! 在人工智能浪潮席卷全球的2025年,企业拥抱AI的意愿空前高涨,但技术门槛高、流程复杂、资源投入巨大的现实,却让许多创新构想止步于实验室。数据科学家…...
浅谈不同二分算法的查找情况
二分算法原理比较简单,但是实际的算法模板却有很多,这一切都源于二分查找问题中的复杂情况和二分算法的边界处理,以下是博主对一些二分算法查找的情况分析。 需要说明的是,以下二分算法都是基于有序序列为升序有序的情况…...
精益数据分析(97/126):邮件营销与用户参与度的关键指标优化指南
精益数据分析(97/126):邮件营销与用户参与度的关键指标优化指南 在数字化营销时代,邮件列表效度、用户参与度和网站性能等指标往往决定着创业公司的增长成败。今天,我们将深入解析邮件打开率、网站可用性、页面参与时…...
DeepSeek 技术赋能无人农场协同作业:用 AI 重构农田管理 “神经网”
目录 一、引言二、DeepSeek 技术大揭秘2.1 核心架构解析2.2 关键技术剖析 三、智能农业无人农场协同作业现状3.1 发展现状概述3.2 协同作业模式介绍 四、DeepSeek 的 “农场奇妙游”4.1 数据处理与分析4.2 作物生长监测与预测4.3 病虫害防治4.4 农机协同作业调度 五、实际案例大…...
如何在网页里填写 PDF 表格?
有时候,你可能希望用户能在你的网站上填写 PDF 表单。然而,这件事并不简单,因为 PDF 并不是一种原生的网页格式。虽然浏览器可以显示 PDF 文件,但原生并不支持编辑或填写它们。更糟的是,如果你想收集表单数据ÿ…...
Android第十三次面试总结(四大 组件基础)
Activity生命周期和四大启动模式详解 一、Activity 生命周期 Activity 的生命周期由一系列回调方法组成,用于管理其创建、可见性、焦点和销毁过程。以下是核心方法及其调用时机: onCreate() 调用时机:Activity 首次创建时调用。…...
论文阅读笔记——Muffin: Testing Deep Learning Libraries via Neural Architecture Fuzzing
Muffin 论文 现有方法 CRADLE 和 LEMON,依赖模型推理阶段输出进行差分测试,但在训练阶段是不可行的,因为训练阶段直到最后才有固定输出,中间过程是不断变化的。API 库覆盖低,因为各个 API 都是在各种具体场景下使用。…...
Python 训练营打卡 Day 47
注意力热力图可视化 在day 46代码的基础上,对比不同卷积层热力图可视化的结果 import torch import torch.nn as nn import torch.optim as optim from torchvision import datasets, transforms from torch.utils.data import DataLoader import matplotlib.pypl…...
Kubernetes 节点自动伸缩(Cluster Autoscaler)原理与实践
在 Kubernetes 集群中,如何在保障应用高可用的同时有效地管理资源,一直是运维人员和开发者关注的重点。随着微服务架构的普及,集群内各个服务的负载波动日趋明显,传统的手动扩缩容方式已无法满足实时性和弹性需求。 Cluster Auto…...
