为什么我的unity5 gi里面的GI的light bounce无效

昨天在中,我们为大家解答了:“为什么场景烘焙出来的lightmap上有Realitime灯光的颜色?”和“为什么在Unity 5中动态更换lightmap没有作用?” 这两个问题。今天,我们将继续提供其他相关问题的解答。为什么烘焙的point灯光会有一圈圈的色阶变化?大家在烘焙lightmap的时候可能会发现类似下图的奇怪效果。图中我们使用了一盏Baked的point light,烘焙之后发现光照效果会出现一圈圈的色阶突变。原因是我们使用的是压缩版本的lightmap。如下图Lighting窗口中选项所示:这个压缩虽然可以帮助我们减少游戏最后的打包体积,但是对场景的光照效果也会产生影响,所以对于要追求最好的光照效果的场景建议不要勾选此选项。我们来看看去掉此选项后的效果,现在,色阶变化不存在了。为什么在Realtime灯光下的效果和改为Baked烘焙的效果差别很大?这个问题美术同学会经常遇见。美术一般在烘焙场景之前会先把灯光都设为Realtime, 来实时查看调整灯光参数后的效果。调整到较满意的效果之后,就把灯光类型改为Baked然后进行烘焙。& &在Unity 4中这样做一般可以达到烘焙之后的效果与实时灯光的效果比较接近,但是在Unity 5中可能会发现差别很大。究其原因主要有两点:1、在上面我们已经提到,新的灯光参数Bounce Intensity,这个参数的调整会影响最终烘焙效果中间接光分量的比例。2、Unity 5中对Gamma和Linear颜色空间的实现做了调整以更符合真实情况,但这也导致实时灯光效果与烘焙效果在两种颜色空间中存在差异。所以,建议美术在Linear颜色空间中进行Realtime灯光的调整。因为在Linear颜色空间下,实时灯光与烘焙效果最为接近。不过由于目前移动平台并不支持颜色空间切换,我们可以让项目在PC平台下切换为Linear颜色空间。该选项在Player Settings中的Other Settings里,如下图所示:另外,为了让Bounce Intensity参数的调整也能反映在Realtime灯光中,建议美术在实时调整灯光参数的时候在Lighting窗口中勾选Precomputed Realtime GI,如下图所示:当然Precomputed Realtime GI也是需要在场景静态物体的位置固定之后烘焙一次的,所以如果怕会忘记烘焙的话也可以勾选Build旁边的Auto选框。最后,在调整好灯光效果之后我们把灯光类型改为Baked(或Mixed),取消勾选Precomputed Realtime GI,并勾选Baked GI,然后进行烘焙。下面展示了两种颜色空间下Realtime灯光与烘焙效果的对比:我们可以看到Linear颜色空间下两种光照方式的效果是最为接近的。另外还有朋友曾经咨询:项目的场景在手机上的烘焙效果与Editor中看到的实时灯光的差异非常的大,已经远远比上面对比图中的差别要大了。如果大家也有这样的问题,那么请注意:不同的屏幕对于同一种颜色的表现都会有或多或少的差别,要对比手机与电脑上看到的颜色差别不能直接进行对比,而应该让两个效果在同一个屏幕中对比。一个简单的办法是在手机中截屏然后传到电脑中进行对比。感兴趣的同学可以尝试,保证你一定会为手机与电脑屏幕的颜色解析差异感到惊讶。怎么让不同物体占用不同数量的lightmap像素?这个问题经常会有开发者遇见。主要目的是为了最大限度缩减lightmap的大小,通过让场景中次要物体的lightmap效果粗糙一点来节省游戏的空间。其实做法非常简单,我们可以通过lighting窗口中Object页面里的Scale In Lightmap来设定某个选定的Object在lightmap中占用像素的多少,默认是1对于重要的物体通过提高这个数值来增加此物体使用的lightmap像素,反之我们可以把这个值设为0到1之间来减少此物体所使用的lightmap像素。选项如下图所示:有关Unity 5的Enlighten全局光照系统中的相关问题就介绍到这里,如果大家在开发过程中遇到类似问题,或有相应的解决方法,欢迎给我们留言或是在官方论坛:http://forum.&与我们交流!延展阅读:
点击原文,访问Unity官方社区,阅读更多技术文章!Unity官方平台(Unity-GreaterChina) 
 文章为作者独立观点,不代表微头条立场
的最新文章
近日,微软发布了Visual Studio Tools for Unity 2.2 版本 (简称VSTU)。该版本修复了一些常见的集成问题,让游戏开发者使用 Visual Studio 更为便捷地构建 Unity 游戏。本教程主要讲解Unity引擎自带的2D骨骼动画工具,以及2D动画的基本概念。本篇会添加一些动画,如默认状态、跳动、坠落等。自从我们发布了"The Blacksmith"的相关资源后,许多开发者纷纷询问如何能从美术的角度制作出该demo中高质量的人物角色,今天我们就为大家分享一个相关的视频教程。随着2016年Unite大会的全球启动。这个一年一度的Unity开发者盛会已经转眼步入第十个年头。时值新年,我们将追寻Unite在全世界留下的足迹,为大家回顾它的发展历程!不久之前,App Store推出了“中文独立游戏精选”的头版专栏,其中使用Unity引擎打造的游戏已超过半数。这些优秀的游戏为国产游戏市场注入了一针强心剂。今天,我们将进行岁末最后一轮游戏盘点,让我们来看看Unity制造的“独立骄傲”。在昨天的文章中,我们为大家解答了:“为什么场景烘焙出来的lightmap上有Realitime灯光的颜色?”和“为什么在Unity 5中动态更换lightmap没有作用?” 这两个问题。今天,我们将继续为大家提供其他相关问题的解答。在每一个iOS项目开发过程中,开发者们总会遇见,一边运行游戏一边纳闷“这玩意儿为什么跑这么慢?”的时刻。其实有许多很不错的性能分析工具集,今天我们将会为大家介绍Instruments,就是其中的佼佼者。本文将为大家介绍如何实现类似《Samurai Gunn》游戏中的Pixel溅血效果。本文将向你介绍如何用游戏中的广告,在不影响玩家的情况下获得广告收入。实际上,我们的目标是将广告作为整个游戏体验设计的一部分,用户甚至可能会爱上广告。难得的周末休闲时刻,为大家分享U大队吃喝玩乐的“鹭岛”厦门游记一篇。欢迎大家参与文章中的投票!在制作游戏的过程中,我们总要一次次的去测试一个或多个场景。当然整个游戏过程的速度也需要把控,因为为了达到想要的效果就必须不停地从头试玩游戏关卡。为了解决这个问题,我们需要一组灵活的用于作弊的子系统。“部落猪”和“联盟狗” 们,让我们来看看,Unity 5重现达拉然吧。2015刚刚过去,想必大家今天已经投身到2016年的工作和学习中了!今天我们特别选出了去年在Unity官方微信上最受欢迎的10大Unity技术文章,这些内容你都看过了吗?本篇教程将使用Unity强大的2D功能,仅用62行代码来制做一个仿版《吃豆人》游戏。游戏会尽可能的简单,只关注迷宫、怪物、豆豆以及主角吃豆人。在今天的文章中,我们将先为大家介绍如何创建游戏迷宫。在前面的教程(1)和(2)中,我们介绍了如何使用Unity创建《吃豆人》的迷宫,以及添加吃豆人的动画。今天的文章将介绍如何设置吃豆人物理以及添加豆豆。应用切片(App Slicing)是自iOS与tvOS 9.0开始加入的一个iOS新特性,其目的是减小主应用程序包的大小。开发者将与多种设备相关的资源版本上传到App Store, 只有符合用户当前设备版本的资源才会包含在下载的应用包里。在这篇《吃豆人》教程的最终篇里,我们将介绍如何添加怪物敌人。在本文的末尾有《吃豆人》教程汇总,让我们一起动手来做这款经典的复古游戏吧!在前面的教程(1)和(2)中,我们介绍了如何使用Unity创建《吃豆人》的迷宫,以及添加吃豆人的动画。今天的文章将介绍如何设置吃豆人物理以及添加豆豆。在昨天的教程中,我们分享了创建《吃豆人》迷宫的方法,今天我们将告诉大家如何添加游戏主角 - 吃豆人的动画!本篇教程将使用Unity强大的2D功能,仅用62行代码来制做一个仿版《吃豆人》游戏。游戏会尽可能的简单,只关注迷宫、怪物、豆豆以及主角吃豆人。在今天的文章中,我们将先为大家介绍如何创建游戏迷宫。在圣诞节来临的时刻,Unity产品组给了我们一个惊喜,发布了Unity 5.4的beta1版本。大家好,我们之前允诺过会发布The Blacksmith实时短片里用到的资源和项目定制的工具集与着色器。在本篇文章中,我们将为大家分享该项目的环境包,以及其中的工具集和着色器。UNITE 2016 SHANGHAI | 商务&媒体合作正式启动!Unity 5.3已经发布,这个版本在2D物理系统带来了非常多的新特性与改进,我们将本文中详细的给大家介绍。《Unity 5.x 从入门到精通》中文官方教材预售开启!再见Unity 4,最终版本Unity 4.7发布。结束亦是新的开始,让我们拥抱Unity 5吧!12月17日,Unity 2D新功能发布会圆满结束,来自全球的Unity 2D研发团队为在场开发者详细演示并讲解了Unity即将推出的2D酷炫功能,并与国内从事2D游戏开发的团队进行了深入的沟通和交流,只为进一步改善Unity 2D功能。在本系列之前的博文中,我们介绍了The Blacksmith的创作团队,以及短片美感的制作流程。在这篇博文中,我们将关注场景建设、着色和照明。第一期Unity Masterclass顺利结束,未来我们将邀请全球的技术大师到中国进行技术布道,我们将以此活动为契机,致力于打造“分享、学习、联合”的社区精神,也将带给开发者更切实际的帮助,并创造友好的交流氛围。期待我们下一次的聚会!Unity建立起了全球企业级支持服务体系,旨在为游戏企业提供具备全面性、前瞻性、教育性的服务,希望通过我们全球专业化的服务体系与游戏企业成为长久的合作伙伴,并帮助他们走向成功!本篇将为大家介绍更多炫酷插件。他们将帮助您制作效果更精美的作品,为您的玩家带来震撼的视觉体验。即将发布的Unity 5.3是第四个支持WebGL发布的Unity版本。自Unity 5.0第一次发布预览版WebGL以来,我们取得了许多进展,现在与大家分享相关更新内容。现在Unity 5.3已发布,全新功能,更多平台!按需加载资源是从iOS、tvOS 9.0开始引入的一个新特性Unity VR Masterclass时间变更,12月15日,北京国家会议中心见!本篇为大家推荐的Asset Store插件是Icarus Studio 开发的Complete Physics Platformer Kit以及Robin Schmidt的Character System.2016首届Vision VR/AR(虚拟现实/增强现实)峰会将于-11日在加利福利亚州好莱坞举行,创意资深人士Alex McDowell将在会上发表主题演讲。《时空召唤》,是由银汉游戏使用Unity引擎打造的一款科幻竞技类的MOBA手游。Unity引擎打造,2D精品游戏推荐:The Bridge & 王国保卫战。Unity全面支持全国大学生高校联盟,并联合北京电影学院共同举办教育论坛:探索教育“三维新可能”。Unity现已公布Networking开源内容的下载地址!我们常会感慨游戏场景的逼真。小至一缕阳光下漂浮的点点灰尘,大到浩瀚星空中行行流星飞逝。这些奇妙的效果都是通过游戏引擎中的粒子系统所创作的。这些效果制作精美,消耗低廉,带给玩家最为震撼的视觉体验。近日Unity CEO, John Riccitiello, 在接受专访时表达了对VR发展前景的看好, 以及当下VR项目无法满足市场需求的种种担忧。John指出VR市场还需要两到四年的时间去发展, 初创公司以及游戏开发者们任重而道远。素有游戏界“奥斯卡”之称的金翎奖正式揭晓,奖项花落各家。在这些获奖游戏中,使用Unity引擎研发的移动游戏占据半数之多。《劳拉快跑》(Lara Croft GO)是继 《杀手47:行动 Hitman Go》(Hitman GO)之后, SquareEnix公司又一款快跑系列的游戏作品,本篇文章将以SquareEnix开发人员的视角来分享在这款游戏开发过程中的一些经验。
正在快速发展的VR/AR技术在开启着人类数字互动体验的全新篇章。由Unity举办的Vision V今天将给读者推荐由Ootii 开发的角色控制系统Motion Controller 和 Adventure Camera Rig。搭配使用组成了3A级的第三人称控制器系统。由于各大浏览器厂商陆续宣布Web端将不再支持浏览器插件,所以我们在10月宣布了:从Unity5.4版本开始将不再支持WebPlayer。现在,我们将提供给开发者,对应版本的Web Player离线安装包。《Jotun佐敦》是游戏团队Thunder Lotus Games使用Unity引擎开发的一款手绘风格的2D动作冒险游戏。本文Unity VR指南为大家作介绍。以便大家可以开始制作第一款自己的VR作品。Unity-GreaterChinaUnity大中华区官方微信热门文章最新文章Unity-GreaterChinaUnity大中华区官方微信  本文主要介绍Untiy5以后的GI,PBS,以及光源探头,反射探头的用法以及在着色器代码中如何发挥作用,GI是如何影响渲染的,主要分成三个部分,最开始说明PBS需要的材质与相应概念,二是Unity&里相应GI的操作,三是对应着色器代码的理解。如果没有特殊声明,所有操作与代码都是针对Unity5.3.
PBS材质与概念
  简单来说,PBS的优点不同的照明下获得一致的外观,更容易实现,更直观的参数。
PBS材质概念:
  1.albedo&反照率&
  反照率贴图定义漫反射的基本颜色,与原来的漫反射贴图相比,不包含定向光与AO,在这我们应该由环境自己的定向光与AO来影响,Unity里,我们用GI得到相应烘培或是实时的方向光与AO。
  2.Smoothness/Microsurface&表面细节&材料细节&光滑度
  光滑度:描述物体微表面的一个参数,可以用来定义法线分布函数,这样,粗糙的表面呈现宽,淡的镜面反射,光滑呈现集中和明亮的镜面反射。
  3.Metal/reflectivity&金属性/反射&
  金属与绝缘体应该使用不同的反射设置,导体的反射率&60-90%,绝缘体0-20%,高反射光分子不容易到达内部和散射,这样金属的高表现出来比较淡。
  如下全局设置:
  对于固定的材料,反射率趋于稳定,这样一般来说,一个模型的metal相对变化较少,如泥,水,木头这些他们的反射率相关并不大,只有金属与绝缘体会有相对比较大的反差,而模型表面的粗糙度应该用上面的图光滑性来表示,这个相对变化会比较大些,如下,水和泥土有相似的金属性(反射率),但是光滑度相差大,所以相差比较明显。
  上图来自pbr-theory:&
  Unity中事项,Metallic&贴图,金属性质占用R通道,光滑性占用A通道,GB被忽略。  
  物体的本来颜色用albedo表示,光滑性用Smoothness表示,材质特性用Metal表示,其中Unity&二种PBS标准着色,Standard其中金属性越高,本身镜面颜色占比越高,灯光的颜色占比越低,而高光可以设置自己的镜面反射。
  PS: pbr-practice& 
BRDF&光照模型&概念
  1&能量守恒:一个对象不能反射比他接收的光多。
  粗糙的材料有更多比较淡的亮点,而光滑的材料有更集中,更明亮的亮点,也可以这么理解,漫反射越多,镜面反射相对越少,镜面反射越多,漫反射越少。
  2&菲涅尔效应:边缘的反射更亮。
  更具体的可以看:
  3&微表面模型模型:
  普通的着色模型假定着色的区域是一个平滑的表面,表面有一个法线,而微表面则认为,着色区域是一个无数比入射光线覆盖范围更小的微小表面组成的粗糙区域,这个微小表面是光滑的镜面反射。表面细微细节对扩散的影响,表面越粗糙,反射光越发散或模糊。
GI结合BRDF渲染
  GI全局照明指的是全局照明会模拟光线在场景中的多次反射,所有的东西都是一个潜在的光源,任何可见的模型不是辐射光线,就是反射光线,其中GI(渲染间接光源,本身一般也用BRDF渲染)&配合BRDF生成带灯光直射,环境内模型互想影响的逼真场景。 &
  天空盒是GI的组成部分,反射天空盒可以改变场景所有模型接受反射量。
  GI结合PBS,如下,摄像机的镜头是一样的材质,在不同的环境下:
  更详细的可以点进这个链接:&&
  全局光照的特点在于能够捕捉间接光照,所以5以后,除开原来的direct&light的效果,增加indirect&light的效果,简单来说,就是除开光源之后,然后模型本身做为光源,幅射到别的模型上,层层递归后的效果。现不管是预计算实时GI还是烘培GI都只是针对静态模型。预计算Gi的实时光源与烘陪对应的烘培光源里的强度与反射强度都会影响幅射图与方向图的内容。需要注意,预计算Gi针对的是实时方向光,而烘培GI针对的是烘培方向光。
  Skybox&:天空盒,参考材质Skybox/Cubemap,如果全局光源与全局反射探头都选择Skybox模式,则会把Skybox当做一个Cubemap,场景所有模型,静态与非静态的一部分光源从这个Cubemap反射上得到。
  Sun:Skybox选择一个方向光,以这个方向光的方向做方向,这个方向光如颜色与强度不影响全局本身,如果没有设置方向光,选择强度最大的那个方向光源。&
  Ambient&Source:全局光源,如果设置天空盒,但是天空盒本身没有设置,自动选择下面的全局颜色设置,全局反射探头以Ambient&Source当做光源。
  Ambient&Intensity:全局光源强度,越高越亮,为0时,光源不起作用。
  Ambient&GI:当预计算GI与烘培GI二个都选择后,这个可以选择是用实时还是烘培。&
  Reflection&Source:Unity默认放入的全局反射探头,选择Skybox会以Ambient&Source里提供的光源颜色做反射,同时也可以自己提供cubemap当做反射源。
  Resolution:反射探头解析度,应该是对应RTT的cubemap六张纹理的分辨率。
  Compression:是否压缩。
  Reflection&Intensity:Reflection&Source针对所有模型反射强度,值越大,相应的模型面上显示越清晰的Reflection&Source。
  Reflection&Bounces:当设置多个Reflection&Probe时,互相反射对方信息的次数,如二面镜子。
  Precomputed&Realtime&GI
  预计算实时GI,针对实时静态物体之间的幅射光,故相应的幅射图与方向图都是低分辨率下的。动态物体可以使用光照探头来得到相应反射光源信息,注意动态模型与光探头的距离。
  Realtime&Resolution:预计算实时GI,把场景分成许多格,得到每个格的幅射信息。那么这个值越高,计算量将以平方增加,最终值还将和General&GI里的光源参数里的Resolution相乘。
  CPU&Usage:生成相应GI的数据时,在游戏运行时分配多少CPU计算能力。&
  Baked&GI
  烘培GI,因此能得到更精确的模型之间的反射光信息,但是不能运行时更改相应的光源信息,如颜色,方向,预计算实时GI没有这个问题。
  Baked&Resolution:一般来说,是Realtime&Resolution&10+,因为相应的幅射图与方向图精确度要高很多。
  Baked&Padding:网上说是光照贴图中分隔的距离,还需要验证。
  Compressed:是否压缩
  Ambient&Occlusion:值越高,遮挡地区得到的光比差越大。
  Final&Gather:用FG技术来产生烘培数据,这种技术时间会长一些。参考
  Ray&Count:Final&Gather所用的光线追踪光线数目。
  Atlas&Size:图集里贴图的大小,越低实际占用越精确也就是越小,但是贴图产生越多,应该选择一个合适的大小。&  
  General&GI
  预计算实时GI还是烘培如何生成.
  Direction&Mode:幅射图/带方向光/加镜面,具体看Shader分析,其中预计算实时GI与烘培GI在这生成的相应幅射图,方向图等有所不同,后面会提到。
  Indirect&Intensity:间接光的强度。
  Default&Parameters:生成相应贴图所需要的信息。
  其中全局预计算GI,烘培GI,全局反射探头相应的改动需要重新烘培,如果选择自动,相关改动会自动在后台烘培。
  上面这些说实话,写这么操作没啥用,自己对着每项实践一篇,什么都清楚了。&
Light&Probe:&
  对于GI来说,不管是预计算GI与烘培GI,都不会对非静态模型计算间接反射,光探头的加入,可以使非静态模型得到周围静态模型的幅射光,主要技术原理使用一种球谐光照的技术,注意light probe一般不会对静态模型有影响,你看到的影响,只是因为非静态模型的颜色变化大造成的反差。
  相关球谐光照的技术原理可以参见,本人也看不懂,只能说看了后有点印象是怎么回事:
  一种2D傅立叶级数的球形推广,可以把光照函数展开成SH基函数的叠加,类似傅立叶变换能把任何函数展开成正弦波的叠加,对光照图来说一般只用2&bands&=&4&RGB&textures,通过丢失高频细节来压缩存储。  
Reflection&Probe:
  定义一个Cubemap用来影响周围模型的镜面反射,给镜面高光模型使用。
  一般来说,我们想得到一个实时场景的Cubemap,只需要在一个点,用摄像机对着前后,左右,上下,各拍摄一次,形成6个面,组合成Cubemap.
  Type:烘培,用户,自动。其中,烘培就是用户来控制生成一个当前的场景cubemap,用户就是用户自己提供一个cubemap,实时就是不断更新这个cubemap以映射最新的场景。
  当选择实时,Refresh&mode:On&&awake启动时,每桢,用户脚本控制,当每桢时,如下选择。
  Time&slicing:一桢先生成6个面,后面8桢每桢生成一个mipmap,一共9桢。
  Individual&face:6面6桢,加后面8桢每个mipmap,一共14桢。
  No&time&slicing:一桢内把mipmap与cubemap全部生成。
  Importance:当多个反射探头影响一个模型时,这个参数影响这个反射探头的比重。
  Intensity:间接光强度,强度影响镜面反射,镜面反射越亮。
  Box&Projection:从着色代码来看,应该根据当前反射探头的源点与AABB影响是模型原来法线。
  Size:大小,范围内的模型使用这个。
  Probe&Origin:原点。
  Cubemap&capture&sttings:
  Resolution:cubempa材质的大小。
  HDR:高光。
  Shadow&Distance:阴影距离,数值越少,阴影越近。
  下面就是RTT对应摄像机的属性。
GI间接光源算法:辐射度算法
  辐射度算法就是:把场景细分到很细很细的面片(如1个像素那么大的三角形),分别计算它们接受和发出的光能,然后逐次递归,直到每个面片的光能数据不再变化(或者到一定的阀值)为止.因此,计算量很大(要计算很多次),而且难以并行(因为递归),参考
  Unity中GI选择non-direction模式生成的辐射度,使用一张图,储存每个位置收到的间接光照,其中假定都只是扩散,没有镜面反射。&
GI&Directional&LightMap算法:
  把半球面的入射辐射度用某种方法进行采样,保存起来在运行时根据法线图中的法线方向来进行一次合成,由于带方向信息,也可以支持高光计算了,可以参考:
  Unity中GI选择direction模型,会在上面辐射图添加一张图,用来存储接收到的光的方向选择specular,烘培GI与预计算GI使用不同的方式,烘培GI在上面二张图各扩大一倍,原来的保存直接光的影响,新增加的位置用来保存间接光的影响,其中预计算GI新增加一张贴图,三张图分别保存辐射光照,光源方向,法线,需要结合实时方向光源。
  探讨Unity5中全局光照(Enlighten)&
  Unity&5.0新功能教学:
  Unity&5&中的全局光照技术详解&
  Unity5&官网文档GI三种模式具体区别&
Unity&GI&BRDF&Shader
  主要参考对照如下Shader文件:
  UnityStandardCore.cginc:前向渲染base,顶点着色入口vertForwardBase,片断着色入口fragForwardBase,这个是着色器的主要Pass,全局方向光,GI信息合并都在这个pass中。
  UnityStandardBRDF.cginc:BRDF的具体实现.
  UnityGloballllumination.cginc:提取GI信息,包含烘陪GI与预计算GI。
  预计算Gi针对的是实时方向光,而烘培GI针对的是烘培方向光,所以当说预计算GI的light时,指的是实时方向光,而烘培GI的light说的是烘培方向光。
1 ---------UnityStandardCore
2 //顶点着色器入口
3 VertexOutputForwardBase vertForwardBase (VertexInput v)
VertexOutputForwardB
UNITY_INITIALIZE_OUTPUT(VertexOutputForwardBase, o);
//世界坐标下位置
float4 posWorld = mul(_Object2World, v.vertex);
#if UNITY_SPECCUBE_BOX_PROJECTION
o.posWorld = posWorld.
//屏幕空间位置
o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
o.tex = TexCoords(v);
o.eyeVec = NormalizePerVertexNormal(posWorld.xyz - _WorldSpaceCameraPos);
float3 normalWorld = UnityObjectToWorldNormal(v.normal);
#ifdef _TANGENT_TO_WORLD
float4 tangentWorld = float4(UnityObjectToWorldDir(v.tangent.xyz), v.tangent.w);
float3x3 tangentToWorld = CreateTangentToWorldPerVertex(normalWorld, tangentWorld.xyz, tangentWorld.w);
o.tangentToWorldAndParallax[0].xyz = tangentToWorld[0];
o.tangentToWorldAndParallax[1].xyz = tangentToWorld[1];
o.tangentToWorldAndParallax[2].xyz = tangentToWorld[2];
o.tangentToWorldAndParallax[0].xyz = 0;
o.tangentToWorldAndParallax[1].xyz = 0;
o.tangentToWorldAndParallax[2].xyz = normalW
//We need this for shadow receving
TRANSFER_SHADOW(o);
// Static lightmaps
#ifndef LIGHTMAP_OFF
//开启烘培GI后
o.ambientOrLightmapUV.xy = v.uv1.xy * unity_LightmapST.xy + unity_LightmapST.
o.ambientOrLightmapUV.zw = 0;
// Sample light probe for Dynamic objects only (no static or dynamic lightmaps)
//光源探头对动态模型的影响,rgb(颜色)根据SH系数还原光源探头与不重要的点光源上的颜色信息
#elif UNITY_SHOULD_SAMPLE_SH
#if UNITY_SAMPLE_FULL_SH_PER_PIXEL
o.ambientOrLightmapUV.rgb = 0;
#elif (SHADER_TARGET & 30)
o.ambientOrLightmapUV.rgb = ShadeSH9(half4(normalWorld, 1.0));
// Optimization: L2 per-vertex, L0..L1 per-pixel
o.ambientOrLightmapUV.rgb = ShadeSH3Order(half4(normalWorld, 1.0));
// Add approximated illumination from non-important point lights
#ifdef VERTEXLIGHT_ON
o.ambientOrLightmapUV.rgb += Shade4PointLights (
unity_4LightPosX0, unity_4LightPosY0, unity_4LightPosZ0,
unity_LightColor[0].rgb, unity_LightColor[1].rgb, unity_LightColor[2].rgb, unity_LightColor[3].rgb,
unity_4LightAtten0, posWorld, normalWorld);
//开启预计算GI后
#ifdef DYNAMICLIGHTMAP_ON
o.ambientOrLightmapUV.zw = v.uv2.xy * unity_DynamicLightmapST.xy + unity_DynamicLightmapST.
#ifdef _PARALLAXMAP
TANGENT_SPACE_ROTATION;
half3 viewDirForParallax = mul (rotation, ObjSpaceViewDir(v.vertex));
o.tangentToWorldAndParallax[0].w = viewDirForParallax.x;
o.tangentToWorldAndParallax[1].w = viewDirForParallax.y;
o.tangentToWorldAndParallax[2].w = viewDirForParallax.z;
UNITY_TRANSFER_FOG(o,o.pos);
72 //片断着色器入口
73 half4 fragForwardBase (VertexOutputForwardBase i) : SV_Target
FRAGMENT_SETUP(s)
UnityLight mainLight = MainLight (s.normalWorld);
half atten = SHADOW_ATTENUATION(i);
half occlusion = Occlusion(i.tex.xy);
//提取GI里的信息到UnityGI中。
UnityGI gi = FragmentGI (
s.posWorld, occlusion, i.ambientOrLightmapUV, atten, s.oneMinusRoughness, s.normalWorld, s.eyeVec, mainLight);
// 如果是预计算GI或动态模型,gi.light表示主光源,焙烘取
half4 c = UNITY_BRDF_PBS (s.diffColor, s.specColor, s.oneMinusReflectivity, s.oneMinusRoughness, s.normalWorld, -s.eyeVec, gi.light, gi.indirect);
// GI生成类型是spceular,才会计算
c.rgb += UNITY_BRDF_GI (s.diffColor, s.specColor, s.oneMinusReflectivity, s.oneMinusRoughness, s.normalWorld, -s.eyeVec, occlusion, gi);
c.rgb += Emission(i.tex.xy);
UNITY_APPLY_FOG(i.fogCoord, c.rgb);
return OutputForward (c, s.alpha);
93 //填充UnityGIInput,用来得到UnityGI信息。
94 inline UnityGI FragmentGI (
float3 posWorld,
half occlusion, half4 i_ambientOrLightmapUV, half atten, half oneMinusRoughness, half3 normalWorld, half3 eyeVec,
UnityLight light)
d.worldPos = posW
d.worldViewDir = -eyeV
//如果有GI信息。
#if defined(LIGHTMAP_ON) || defined(DYNAMICLIGHTMAP_ON)
d.ambient = 0;
d.lightmapUV = i_ambientOrLightmapUV;
//一般来说,非静态模型,得到环境光
d.ambient = i_ambientOrLightmapUV.
d.lightmapUV = 0;
//全局反射探头的AABB
d.boxMax[0] = unity_SpecCube0_BoxM
d.boxMin[0] = unity_SpecCube0_BoxM
d.probePosition[0] = unity_SpecCube0_ProbeP
d.probeHDR[0] = unity_SpecCube0_HDR;
//用户定义的反射探头AABB
d.boxMax[1] = unity_SpecCube1_BoxM
d.boxMin[1] = unity_SpecCube1_BoxM
d.probePosition[1] = unity_SpecCube1_ProbeP
d.probeHDR[1] = unity_SpecCube1_HDR;
return UnityGlobalIllumination (
d, occlusion, oneMinusRoughness, normalWorld);
130 --------UnityGloballllumination.cginc
131 //FragmentGI 跳转到这
132 inline UnityGI UnityGlobalIllumination (UnityGIInput data, half occlusion, half oneMinusRoughness, half3 normalWorld, bool reflections)
UnityGI o_
UNITY_INITIALIZE_OUTPUT(UnityGI, o_gi);
// Explicitly reset all members of UnityGI
ResetUnityGI(o_gi);
//动态模型使用 SH得到的漫反射信息。
#if UNITY_SHOULD_SAMPLE_SH
#if UNITY_SAMPLE_FULL_SH_PER_PIXEL
half3 sh = ShadeSH9(half4(normalWorld, 1.0));
#elif (SHADER_TARGET &= 30)
half3 sh = data.ambient + ShadeSH12Order(half4(normalWorld, 1.0));
half3 sh = data.
o_gi.indirect.diffuse +=
//如果没有烘培GI,需要当前全局方向光源的信息
#if !defined(LIGHTMAP_ON)
o_gi.light = data.
//atten阴影信息,值越小阴影越重
o_gi.light.color *= data.
// Baked lightmaps
fixed4 bakedColorTex = UNITY_SAMPLE_TEX2D(unity_Lightmap, data.lightmapUV.xy);
half3 bakedColor = DecodeLightmap(bakedColorTex);
//没有方向贴图
#ifdef DIRLIGHTMAP_OFF
//设置漫反射
o_gi.indirect.diffuse = bakedC
#ifdef SHADOWS_SCREEN
o_gi.indirect.diffuse = MixLightmapWithRealtimeAttenuation (o_gi.indirect.diffuse, data.atten, bakedColorTex);
#endif // SHADOWS_SCREEN
//方向与漫反射
#elif DIRLIGHTMAP_COMBINED
fixed4 bakedDirTex = UNITY_SAMPLE_TEX2D_SAMPLER (unity_LightmapInd, unity_Lightmap, data.lightmapUV.xy);
//更精准的漫反射
调整过后的half Lambert
o_gi.indirect.diffuse = DecodeDirectionalLightmap (bakedColor, bakedDirTex, normalWorld);
#ifdef SHADOWS_SCREEN
o_gi.indirect.diffuse = MixLightmapWithRealtimeAttenuation (o_gi.indirect.diffuse, data.atten, bakedColorTex);
#endif // SHADOWS_SCREEN
//漫反射,方向,高光
#elif DIRLIGHTMAP_SEPARATE
// Left halves of both intensity and direction lightmap right halves - indirect.
// Direct 调整o_gi.light
fixed4 bakedDirTex = UNITY_SAMPLE_TEX2D_SAMPLER(unity_LightmapInd, unity_Lightmap, data.lightmapUV.xy);
o_gi.indirect.diffuse += DecodeDirectionalSpecularLightmap (bakedColor, bakedDirTex, normalWorld, false, 0, o_gi.light);
// Indirect 漫反射,镜面都是保存在unity_Lightmap中,竖直中间分开
//调整o_gi.light2
half2 uvIndirect = data.lightmapUV.xy + half2(0.5, 0);
bakedColor = DecodeLightmap(UNITY_SAMPLE_TEX2D(unity_Lightmap, uvIndirect));
bakedDirTex = UNITY_SAMPLE_TEX2D_SAMPLER(unity_LightmapInd, unity_Lightmap, uvIndirect);
o_gi.indirect.diffuse += DecodeDirectionalSpecularLightmap (bakedColor, bakedDirTex, normalWorld, false, 0, o_gi.light2);
//预计算GI
#ifdef DYNAMICLIGHTMAP_ON
// Dynamic lightmaps unity_DynamicLightmap unity_DynamicDirectionality unity_DynamicNormal
fixed4 realtimeColorTex = UNITY_SAMPLE_TEX2D(unity_DynamicLightmap, data.lightmapUV.zw);
//间接漫反射
half3 realtimeColor = DecodeRealtimeLightmap (realtimeColorTex);
#ifdef DIRLIGHTMAP_OFF
o_gi.indirect.diffuse += realtimeC
#elif DIRLIGHTMAP_COMBINED
half4 realtimeDirTex = UNITY_SAMPLE_TEX2D_SAMPLER(unity_DynamicDirectionality, unity_DynamicLightmap, data.lightmapUV.zw);
//调整漫反射
o_gi.indirect.diffuse += DecodeDirectionalLightmap (realtimeColor, realtimeDirTex, normalWorld);
#elif DIRLIGHTMAP_SEPARATE
half4 realtimeDirTex = UNITY_SAMPLE_TEX2D_SAMPLER(unity_DynamicDirectionality, unity_DynamicLightmap, data.lightmapUV.zw);
half4 realtimeNormalTex = UNITY_SAMPLE_TEX2D_SAMPLER(unity_DynamicNormal, unity_DynamicLightmap, data.lightmapUV.zw);
//调整o_gi.light3
o_gi.indirect.diffuse += DecodeDirectionalSpecularLightmap (realtimeColor, realtimeDirTex, normalWorld, true, realtimeNormalTex, o_gi.light3);
//gi里的信息全放入indirect的diffuse中
o_gi.indirect.diffuse *=
//有反射探头,设置镜面光源信息。
if (reflections)
half3 worldNormal = reflect(-data.worldViewDir, normalWorld);
#if UNITY_SPECCUBE_BOX_PROJECTION
half3 worldNormal0 = BoxProjectedCubemapDirection (worldNormal, data.worldPos, data.probePosition[0], data.boxMin[0], data.boxMax[0]);
half3 worldNormal0 = worldN
half3 env0 = Unity_GlossyEnvironment (UNITY_PASS_TEXCUBE(unity_SpecCube0), data.probeHDR[0], worldNormal0, 1-oneMinusRoughness);
#if UNITY_SPECCUBE_BLENDING
const float kBlendFactor = 0.99999;
float blendLerp = data.boxMin[0].w;
UNITY_BRANCH
if (blendLerp & kBlendFactor)
#if UNITY_SPECCUBE_BOX_PROJECTION
half3 worldNormal1 = BoxProjectedCubemapDirection (worldNormal, data.worldPos, data.probePosition[1], data.boxMin[1], data.boxMax[1]);
half3 worldNormal1 = worldN
half3 env1 = Unity_GlossyEnvironment (UNITY_PASS_TEXCUBE(unity_SpecCube1), data.probeHDR[1], worldNormal1, 1-oneMinusRoughness);
o_gi.indirect.specular = lerp(env1, env0, blendLerp);
o_gi.indirect.specular = env0;
o_gi.indirect.specular = env0;
//反射探头的信息存入到gi的indirect镜面中
o_gi.indirect.specular *=
262 --------UnityStandardBRDF.cginc
263 // Main Physically Based BRDF
264 // Derived from Disney work and based on Torrance-Sparrow micro-facet model
BRDF = kD / pi + kS * (D * V * F) / 4
I = BRDF * NdotL
269 // * NDF (depending on UNITY_BRDF_GGX):
a) Normalized BlinnPhong
272 // * Smith for Visiblity term
273 // * Schlick approximation for Fresnel
274 half4 BRDF1_Unity_PBS (half3 diffColor, half3 specColor, half oneMinusReflectivity, half oneMinusRoughness,
half3 normal, half3 viewDir,
UnityLight light, UnityIndirect gi)
half roughness = 1-oneMinusR
//nh,能射入眼睛的光线的角度 也叫半线
half3 halfDir = Unity_SafeNormalize (light.dir + viewDir);
half nl = light.
//nh,半线与法线夹角,夹角越少,射入眼睛的光越大
half nh = BlinnTerm (normal, halfDir);
//射线与法线夹角
half nv = DotClamped (normal, viewDir);
//光线与法线夹角
half lv = DotClamped (light.dir, viewDir);
//半线与光线夹角
half lh = DotClamped (light.dir, halfDir);
291 #if UNITY_BRDF_GGX
//遮挡函数
half V = SmithGGXVisibilityTerm (nl, nv, roughness);
//法线分布函数 1/Pi
half D = GGXTerm (nh, roughness);
//遮挡函数
half V = SmithBeckmannVisibilityTerm (nl, nv, roughness);
//法线分布函数 1/Pi
half D = NDFBlinnPhongNormalizedTerm (nh, RoughnessToSpecPower (roughness));
301 #endif
half nlPow5 = Pow5 (1-nl);
half nvPow5 = Pow5 (1-nv);
half Fd90 = 0.5 + 2 * lh * lh *
//disney Diffuse 菲涅尔 边角有更亮的光
half disneyDiffuse = (1 + (Fd90-1) * nlPow5) * (1 + (Fd90-1) * nvPow5);
// HACK: theoretically we should divide by Pi diffuseTerm and not multiply specularTerm!
// BUT 1) that will make shader look significantly darker than Legacy ones
// and 2) on engine side "Non-important" lights have to be divided by Pi to in cases when they are injected into ambient SH
// NOTE: multiplication by Pi is part of single constant together with 1/4 now
//镜面系数
half specularTerm = max(0, (V * D * nl) * unity_LightGammaCorrectionConsts_PIDiv4);// Torrance-Sparrow model, Fresnel is applied later (for optimization reasons)
half diffuseTerm = disneyDiffuse *
//Gi镜面,可以看到oneMinusReflectivity越高,grazingTerm越低,specColor越高(本身镜面颜色)
half grazingTerm = saturate(oneMinusRoughness + (1-oneMinusReflectivity));
//GI non-direction与direction的BRDF如下情况
//light.color
实时方向光直接信息
实时方向光直接信息
//gi.diffuse
直接与间接光源信息
间接光源信息
SH(光源探头)间接光源信息
//gi.specular
half3 color =
diffColor * (gi.diffuse + light.color * diffuseTerm)
+ specularTerm * light.color * FresnelTerm (specColor, lh)
+ gi.specular * FresnelLerp (specColor, grazingTerm, nv);
return half4(color, 1);
  整个代码并不多,但是对于前面所说所有东东,在这都有一个完整的解释,这份代码来告诉我们,那些金属性,光滑度,GI中幅射图,方向图,还有光源探头,反射探头所起的作用。
BRDF&光照模型:
  如下是现有光照模型没有考虑的问题:
  光照现象,漫反射并不是各个方面平均发散. & &----微表面模型(NDF).&&
  菲涅尔定理(Fresnel) & & & & & & & & & & & & & & &&&----光源在边角处有更明亮的反光。
  能量守恒,反射的光不能超过入射的光. & & & & &----遮挡因素,越光滑镜面越集中越亮&
  普通的着色模型假定着色的区域是一个平滑的表面,表面有一个法线,而微表面则认为,着色区域是一个无数比入射光线覆盖范围更小的微小表面组成的粗糙区域,这个微小表面是光滑的镜面反射,因为着色区域并不能一个法向量来表示表面的方向,转面代替用一概率分布函数(NDF)来表示。一般来说,分别用如下字母表示:
  D&用来表示法线分布。
  F&用来菲涅尔影响,光源在边角处有更明亮的反光。
  G/V&用来表示凹凸表面间的遮挡因素(Unity用V来表示)&
  如下是Unity相对应BRDF的处理
  先要说明每个引擎对BRDF处理各不同,在这只介绍Untiy的实现:
  D&采用GGX与BlinnPhong二种法线分布函数,BlinnPhong比较简单,效率高。
  F&采用简化的Disney&Fresnel方式求得菲涅尔影响。
  G/V&采用GGX与Beckmann二种技术,可以看到,光滑度是个关键参数。
  针对Unity5.3简化过的Disney&Fresnel,简单分析下.
  Nl:法线与灯光的夹角,夹角越大,这个值越小。
  Nv:法线与视线的夹角,夹角越大,这个值越小。
  Lh:灯光与视线的半线与法线的夹角,其中灯光与视线的半线就是灯光与视线的平均线,简单来说,这个线与法线重合,这条由灯光发出来的射线才能进入我们的眼镜。
  假定&fd90不变,nl与nl的角度越大,那么nlPow5与nvPow5的值越大,最终结果越大,这也是菲涅尔想表达的,光源在边角处有更明亮的反光。
  在Unity中,可以看到,D与V影响镜面反射,F影响漫反射,特别说明,只有Unity是这样处理。
  其中,可以看到反射率(也就是金属性)影响的是GI的镜面反射,也就是反射探头。
  其余的部分挑的说明下:
  顶点着色器中,填充VertexOutputForwardBase&信息,其中ambientOrLightmapUV(half4)&如果包含烘培GI,xy填充相应烘培GI的UV坐标,如果包含预计算GI,zw填充为预计算GI的UV坐标。如果是非静态模型,不包含GI信息,相应light&probe提供的光源信息放入rgb中。&
  片断着色器中,每个像素要得到对应像素上的Unity&GI信息,相应的,Unity&GI中的属性light并不是表示光源,而是当前像素受如主光源,幅射,镜面对当前像素的影响,每个像素对应的light都有差别,千万不要看到写的是个light,就把它当做光照,这样所有理解都不对了。
  其中如果只有烘培GI,当前像素的Unity&GI中参数light不提供信息,indirect里的漫反射包含烘培光源的光照。而预计算GI中当前像素的light本身就是全局光源,indirect只包含物体之间的漫反射信息,而非静态模型中当前像素只有实时光源等直接光照信息,其周围的静态模型的反射光只有通过光探头得到SH信息。
  FragmentGI里常见结构:
  1 UnityLight:
  包含当前像素中光源颜色,方向,法线与光源方向点积
  2 UnityIndirect:
  包含当前像素中diffuse漫反射,specular镜面信息
  3 UnityGI:特别注意,里面的light是UnityLight类型,并不表示光源,而是用来表示当前像素受光源影响的量。
  Gi.light&如果烘陪GI信息,则使用当前主光源填充UnityLight,如果有烘陪GI信息,则填充为空。
  Gi.light2&当烘培GI启用高光后,才会调用。
  Gi.light3&预计算GI启用高光后,才会调用。
  UnityGI在根据函数UnityGlobalIllumination被填充,我们可以分析得到动态模型,使用SH得到漫反射信息。如果没有烘培GI,我们需要实时全局光源,故gi.light是像素所受全局方向光。烘培GI,GI光照信息保存在gl.light2中,gi漫反射直接取光照图里的diffuse.预计算GI,GI光照信息保存在gl.light3中,gi漫反射添加光照图里的diffuse.而反射探头用来添加反射的信息到GI里的镜面信息中了,其中Occlusion&控制gi的diffuse与specular系数。(n*=occlusion)&   
  其中UNITY_SHOULD_SAMPLE_SH&当前渲染的动态模型,使用SH得到间接的漫反射信息,其中UNITY_SHOULD_SAMPLE_SH如下定义。#define&UNITY_SHOULD_SAMPLE_SH&(&defined&(LIGHTMAP_OFF)&&&&defined(DYNAMICLIGHTMAP_OFF)&)&
  预计算GI与烘培GI
  烘培GI如上代码中分析得到,选择non-direction,只有一张图,保存直接与间接光照所有信息,选择direction后,会保存方向,选择specular后,上面二张图,长度扩大一倍,保存镜面有关信息。
  其中预计算GI,选择non-direction,只有一张图,不保存直接光照,只保存间接光照,选择direction,保存方向,选择specular后,不同于烘培GI,会新增一张纹理保存镜面相关信息(从代码来上看,可能是组织过的法线)&
  反射探头:
  unity_SpecCube0_ 全局反射探头&unity_SpecCube1_当前模型受影响的反射探头。
  FragmnetGI:得到全局反射探头与用户定义的反射探头位置,AABB,IsHDR.
  UnityGlobalIllumination:片断像素中得到反射探头影响镜面值,可以看到,SpecCube0与SpecCube1通过深度影响gi间接光源上的镜面颜色。
  BoxProjectedCubemapDirection:影响worldNormal(反视线进过法线后的反射)
  Unity_GlossyEnvironment:可以看到&,光滑值影响LOD值,越光滑越清晰。 UNITY_SAMPLE_TEXCUBE&从cubemap取值。&
  光源探头:
  vertForwardBase:VertexOutputForwardBase的ambientOrLightmapUV设置颜色,从这可以看到,光源探头实际不影响静态的物体,你如果看到有影响,只是因为周围的非静态模型颜色反差造成给你的影响。
  UnityGlobalIllumination:灯光探头的值赋到gi间接光源上的漫反射上。
  :今天看UE4中的环境反射文档,我去,Unity里的做法完全是参照UE4的,通过上面的着色器代码,我们可以完全理解下面这个链接里所说的。
阅读(...) 评论()

我要回帖

更多关于 unity5 实时gi 的文章

 

随机推荐