6.更复杂的光照

一、Unity的渲染路径

渲染路径决定了光照是如何应用到Unity Shader中的。我们需要为每个Pass指定它使用的渲染路径

如何设置渲染路径?

Edit>Project Settings>Player>Other Settinigs>Rendering

如何使用多个渲染路径?如:摄像机A渲染的物体使用前向渲染,摄像机B渲染的物体使用延迟渲染

在每一个摄像机的渲染路径设置中设置该摄像机使用的渲染路径,以覆盖Project Settings中的设置

如果选择Use Player Settings,那么这个摄像机会使用Project Settings中的设置;否则就会覆盖的 Project Settings中的设置。注意:如果当前显卡并不支持所选择的渲染路径,unity就会自动使用更低一级的渲染路径。如:一个GPU不支持延迟渲染,那么unity会使用前向渲染

完成上面设置后,我们要给每一个Pass中使用 标签来指定该Pass使用的渲染路径。

这是通过Pass的LightMode标签实现的。不同类型的渲染路径会包含多种标签设置

Pass{

        Tags { “ LightMode”=“ForwardBase” }

// 告诉unity,该Pass使用前向渲染中的ForwardBase路径。

前向渲染中还有一种路径叫ForwardAdd

 那么多渲染路径有什么用呢?如果一个Pass没有指定任何渲染路径会有什么问题吗?

指定渲染路径是和unity的底层渲染引擎的一次重要沟通。

1.前向渲染路径

原理

每进行一次完整的前向渲染,我们需要渲染该对象的渲染图元,并计算两个缓冲区的信息:一个是颜色缓冲区,一个是深度缓冲区。利用深度缓冲来决定一个片元是否可见,如果可见就更新颜色缓冲区中的颜色值。

对于每个逐像素光源,都需要进行一次完整的渲染流程。如果一个物体在多个逐像素光源的影响区域,该物体就需要执行多个Pass,每个Pass计算一个逐像素光源的光照结果,然后再帧缓冲中把这些光照结果混合起来得到最终的颜色值。
如果有大量逐像素光照,就需要执行大量Pass因此渲染引擎通常会限制每个物体的逐像素光照数目。

Unity中的前向渲染

一个Pass不仅仅可以用来计算逐像素光照,还可以计算逐顶点光照等其他光照。

这取决于光照计算所处流水线阶段以及计算时用的数学模型

前向渲染有三种处理光照的方式:

1.逐顶点处理

2.逐像素处理

3.球谐函数(SH)处理

绝定一个光源使用哪种处理模式取决于它的类型和渲染模型

光源类型指的是该光源是平行光还是其他类型的光源,光源的渲染模式指该光源是否是重要的。

可以在Light组件中设置这些属性如上图

在前向渲染中,当渲染一个物体时,unity会根据场景中各个光源的设置以及这些光源对物体的影响程度(距离远近、光源强度等)对光源进行重要度排序。

一定数目的光源会按照逐像素的 方式处理,最多有4个光源按照逐顶点处理,剩下的按SH处理

判断规则:

  • 场景中最亮的平行光总是按逐像素处理
  • 渲染模式被设置为not important的光源按逐顶点会SH处理
  • 渲染模型设置为important按按逐像素处理
  • 如果根据以上规则得到的逐像素光源数量小于Quality Setting中的逐像素光源数量,会有更多光源以逐像素方式渲染

内置的光照变量和函数

2.顶点照明渲染路径

对硬件配置要求少,运算性能高,但得到效果差。

不支持逐像素效果如:阴影、法线映射、高精度的高光反射

3.延迟渲染路径

原理

主要包含两个Pass

第一个Pass中不进行任何光照计算,而是仅仅计算哪些片元是可见的,住哟啊用深度缓冲计算实现,当发现一个片元是可见的,我们就把相关信息存储到G缓冲区。

第二个Pass中我们利用G缓冲区的各个片元信息,如表面法线、视角方向、漫反射系数等,进行真正的光照计算

延迟渲染的Pass数目通常是2个,这与场景中的光源数目无关。延迟渲染的效率不依赖场景的复杂度,而是和我们使用的屏幕空间大小有关。

unity中的延迟渲染

unity中有两种延迟渲染,一种是遗留的延迟渲染路径,另一种是在新的渲染路径。

如果游戏中使用大量实时光照,那么我们选择延迟渲染路径,但该路径需要一定硬件支持

新旧延迟渲染差别很小,只是使用不同的技术案例权衡不同的需求

延迟渲染适合光照数目多、如果使用前向渲染会造成性能瓶颈的情况。

缺点:

  • 不支持真正的抗锯齿功能
  • 不能处理半透明物体
  • 对显卡有一定要求

使用延迟渲染,unity为我们提供两个Pass:

  1. 第一个Pass用于G缓冲。这个Pass中,我们把物体的漫反射颜色、高光反射颜色、平滑度、法线、自发光和深度等信息渲染到屏幕空间的G缓冲区中。对每个物体来说,这个Pass仅会执行一次
  2. 第二个Pass用于计算正在的光照模型。这个Pass会用上一个Pass中渲染的数据来计算最终的光照颜色,再存储到帧缓冲中

可访问的内置变量和函数

4.选择哪种渲染路径

Unity - Manual: Rendering paths in the Built-in Render Pipeline (unity3d.com)

我们需要根据游戏发布的目标平台来选择渲染路径。如果当前显卡不支持所选渲染路径,那么unity会自动使用比其低一级的渲染路径

二、Unity的光源类型

Unity一个支持4种光源类型:平行光、点光源、聚光灯、面光源(面光源仅在烘培时使用)

1.光源类型有什么影响

1.平行光

平行光可以照亮的范围是没有限制的,常作为太阳这样的角色出现

平行光可以放置在场景中的任何位置

几何属性只有方向且所有点的方向都是一样的

平行光没有具体的位置,也没有衰减的概念,光照强度不会随着距离而发生改变

2.点光源

点光源照亮的空间是有限的,它是空间中的一个球体定义的。点光源可以表示由一个点发出的、向所有方向延申的光

 点光源有位置属性

对于方向属性,我们要用点光源的位置减去某点的位置来得到它到该点的方向。

点光源是会衰减的,随着物体逐渐远离点光源,它收到的光照强度也会逐渐减小。

点光源球心处的光照强度最强,球体边缘最弱值为0,中间的衰减值可以由函数定义

3.聚光灯

聚光灯照亮的空间是有限的,不再是简单的球体,而是由空间中的一块锥形区域定义

聚光灯可以用于表示一个特定位置出发、特定方向延申的光

 锥形区域的半径由Range属性决定,张开的角度由Spot Angle属性决定

对于方向属性,需要聚光灯位置减去某点的位置来得到它到该点的方向

聚光灯的衰减随着物体逐渐远离点光源而逐渐减小,在锥形的顶点处光照强度最强,边缘处为0,衰减值由函数定义,但更复杂

2.在前向渲染中处理不同的光源类型

在unity中如何访问光源的5个属性:位置、方向、颜色、强度以及衰减

 1.实践

Shader "Shader/ForwardRender"
{Properties{_Diffuse ("Diffuse", Color) = (1, 1, 1, 1)_Specular ("Specular", Color) = (1,1,1,1)_Gloss ("Gloss", Range(8.0, 256)) = 20 }SubShader{Tags { "RenderType"="Opaque" }Pass{Tags { "LightMode"="ForwardBase" }CGPROGRAM#pragma multi_comile_fwdbase#pragma vertex vert#pragma fragment frag#include "Lighting.cginc"struct appdata{float4 vertex : POSITION;float3 normal : NORMAL;};struct v2f{float4 pos : SV_POSITION;float3 worldNormal : TEXCOORD0;float3 worldPos : TEXCOORD1;};fixed4 _Diffuse;fixed4 _Specular;float  _Gloss;v2f vert (appdata v){v2f o;o.pos = UnityObjectToClipPos(v.vertex);o.worldNormal = UnityObjectToWorldNormal(v.normal);o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;return o;}fixed4 frag (v2f i) : SV_Target{   fixed3 worldNormal = normalize(i.worldNormal);fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * max(0, dot(worldNormal, worldLightDir));fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - i.worldPos);fixed3 halfDir = normalize(worldLightDir + viewDir);fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(max(0, dot(worldNormal, halfDir)), _Gloss);fixed atten = 1.0;return fixed4(ambient + (diffuse + specular) * atten, 1.0);}ENDCG}Pass{Tags { "LightMode"="ForwardAdd" }Blend One OneCGPROGRAM#pragma multi_compile_fwdadd#pragma vertex vert#pragma fragment frag#include "Lighting.cginc"#include "AutoLight.cginc"struct appdata{float4 vertex : POSITION;float3 normal : NORMAL;};struct v2f{float4 pos : SV_POSITION;float3 worldNormal : TEXCOORD0;float3 worldPos : TEXCOORD1;};fixed4 _Diffuse;fixed4 _Specular;float  _Gloss;v2f vert (appdata v) {v2f o;o.pos = UnityObjectToClipPos(v.vertex);o.worldNormal = UnityObjectToWorldNormal(v.normal);o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;return o;}fixed4 frag(v2f i) : SV_Target {fixed3 worldNormal = normalize(i.worldNormal);#ifdef USING_DIRECTIONAL_LIGHTfixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);#elsefixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz - i.worldPos.xyz);#endiffixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * max(0, dot(worldNormal, worldLightDir));fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - i.worldPos.xyz);fixed3 halfDir = normalize(worldLightDir + viewDir);fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(max(0, dot(worldNormal, halfDir)), _Gloss);#ifdef USING_DIRECTIONAL_LIGHTfixed atten = 1.0;#else#if defined (POINT)float3 lightCoord = mul(unity_WorldToLight, float4(i.worldPos, 1)).xyz;fixed atten = tex2D(_LightTexture0, dot(lightCoord, lightCoord).rr).UNITY_ATTEN_CHANNEL;#elif defined (SPOT)float4 lightCoord = mul(unity_WorldToLight, float4(i.worldPos, 1));fixed atten = (lightCoord.z > 0) * tex2D(_LightTexture0, lightCoord.xy / lightCoord.w + 0.5).w * tex2D(_LightTextureB0, dot(lightCoord, lightCoord).rr).UNITY_ATTEN_CHANNEL;#elsefixed atten = 1.0;#endif#endifreturn fixed4((diffuse + specular) * atten, 1.0);}ENDCG}}FallBack "Specular"
}

2.实验  Base Pass 和 Addition Pass的调用

当我们创建一个光源时,默认情况下它们Render Mode时Auto。即Unity会在背后为我们判断哪些光源会按照逐像素处理,而哪些光源按照逐顶点或SH的方式处理了。

我们未改变Edit>Project Setting>Quality>Pixel Light Count中的数值,因此默认情况下物体可以接收除最亮的平行光外的4个逐像素光照

帧调试器:Window>Frame Debugger

三、Unity的光照衰弱

Unity使用一张纹理作为查找表来在着色器中计算逐像素光照的衰减

好处是,计算机衰减不依赖于数学公式的复杂性,只需要使用一个参数值去纹理中采样即可

但使用纹理查找来计算衰减也有弊端:

  • 需要预处理得到采样纹理,而且纹理的大小也会影响衰减的精度
  • 不直观,同时也不方便,因此一旦把数据存储到查找表中,我们就无法使用其他数学公式来计算衰减

优点是:

  • 在一定程度上提升性能
  • 得到的效果在大部分情况下都是良好的

unity默认使用纹理查找的方式计算逐像素的点光源和聚光灯的衰减

1.用于光照衰弱的纹理

unity在内部使用一张_LightTexture0的纹理来计算光照衰减。

2.使用数学公式计算衰弱

计算光源线性衰减

float distance = length (_WorldSpaceLightPos0.xyz - i.worldPosition.xyz);
atten = 1.0 / distance;

四、Unity的阴影

1.阴影是如何实现的

Shadow Map技术:先把摄像机位置放在与光源重合的位置上,那么该场景中光源的阴影区域就是哪些摄像机看不到的地方。

在前向渲染中,如果场景中最重要的平行光开启了阴影,Unity就会为该光源计算它的阴影映射纹理(shadowmap)。这张阴影映射纹理本质上也是一张深度图,它记录了从该光源出发、能看到的场景中距离它最近的表面位置(深度信息)。

在计算阴影映射纹理时,如何判断距离它最近的表面位置呢?

把摄像机放在光源文字,然后按照正常的渲染流程,即调用Base Pass 和 Addition Pass来更新深度信息,得到阴影映射纹理。

但会造成性能消耗,因为我们只需要深度信息

解决办法就是:使用一个额外的Pass来专门更新光源的阴影映射纹理,这个Pass就是LightMode标签被设置为ShadowCaster的Pass。

这个Pass的渲染目标不是帧缓存,而是阴影映射纹理(或深度纹理)。

屏幕空间的阴影映射技术:

屏幕空间的阴影映射原本是延迟渲染中产生阴影的方法。但该技术需要显卡支持MRT,有些移动平台不支持这种特性。

先调用LightMode为ShadowCaster的Pass来得到可投射阴影的光源的阴影映射纹理以及摄像机的深度纹理。然后根据光源的阴影映射纹理和摄像机的深度纹理来得到屏幕空间的阴影图。

如果摄像机的深度图中记录的表面深度大于转换到阴影映射的深度值,就说明该表面虽然可见,但是却处于该光源的阴影中,通过这样的方式,阴影图就包含了屏幕可见中所有有阴影的区域。

如果我们想一个物体接收另一个物体的阴影,以及它向其他物体投射阴影的过程:

  1. 我们向一个物体接收来自其他物体的阴影,就保修在Shader中对阴影映射纹理(包括屏幕空间的阴影图)进行采样,把采样结果和最后的光照结果进行相乘来产生阴影效果
  2. 如果我们向要一个物体向其他物体投影,就必须把该物体加入到光源阴影映射纹理计算中,从而让其他物体在对阴影映射纹理采样时可以得到该物体的相关信息。这个过程在LightMode为ShadowCaster的Pass中实现。

2.不透明物体的阴影

Cast Shadow:把该物体加入光源阴影映射纹理的计算中,从而让其他物体在对阴影映射纹理采样时可以得到物体的相关信息

Receive Shadow:可以选择是否让物体接收来自其他物体的阴影

Two Sided:允许物体的所有面都计算阴影信息

3.使用帧调试器查看阴影绘制过程

4.统一管理光照衰弱和阴影

5.透明度物体的阴影

五、本书使用的标准UnityShader

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

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

相关文章

Vuex 4与状态管理实战指南

title: Vuex 4与状态管理实战指南 date: 2024/6/6 updated: 2024/6/6 excerpt: 这篇文章介绍了使用Vuex进行Vue应用状态管理的最佳实践,包括为何需要状态管理,Vuex的核心概念如store、actions、mutations和getters,以及如何处理异步操作和模…

网工内推 | 网络运维工程师,H3CIE认证优先,13薪,享股票期权

01 畅读 🔷招聘岗位:高级网络运维工程师 🔷职责描述: 1.负责线上业务网络技术运维工作,保障并优化线上网络质量; 2.规划并构建公司线上业务网络架构; 3.规划线上业务网络质量评估与监控体系&…

USB (1)

再看USB 其实回过头看USB 是可以和无线 有线(internet) 可以和PCIe 甚至AXI类比的 它们共通处在于都是communication 有限通信 有7层网络协议 在USB也是分层的 不同的协议,依赖的介质不一样 这就要求相应的Physical层处理 USB的physical层是基于Serdes的,所以有串并/并串的…

找寻卓越的生成式人工智能应用案例?别浪费在无趣之处!

“ 生成式AI(AI)技术的强大众所周知。但不知道你们是否和我有一样感觉,目前市面上,企业对生成式AI的应用,场景大多较为单一。” Ingo Mierswa Altair产品开发高级副总裁 我说这些生成式AI的应用单一,是指…

整理好了!2024年最常见 20 道 Kafka面试题(十)

上一篇地址:整理好了!2024年最常见 20 道 Kafka面试题(九)-CSDN博客 十九、Kafka的消费者如何实现幂等性? 在Kafka中,幂等性指的是消费者处理消息时,即使多次接收到同一条消息,也能…

MongoDBTemplate-基本文档查询

文章目录 流程概述步骤1:创建一个MongoDB的连接步骤2:创建一个查询对象Query步骤3:设置需要查询的字段步骤4:使用查询对象执行查询操作 流程概述 步骤描述步骤1创建一个MongoDB的连接步骤2创建一个查询对象Query步骤3设置需要查询…

中介子方程二

*#X$XyXpXyX$XαXηXtXαX$XWXyX$XyXWX$XpXαXqXηX$XeXαXhX$XyX$XpX$XyX$XyXeXαX$XpXyXpX$XαXeXyX$XyX$XpX$XyX$XhXαXeX$XηXqXαXpX$XWXyX$XyXWX$XαXtXηXαXpX$XEX$XZX$XpXαXηXtXαX$XWXyX$XyXWX$XpXαXqXηX$XeXαXhX$XyX$XpX$XyX$XyXeXαX$XpXyXpX$XαXeXyX$XyX$Xp…

让你工作效率飞起的五款软件

🌟 No.1:亿可达 作为一款自动化工具,亿可达被誉为国内版的免费Zaiper。它允许用户无需编程知识即可将不同软件连接起来,构建自动化的工作流程。其界面设计清新且直观,描述语言简洁易懂,使得用户可以轻松上…

【数据结构与算法 经典例题】反转链表(图文详解)

💓 博客主页:倔强的石头的CSDN主页 📝Gitee主页:倔强的石头的gitee主页 ⏩ 文章专栏:《数据结构与算法 经典例题》C语言 期待您的关注 ​ 目录 一、问题描述 二、解题思路分析 三、代码实现 一、问题描述 二、解题…

[笔记] 记录docker-compose的部署过程

容器技术 第二章 记录docker-compose的部署过程 容器技术记录docker-compose的部署过程(可选)新建docker用户(可选)迁移docker-ce目录docker-compose官方插件形式安装官方二进制形式独立安装(可选) 使用docker-compose二进制包的 bash_completion 命令补齐 参考来源 记录docker…

⾃动化批量管理-Ansible

目录 一、ansible 简介 自动化工具选择 (了解)​编辑 1、ansible 是什么? 2、ansible 特点 3、ansible 架构图 二、ansible 任务执行 1、ansible 任务执行模式 2、ansible 执行流程 3、ansible 命令执行过程 三、ansible 配置详解 …

一文看懂Llama 2:原理、模型与训练

一文看懂Llama 2:原理、模型与训练 Llama 2是一种大规模语言模型(LLM),由Meta(原Facebook)研发,旨在推动自然语言处理(NLP)领域的发展。本文将详细介绍Llama 2的原理、模…

通过Slf4j中的MDC实现在日志中添加用户IP功能

一、slf4j中MDC是什么 slf4j除了trace、debug、info、warn、error这几个日志接口外,还可以配合MDC将数据写入日志。换句话说MDC也是用来记录日志的,但它的使用方式与使用日志接口不同。 在使用日志接口时我们一般这么做 log.debug("log debug"…

echaerts图例自动滚动并隐藏翻页按钮

效果图 代码 legend: {itemHeight: 14,itemWidth: 14,height: "300", //决定显示多少个// 通过 CSS 完全隐藏翻页按钮pageButtonItemGap: 0,pageButtonPosition: end,pageIconColor: transparent, // 隐藏翻页按钮pageIconInactiveColor: transparent, // 隐藏翻页按…

利用ffmpeg从视频中提取纯音频和纯视频且再合成视频

1. 提取纯音频 ffmpeg -i rawVideo.mp4 -acodec copy -vn vnVideo.aac 或者 ffmpeg -i rawVideo.mp4 -c:a copy -vn vnVideo.aac-acodec copy: 音频只拷贝,不编解码 -vn: v代表视频,n代表no,无视频的意思2. 提取纯视频 ffmpeg -i rawVideo.mp4 -vcodec…

数据资产入表-数据治理-指标建设标准

前情提要:数据价值管理是指通过一系列管理策略和技术手段,帮助企业把庞大的、无序的、低价值的数据资源转变为高价值密度的数据资产的过程,即数据治理和价值变现。上一讲介绍了标签标准设计的基本逻辑和思路。数据资产入表-数据治理-标签设计…

【外汇天眼】胜率提升秘籍:洞悉外汇市场五大参与者的角色与功能

外汇市场是全球最活跃、流动性最高的金融交易市场,每日交易量在6万亿到11万亿美元之间。它的日交易量是全球股票市场的27倍,全球期货市场的12倍,全球债券市场的7倍,超过了全球所有金融产品日交易量的总和。随着全球金融一体化的进…

gitee: fatal: Authentication failed for ‘https://gitee.com/xxx‘

推送更新到你的某个项目时,会遇到以下报错: $ git push origin master remote: [session-6841d990] xxx: Incorrect username or password (access token) fatal: Authentication failed for https://gitee.com/xxx/vue3-element-admin.git/执行以下命令…

混剪素材哪里找?分享几个热门混剪素材下载网站

在短视频和新媒体的世界里,高质量的混剪素材是吸引观众的关键。今天,我将为大家详细介绍几个优秀的素材网站,它们不仅资源丰富,而且完全满足新媒体创作者的需求。这篇文章将帮助你理解如何有效利用这些平台提升你的视频创作。 蛙…

Crosslink-NX器件应用连载(9): USB3.0相机

作者:Hello,Panda 大家晚上好,很久没有分享设计案例了,实在是太忙了,精力十分有限,今天分享一个CrosslinkNX系列器件用作USB3.0相机的案例。其实就是分享一下使用CrosslinkNX器件设计USB3.0相机主要有两种…