unity GI Shader 实现

news2024/11/24 0:59:10

之前分享了一篇对unity全局光照的解析,里面提到了一些东西,需要在Shader内实现,在这一篇补上。
要实现对全局GI的shader实现,我们可以通过对unity内置的Lit进行解析查看。

烘焙的方式有很多种,选择合适的方式烘焙和使用合适类型的光源尤为重要。

首先,我们先实现一下最基础的烘焙光照显示,就是将Light Map贴图显示出来。需要设置的是,将需要烘焙的模型全设置成静态,光照设置为Baked,并且模型开启了第二套LightMap UV。
在这里插入图片描述
准备工作结束。

纯烘焙,无动态

光照全部为静态的,照明模式将不会起作用,因为它选择哪个烘焙都一样,将直接光,间接光和阴影都烘焙到Light Map上面。
那么开始写shader,首先要开启宏

#pragma multi_compile _ LIGHTMAP_ON //光照贴图支持

获取LightMap的UV

float2 staticLightmapUV : TEXCOORD1;

LightMapUV是第二套

output.staticLightmapUV = input.staticLightmapUV * unity_LightmapST.xy + unity_LightmapST.zw;

然后计算完UV偏移以后,传递到片元着色器
在片元着色器中,我们只需要和之前的SH进行一个宏的判断,用来对间接光漫反射进行修改。

#if defined(LIGHTMAP_ON)
    float4 encodedIrradiance = SAMPLE_TEXTURE2D(unity_Lightmap,samplerunity_Lightmap,input.staticLightmapUV);
    Irradiance = DecodeLightmap(encodedIrradiance, float4(LIGHTMAP_HDR_MULTIPLIER, LIGHTMAP_HDR_EXPONENT, 0.0h, 0.0h));
#else
 Irradiance = SampleSH(WorldNormal);//SH,Light Probe
#endif

首先是对宏进行判断,然后读取LightMap贴图,读取到的贴图是被编码过的,所以还需要一步解码,这个是unity内置的功能,所以可以直接使用内值的变量去解码。如果当前没有开启LIGHTMAP_ON,我们还可以按照之前的那种SH方法去获取间接光漫反射。

在这种模式下,动态模型接收的是Light Probe的漫反射光照,因为没有主光源,实时渲染时也没有主光源进行渲染。
在这里插入图片描述
接下来兼容一下Lightmap方向贴图。

#pragma multi_compile _ DIRLIGHTMAP_COMBINED //方向贴图

首先要设置宏,用来判断是否开启方向贴图。
然后再LightMap中判断方向贴图,去设置方向贴图

half3 Irradiance = half3(0,0,0);
#if defined(LIGHTMAP_ON)
    float4 encodedIrradiance = SAMPLE_TEXTURE2D(unity_Lightmap,samplerunity_Lightmap,input.staticLightmapUV);
    Irradiance = DecodeLightmap(encodedIrradiance, float4(LIGHTMAP_HDR_MULTIPLIER, LIGHTMAP_HDR_EXPONENT, 0.0h, 0.0h));
    #if defined(DIRLIGHTMAP_COMBINED)
        float4 direction = SAMPLE_TEXTURE2D(unity_LightmapInd,samplerunity_Lightmap,input.staticLightmapUV);
        half3 LightDir = direction * 2.0f - 1.0f;
        half halfLambert = dot(WorldNormal,LightDir) * 0.5 + 0.5;
        Irradiance = Irradiance * halfLambert / max(1e-4,direction.w);
    #endif
#else
 Irradiance = SampleSH(WorldNormal);//SH,Light Probe
#endif

注意,unity_Lightmap是内置LightMap,unity_LightmapInd是内置的方向贴图名称,samplerunity_Lightmap是公用的采样器。
那么,有个问题,我们有了光照的方向,法向以及视角方向,是不是可以计算LightMap模型的高光效果,答案是肯定的。不管是blinnPhong还是使用GGX高光数据都够,那肯定能直接计算出来。
以下是示例代码:

#if !defined(_DIRHIGHLIGHT_OFF)
    half BlinnPhong = pow(saturate(dot(WorldNormal,normalize(LightDir + ViewDir))),30); //计算出高光强度
    Irradiance = Irradiance + Irradiance * BlinnPhong; //高光和漫反射相加
#endif

特点:

  1. 场景中的光照全靠Light Map,Light Probe,Refletion Probe提供。没有实时光源,节约性能。
  2. 所有物体缺少动态高光,静态物体勉强可以使用方向贴图获取朝向计算,动态物体的话只能使用其它方式实现。
  3. 动态物体不能产生投影。

总结:纯烘焙模式,由于其性能优秀,一般会采用在移动端固定视角类型的游戏上,动态物体就使用其它方式比如全局设置一个光的朝向等方法实现。动态物体无阴影,一般采用假阴影,比如平面阴影那种,还是比较适合移动端。
使用推荐:移动端2.5D俯视角游戏。

使用Mixed混合光照烘焙

之前说过,使用了Mixed混合光源以后,会额外的生成一组阴影贴图,也就是静态阴影贴图,然后根据我们设置的光照模式,有不同的区别。

Subtrative模式

Mixed灯光对LightMap物体无效,通过light.distanceAttenuation来屏蔽Mixed光源,如果是使用LightMap的物体,这个值将为0,避免的重复着色。
在这个模式下,静态物体的直接光,间接光,阴影都被烘焙到LightMap和LightProbe上面,动态物体还是会被Mixed光源照射,进行实时计算。这种方式是一种非常合理的设置方式,静态物体固定,用LightMap计算即可,动态物体刚好使用Mixed光照实时渲染,漫反射使用LightProbe。但是还是有几个问题需要解决,如果能解决,这将适合大多数移动端平台性能最优方案:

  1. 动态物体无法投射阴影到静态物体身上。
    解决方案:
//SUBTRACTIVE模式下的混合光照,用于处理实时光照和光照贴图的混合
#if defined(LIGHTMAP_ON) && defined(_MIXED_LIGHTING_SUBTRACTIVE)
    #if defined(_MAIN_LIGHT_SHADOWS_SCREEN)
        float4 positionCS = TransformWorldToHClip(WorldPos);
        float4 ShadowCoord = ComputeScreenPos(positionCS);
    #else
        float4 ShadowCoord = TransformWorldToShadowCoord(WorldPos);
    #endif
    float4 ShadowMask = float4(1.0, 1.0, 1.0, 1.0);
    Light mainLight = GetMainLight(ShadowCoord, WorldPos, ShadowMask);
    Irradiance = SubtractDirectMainLightFromLightmap(mainLight, WorldNormal, Irradiance);
#endif

这种方式是在对间接光源的辐射度里面去处理,从名字SubtractDirectMainLightFromLightmap就可以看出,是从光照贴图冲减去主光源,属于trick的方式。
首先还是要获取到平衡光主光源,这种方式只适合平衡光主光源。
上面的宏_MIXED_LIGHTING_SUBTRACTIVE是在unity内不声明的,只需要判断即可。
对于其的实现原理,我们可以查看源码学习一下:
在这里插入图片描述
从效果上看,在移动端是可以接受的:
在这里插入图片描述
2. 动态物体的实时光照无法被静态物体遮挡。
解决方案:就是在获取实时光源时,通过宏进行区别。

//ShadowMask是用来处理静态投影和动态投影的结合
#if defined(SHADOWS_SHADOWMASK) && defined(LIGHTMAP_ON)
    half4 ShadowMask = SAMPLE_SHADOWMASK(input.staticLightmapUV);
#elif !defined(LIGHTMAP_ON)
    half4 ShadowMask = unity_ProbesOcclusion;
#else
    half4 ShadowMask = half4(1, 1, 1, 1);
#endif

以上是获取ShadowMask的方式,如果使用光照烘焙,则直接获取ShadowMask的贴图(如果有的情况下)。如果没有LIGHTMAP_ON,那就是实时渲染,则在Light Probe上面去获取遮挡关系,遮挡关系我们也可以通过编辑器查看:
在这里插入图片描述
设置显示全部Light Probe,然后显示遮挡,会发现在阴影处的Light Probe明显比如在亮光处的Light Probe要暗。
在这里插入图片描述
unity的内置处理是一个叫MainLightShadow的函数:
在这里插入图片描述
这种方式是在移动端平台最推荐的一种方式,静态物体单纯的从Light Map上面获取直接光,间接光和阴影,能够实时从动态物体上面获取实时阴影进行混合。动态物体能够实时计算直接光,并且能够通过烘焙的Light Probe实时更新被场景遮挡的关系,性能和效果达到的一种均衡。
还有一些问题:角色被阴影遮挡没有实时遮挡那么明确,实时渲染阴影和烘焙阴影之间融合的也不好。如果移动平台的话,勉强够用。毕竟其它方式更耗。

ShadowMask模式

如果目标是主机或者pc,那就不用这么拮据了,可以使用ShadowMask模式,这种模式和上面的Subtrative的区别在于,烘焙时不会将阴影直接烘焙到LightMap上面,而是单独生成一份ShadowMask贴图,用于阴影遮挡关系。这样,就不用使用那种trick的方式计算阴影,而是直接两个阴影直接融合,并且动态物体身上也能够获取到烘焙的阴影的影响。但是你会发现,烘焙出来的LightMap的体积会增加一倍,这也算一个缺点。
在这里插入图片描述
你会发现每个贴图都有对应的一张shadowmask,ShadowMask模式下还有两种模式,之前也说过,
在这里插入图片描述
在质量里面可以设置ShadowMask的模式,ShadowMask就是静态物体纯用shadowmask贴图渲染阴影,也能和动态物体很好的融合。但是Distance Shadowmask,它会渲染两遍,也就是实时阴影和shadowmask阴影都渲染,最后再来一个融合。
在这里插入图片描述
上图为Distance Shadowmask的渲染阴影的批次。
在这里插入图片描述
上图为shadowmask模式的批次。明显的看出少了几十个pass。所以,还是那句话,更好的效果需要更多的性能。
使用Distance Shadowmask,你的静态物体会进行两次阴影渲染(shadowmask贴图的和实时渲染)最后进行融合的,而且还需要shadowCasterPass渲染。
而Shadowmask,相对于Subtrative模式,解决了动态阴影和静态阴影融合的问题,代价是lightmap体积翻倍。

Baked Indirect模式

这个模式,就是将间接光以及烘焙光都烘焙到LightMap上面,直接光还是实时渲染的。我们只需要按照前面,在间接光里面去获取LightMap去替换SH即可。

实时渲染LightMap

Realtime Lighting和Mixed Lighting是可以共用的,实时的主要解决实时光源的漫反射弹射效果,而烘焙的,可以直接处理Baked光源以及区域光Area Light。
在这里插入图片描述
如何混合呢,我们可以看到unity内置的代码,它兼容了动态LightMap和静态LightMap,通过宏,进行判断你的lightmap是否需要计算。它们之前没有重叠的部分,因为动态LightMap是存储的动态光照的漫反射信息,而静态LightMap是存储的静态光照的漫反射信息。所以它们之间相加即可。我们之前也计算了静态LightMap,那么动态LightMap的UV如何获取。

首先要获取到dynamicLightmapUV,这个需要第三套uv。

float2 dynamicLightmapUV : TEXCOORD2;

顶点着色器计算UV

output.dynamicLightmapUV = input.dynamicLightmapUV * unity_DynamicLightmapST.xy + unity_DynamicLightmapST.zw;

获取动态光照LightMap:

float4 encodedIrradiance = SAMPLE_TEXTURE2D(unity_DynamicLightmap,samplerunity_DynamicLightmap,input.dynamicLightmapUV);
Irradiance = DecodeLightmap(encodedIrradiance, float4(LIGHTMAP_HDR_MULTIPLIER, LIGHTMAP_HDR_EXPONENT, 0.0h, 0.0h));

这样就自己实现,如果没有自定义的要求,我推荐,还是直接使用SampleLightmap函数就行了。

这种双管齐开的方式,是最好的效果,推荐最高的效果上开启即可,毕竟用了两套烘焙系统,即耗性能又耗内存,但是效果会好很多,因为你的动态光源和静态光源都得到间接光漫反射的计算,让效果更真实。
推荐:主机和电脑高画质开启。

插件推荐

Bakery 替换内置的烘焙GI,效率还高
Magic Lightmap Switcher 可以实现LightMap贴图的切换
Magic Light Probes 可以帮你轻松快速的布置光照探测器LightProbe

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/472688.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

python-使用Qchart总结4-绘制多层柱状图

1、上代码 import sysfrom PyQt5.QtChart import QChart, QChartView, QBarCategoryAxis, QValueAxis, QBarSeries, QBarSet from PyQt5.QtGui import QPainter, QColor from PyQt5.QtWidgets import QMainWindow, QApplicationfrom untitled import Ui_MainWindow #从生成好的…

财报解读:连续三年逆势增长的背后,欧派家居到底靠的是什么?

能在过去3年逆势增长的家居企业并不多,而欧派家居就是其中一个。4月25日,欧派家居发布2022年年度报告。据年报数据显示,2022年,欧派家居共实现营业收入224.80亿元,净利润约26.88亿元。 从2020年到2022年,欧…

设计模式——单例设计模式

目录 一、设计模式概述和分类 1.1 设计模式介绍 1.2 23种设计模式 二、创建型设计模式-单例模式 2.1 介绍 2.2 八种单例模式的创建方式 2.2.1 饿汉式(静态常量) 2.2.2 饿汉式(静态代码块) 2.2.3 懒汉式(线程不…

SSH客户端工具输入目标地址端口远程失败故障原因和解决方案

问题表现:SSH客户端工具输入目标地址端口远程失败时,出现ssh client 报 algorithm negotiation failed的异常信息。 使用SSH Secure Shell Client连接Linux服务器的SSH的时候有时会出现错误提示信息:ssh algorithm negotiation failed。这是…

基于DSP+FPGA+ADS1282支持32Bit高精度数据采集方案(三)系统性能测试

系统性能分析与测试 本章将首先对系统电路的噪声和温漂进行分析,而后对采集系统的性能进行 测试,并对测试数据进行分析。 5.1 高精度 AD 转换电路噪声和温漂分析 5.1.1 电阻噪声与温漂 1 、电阻的噪声 电阻是一种噪声源,其严重程度取…

与贵州公安面对面|欧科云链天眼中国行,他们都说“行”

4月28日,为期两天“链上天眼科技助警中国行贵州站”(以下简称:贵州站)迎来了尾声。 继首日亮相中共中央政法委员会机关报-法制日报社主办的“政法智能化建设技术装备及成果展巡展贵州站”,引发贵州省政法机关单位的广…

基于.Net开发的、支持多平台、多语言餐厅点餐系统

今天给大家推荐一套支持多平台、多语言版本的订单系统,适合餐厅、酒店等场景。 项目简介 这是基于.Net Framework开发的,支持手机、平板、PC等平台、多语言版本开源的点餐系统,非常适合餐厅、便利店、超市、酒店等,该系统基础功…

vue3+ts+vite自适应项目——搭建项目

系列文章目录 第一章:搭建项目 目录 系列文章目录 前言 一、搭建项目 二、安装sass 1.安装依赖 2.测试 三、引入element-plus 1.引入库 1.1 安装 2.2引入插件 2.3测试 2.自定义主题 四、实现自适应 1.安装 2.引入 总结 前言 本项目主要目的是熟练…

Web前端学习路线 Web前端面试题 Web前端简历及常用工具

文章目录: 一:web前端学习路线 二:web前端常用工具 手册 文档 教程 插件 组件 三:IT计算机web前端面试题和面试需知 一:web前端学习路线 web前端学习路线 二:web前端常用工具 手册 文档 教程 插件 组件 …

浙大数据结构第三周初识二叉树

03-树1 树的同构 (25分) 给定两棵树T1和T2。如果T1可以通过若干次左右孩子互换就变成T2,则我们称两棵树是“同构”的。例如图1给出的两棵树就是同构的,因为我们把其中一棵树的结点A、B、G的左右孩子互换后,就得到另外一棵树。而图2就不是同构…

[2023.4.28]知识体系脑图

整理下工作5年来的知识体系脑图:

Vulnhub:DerpNStink 1靶机

kali:192.168.111.111 靶机:192.168.111.130 信息收集 端口扫描 nmap -A -v -sV -T5 -p- --scripthttp-enum 192.168.111.130 通过nmap的http-enum脚本发现目标80端口存在wordpress,访问目标网站的wordpress被重定向到http://derpnstink.…

政务智能办体验升级、乳腺癌创新药加速研发,飞桨和文心大模型驱动应用智能涌现...

4月27日,百度“飞桨中国行”落地上海,围绕“如何运用深度学习平台大模型技术打造壁垒快速破局”主题,飞桨携手区域企业、高校院所、硬件厂商、开发者等生态伙伴共话 AI 技术新动向和产业升级新趋势,助力上海夯实具有国际影响力的人…

设计模式 -- 状态模式

前言 月是一轮明镜,晶莹剔透,代表着一张白纸(啥也不懂) 央是一片海洋,海乃百川,代表着一块海绵(吸纳万物) 泽是一柄利剑,千锤百炼,代表着千百锤炼(输入输出) 月央泽,学习的一种过程,从白纸->吸收各种知识->不断输入输出变成自己的内容 希望大家一起坚持这个过程,也同…

系统集成项目管理工程师 笔记(第11章:项目人力资源管理)

文章目录 项目人力资源管理 过程11.2.1 编制项目人力资源计划的工具与技术 375(1)层次结构图(工作、组织、资源 分解结构)(2)矩阵图(责任分配矩阵,RAM)(3&…

KubeSphere 社区双周报 | 杭州站 Meetup 议题征集中 | 2023.04.14-04.27

KubeSphere 社区双周报主要整理展示新增的贡献者名单和证书、新增的讲师证书以及两周内提交过 commit 的贡献者,并对近期重要的 PR 进行解析,同时还包含了线上/线下活动和布道推广等一系列社区动态。 本次双周报涵盖时间为:2023.04.14-2023.…

开源+实时+数据即服务的架构——唐建法受邀出席2023数据技术嘉年华【干货回顾】

点击报名 假设原料是一个产品公司的 SaaS 业务系统、一套 CRM、一套工单系统、一个内部人事系统,和内部研发管理系统;现在给到你 40min 的时间,能做出怎样的数据菜肴? 如果这里的厨师是 Tapdata,那么答案可以是一个实时…

【Python】实战:生成多层嵌套笛卡尔积组合问卷 csv《感知觉与沟通评估表》

目录 一、适用场景 二、业务需求 (1)原产品需求 (2)需求分析 ① 需求漏洞 ②「0 能力完好」分级标准问题答案组合 ③「1 轻度受损」分级标准问题答案组合 ④「2 中度受损」分级标准问题答案组合 ⑤「3 重度受损」…

Superset安装部署(docker版)

为什么选择使用docker部署superset呢?因为Linux的python环境版本太低,而且一般是不能动系统自带的python环境,大部分都是通过conda或docker的形式创建一个新的python环境 安装yum工具集 yum -y install yum-utils添加docker源至镜像源中 y…

利用chatgpt+低代码技术搭建进销存系统

1 前言 在当今数字化时代,企业管理系统已经成为各行各业不可或缺的一部分。而进销存系统更是企业管理中的重要组成部分,它可以帮助企业实现产品库存管理、采购管理、销售管理等多个方面的自动化管理。 然而,搭建一个高质量的进销存系统需要…