unity5 GI全局光照 问题集锦解答

Unity 5 全局光照系统Enlighten问题

Unity 5正式版面世已经一段时间,许多开发者都已经在使用Unity 5进行开发。大家在使用Unity 5时或多或少都会碰到一些问题,今天我们Unity的官方技术工程师,柳振东将在本文中针对Unity 5中全新的Enlighten全局光照系统的一些问题,以及相应的解答与大家进行分享。
        为什么Unity 5的全局光照系统会让大家踩坑呢? 因为Unity 5取缔了Unity 4中使用的Beast全局光照系统,采用了全新的Enlighten全局光照系统。而这两套全局光照系统的算法并不一样,反映到使用上就是各种参数与操作细节的变化。
        对于没有系统学习过计算机图形学的开发者,还是非常建议大家去了解一下全局光照明模型的,因为大家可能对局部光照明模型(就是我们平常所说的实时光照)比较熟悉,有时可能会把局部光照明模型的一些知识用在全局光照明系统上,白白花费时间做了一些无用功。
        下面挑选一些常见问题与大家分享。
        
        为什么场景烘焙出来的lightmap上有Realitime灯光的颜色?

        相信不少开发者都为这样的问题头疼过,因为灯光明明是Realtime的,怎么可能会被烘焙到lightmap里面去呢?但是这在Unity 5里并不是一个bug
        首先我们要知道Unity 5中新增一种全局光照明的使用方式:Precomputed Realtime GI(预计算实时全局光照明),简称:实时GI。而另一种Bake GI就是大家在Unity 4中一直用过来的ligtmap烘焙方式。
        实时GIBake GI一样,也需要预先的Bake过程,但是与Bake GI不同,实时GI并不预计算场景中光线的反射信息,而是预计算场景中静态物体表面所有可能的反射光路,然后在游戏运行时结合灯光的位置、方向等信息实时计算出全局光照的结果。
        这个计算机制使得预计算GI具备非常大的优势,在使用预计算GI的灯光,其位置、方向、强度、颜色等各种信息都可以在运行时实时变化。
        举例:使用预计算GI我们就可以在场景中实现非常真实的日光变化效果(别忘了我们其实是在使用全局光照明模型啊,比实时光照效果强多了)。
        但是,问题来了,预计算GI有一点非常容易让人混淆,那就是预计算GI需要灯光类型是RealtimeWTFRealtime难道不是实时灯光吗?怎么变成全局光照明模型的灯光了?
        Unity 5的灯光属性中增加了一项,叫做Bounce Intensity,如下图所示:

 


        Bounce Intensity是指全局光照中的间接光强度,要理解这点可以简单地把全局光照理解为直接光照与间接光照两部分。直接光照指直接从光源射到物体上的光,而间接光照指从其他物体表面反射而来的光。那么显而易见,直接光照的部分其实就是局部光照模型,也就是实时光照计算出来的结果。
        回到正题,Bounce IntensityUnity 5 中默认值是1,意思就是说一盏Realtime灯光默认是使用预计算GI的,并且间接光照的强度不做改变(大于1是强制增大间接光照,这在一些由室外光照射入洞穴这类的场合中可能会用到)。而lighting窗口中的预计算GI选项也是默认开启的,如下图所示:
        

 


        所以如果你并不更改这些设置,即使看起来你好像只使用了Realtime的灯光,但是真正运行的时候却其实是在使用全局光照系统!
        接下来要说明的一点是,只要一盏灯的Bounce Intensity大于0Unity就会认为你需要使用全局光照系统。那么即使你在lighting窗口中取消勾选Precomputed Realtime GIUnity依然会尝试使用全局光照。
        既然已经取消了预计算GI的选项,Unity会去使用另外一种全局光照的方式,Bake GI(只要你还勾选着Bake GI)。而结果就是,烘焙出来的lightmap里也有那盏Bounce Intensity大于0Realtime灯光的信息。
        总结:Unity 5中灯光有个新属性Bounce Intensity,这个值只要大于0系统就会认为你需要使用预计算GI计算这个灯光,而如果此时Precomputed Realtime GI没有被勾选,而Bake GI勾选了那么Unity会把这个灯光也烘焙到lightmap中去。

        为什么在Unity 5中动态更换lightmap没有作用?

        在场景中动态更换lightmap是挺常用的需求。例如:同一个场景需要白天与黑夜两个时间的效果,那么我们就会烘焙两张不同的lightmap,然后用脚本在运行时切换。在Unity 4中可以通过把lightmap资源loadTexture2D中,然后赋值给一个LightmapData结构,最后赋给LightmapSettings.lightmaps来达到更换当前使用lightmap的目的。
        但是在Unity 5中会发现使用这个方法并不凑效。是因为lightmap没有正确更换吗?不是的,其实lightmap已经更换了,问题是在于此时使用lightmap的物体并不知道自己应该使用哪张lightmap,也不知道要从lightmap的哪个地方开始采样,而这其实就是每个Renderer上的两个参数,lightmapIndexlightmapScaleOffset
        现在大家肯定会问为什么在Unity 4中没有问题呢?那是因为这些信息在Unity 4中已经被序列化进场景文件中,当场景加载进来的时候这两个值就被赋回到每个Renderer中。而在Unity 5中,lightmapIndexlightmapScaleOffset因为多场景编辑的逻辑需要,不再被序列化到场景文件中去了,而是存在于一个伴随lightmap烘焙产生的一个新文件,Lighting Data Asset中去了(这个文件在初期的5.x中叫做lightmapSnapShot)。这个文件与lightmap在同层目录中,并且可以在Editor中随时更换当前使用的LightingData文件,如下图所示:

 


        那么回归正题,既然LightingData文件存储着lightmapIndexlightmapScaleOffset,那么只要保证LightingData文件能被最终的可执行文件使用不就没有问题了吗?其实这样是没有问题的,如果我们只需要更换灯光条件不同情况下的lightmap,而场景本身并没有更改的话,那么多套lightmap对于场景中的静态物体Renderer而言也只需要同一套lightmapIndexlightmapScaleOffset信息而已。所以在这种情况下要达到运行时更换lightmap的效果,只要保证lighting窗口的Ligtmaps页面中Light Data Asset里选中了正确的LightingData文件即可(因为很多开发者习惯性删除掉这个文件,因此也就丢失了lightmapIndexlightmapScaleOffset信息)。
        简单的情况我们简单地使用LightingData文件即可。但是还有一种情况,如果我们需要场景本身也有所改变要怎么办呢?
        举例:我可能需要原始的场景lightmap与一个被炸弹破坏过后的场景lightmap,由于场景中的静态物体有所改变,这个时候两次烘焙会产生两个数据不同LightingData文件,无法简单使用其中一个。然而比较可惜的是现在Unity并不能在运行时切换LightingData文件,其设计之初就仅仅作为Editor使用的资源。
        那么对于这种情况,我们需要自己记录下每个Renderer上的lightmapIndexlightmapScaleOffset信息,然后在更换lightmap的时候把这个信息还原回去。
        具体做法有很多种,基本原理都是把lightmapIndexlightmapScaleOffset序列化起来。比如说我们可以给每个静态物体挂一个脚本,在里面定义一个包含Render,lightmapIndexlightmapScaleOffset的结构,然后一个Save函数用来在每次烘焙lightmap之后把lightmapIndexlightmapScaleOffset序列化进结构中,一个Load函数用来在切换lightmap时还原每个RendererlightmapIndexlightmapScaleOffset信息。现在这个问题就解决了。

 

 

 

    

 详解Unity 5 全局光照系统Enlighten问题(下)

 我们在昨天给大家解答了:为什么场景烘焙出来的lightmap上有Realitime灯光的颜色?和为什么在Unity 5中动态更换lightmap没有作用? 这两个问题。今天,我们继续给大家解答Unity 5 全局光照系统Enlighten中的其他常见问题。
   请阅读:详解Unity 5 全局光照系统Enlighten问题(上)
为什么烘焙的point灯光会有一圈圈的色阶变化?
   大家在烘焙lightmap的时候可能会发现类似下图的奇怪效果。

 


   图中我们使用了一盏Bakedpoint light,烘焙之后发现光照效果会出现一圈圈的色阶突变。
   原因是我们使用的是压缩版本的lightmap。如下图Lighting窗口中选项所示:

 


   这个压缩虽然可以帮助我们减少游戏最后的打包体积,但是对场景的光照效果也会产生影响,所以对于要追求最好的光照效果的场景建议不要勾选此选项。
   最后我们来看看去掉此选项后的效果,现在,色阶变化不存在了。

 


    为什么在Realtime灯光下的效果和改为Baked烘焙的效果差别很大?
    这个的问题美术同学会经常遇见。美术同学一般在烘焙场景之前会先把灯光都设为Realtime,来实时查看调整灯光参数后的效果。调整到较满意的效果之后,就把灯光类型改为Baked然后进行烘焙。
   Unity 4中这样做一般可以达到烘焙之后的效果与实时灯光的效果比较接近,但是在Unity 5中可能会发现差别很大。究其原因主要有二点。
   1、在上面我们已经提到,新的灯光参数Bounce Intensity,这个参数的调整会影响最终烘焙效果中间接光分量的比例。
   2Unity 5中对GammaLinear颜色空间的实现做了调整以更符合真实情况,但这也导致实时灯光效果与烘焙效果在两种颜色空间中存在差异。
   所以,建议美工同学在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来设定某个选定的Objectlightmap中占用像素的多少,默认是1对于重要的物体通过提高这个数值来增加此物体使用的lightmap像素,反之我们可以把这个值设为01之间来减少此物体所使用的lightmap像素。选项如下图所示:



为大家解答的Unity 5 全局光照系统Enlighten问题就到这里了

 

 

 

 

 

 

 Unity 5.4GPU Instancing功能简介

Unity5.4 Beta版本中引入了一种新的Draw Call Batching方式——GPU Instancing。当场景中有大量使用相同材质和网格的物体时,通过GPU Instancing可以大幅降低Draw Call数量。本文会简单介绍GPU Instancing的原理并引导读者修改已有的Shader来开启Instancing


什么是GPU Instancing
GPU Instancing是指由GPU和图形API支持的,用一个Draw Call同时绘制多个Geometry相同的物体的技术。

 


上图中的场景有数千块陨石,但只有三种陨石模型,这种情况下使用Instancing之后只需要数十个Draw Call
D3D11中,Instanced Draw Call API如下所示:

[C] 纯文本查看 复制代码

void DrawIndexedInstanced(

  [in] UINT IndexCountPerInstance,

  [in] UINT InstanceCount,

  [in] UINT StartIndexLocation,

  [in] INT  BaseVertexLocation,

  [in] UINT StartInstanceLocation

);


注意前两个参数:IndexCountPerInstanceInstanceCount,这是不同于一般Draw Call API的地方。你需要告诉D3D每个Instance用到多少个顶点索引以及这个Draw Call要画多少个Instances
那么如何做到像上图中那样每块石头都有不同的位置、旋转和大小呢?在使用Instancing时,我们一般会把世界矩阵这种每个Instance独有的数据放到一个额外的Buffer中以供Shader访问,可以是第二个Vertex Buffer,也可以是Constant Buffer

Instancing的应用场景
Instancing并不是总能提高性能,所以有必要明白Instancing技术可以做什么、不能做什么。

Instancing能做什么:
通过减少Draw Call数量来降低CPU开销。

Instancing不能做什么:
减少GPU的负载。实际上,Instancing还会在GPU上带来一些额外的开销。

具体来说,如果你的场景具备以下条件,使用Instancing可能会给你带来性能提升。
有大量使用相同材质和相同网格的物体
性能受制于过多的Draw Call (图形驱动在CPU上负载过大)
在实际的游戏项目中,最合适使用Instancing来优化的是植被系统。因为通常植被系统需要绘制大量相同的树木和草,使用Instancing之后Draw Call的消耗会大幅降低。

Unity 5.4中使用Instancing
类似于Static / Dynamic BatchingInstancing是一种新的合并Draw Call的方式
适用于MeshRenderer组件和Graphics.DrawMesh()
需要使用相同的MaterialMesh
需要把Shader改成Instanced的版本
当所有前提条件都满足时,Instancing是自动进行的,并且比Static/Dynamic Batching有更高的优先级

Instancing的实现
Per-Instance Data(世界矩阵、颜色等自定义属性)打包成Uniform Array,存储在Instance Constant Buffers
对于可以使用InstancingBatch,调用各平台图形APIInstanced Draw Call,这样会为每一个Instance生成一个不同的SV_InstanceID
Shader中使用SV_InstanceID作为Uniform Array的索引获取当前InstancePer-Instance Data

 


如何修改Shader以支持Instancing
自定义Vertex / Fragment Shader
下面的代码片段展示了如何把一个简单的Unlit Shader修改为支持Instancing的版本。红色字体的部分是在已有Shader基础上需要添加或修改的地方。

[C] 纯文本查看 复制代码

Shader "SimplestInstancedShader"

{

    Properties

    {

        _Color ("Color", Color) = (1, 1, 1, 1)

    }

 

    SubShader

    {

        Tags { "RenderType"="Opaque" }

        LOD 100

 

        Pass

        {

            CGPROGRAM

            #pragma vertex vert

            #pragma fragment frag

            #pragma multi_compile_instancing

            #include "UnityCG.cginc"

 

            struct appdata

            {

                float4 vertex : POSITION;

                UNITY_INSTANCE_ID

            };

 

            struct v2f

            {

                float4 vertex : SV_POSITION;

                UNITY_INSTANCE_ID

            };

 

            UNITY_INSTANCING_CBUFFER_START (MyProperties)

                UNITY_DEFINE_INSTANCED_PROP (float4, _Color)

            UNITY_INSTANCING_CBUFFER_END

             

            v2f vert (appdata v)

            {

                v2f o;

 

                UNITY_SETUP_INSTANCE_ID (v);

                UNITY_TRANSFER_INSTANCE_ID (v, o);

 

                o.vertex = UnityObjectToClipPos (v.vertex);

                return o;

            }

             

            fixed4 frag (v2f i) : SV_Target

            {

                UNITY_SETUP_INSTANCE_ID (i);

                return UNITY_ACCESS_INSTANCED_PROP (_Color);

            }

            ENDCG

        }

    }

}


下面我们来逐一解释每一处的修改是什么意思。

#pragma multi_compile_instancing
“multi_compile_instancing”会使你的Shader生成两个Variant,其中一个定义了Shader关键字INSTANCING_ON,另外一个没有定义此关键字。

除了这个#pragma指令,下面所列其他的修改都是使用了在UnityInstancing.cginc里定义的宏(此cginc文件位于Unity_Install_Dir\Editor\Data\CGIncludes)。取决于关键字INSTANCING_ON是否被定义,这些宏将展开为不同的代码。

UNITY_INSTANCE_ID
用于在Vertex Shader输入 / 输出结构中定义一个语义为SV_InstanceID的元素。

UNITY_INSTANCING_CBUFFER_START(name) / UNITY_INSTANCING_CBUFFER_END
每个Instance独有的属性必须定义在一个遵循特殊命名规则的Constant Buffer中。使用这对宏来定义这些Constant Buffer“name”参数可以是任意字符串。

UNITY_DEFINE_INSTANCED_PROP(float4, _Color)
定义一个具有特定类型和名字的每个Instance独有的Shader属性。这个宏实际会定义一个Uniform数组。

UNITY_SETUP_INSTANCE_ID(v);
这个宏必须在Vertex Shader的最开始调用,如果你需要在Fragment Shader里访问Instanced属性,则需要在Fragment Shader的开始也用一下。这个宏的目的在于让Instance IDShader函数里也能够被访问到。

UNITY_TRANSFER_INSTANCE_ID(v, o);
Vertex Shader中把Instance ID从输入结构拷贝至输出结构中。只有当你需要在Fragment Shader中访问每个Instance独有的属性时才需要写这个宏。

UNITY_ACCESS_INSTANCED_PROP(_Color)

访问每个Instance独有的属性。这个宏会使用Instance ID作为索引到Uniform数组中去取当前Instance对应的数据。

最后我们需要提一下UnityObjectToClipPos
在写Instanced Shader时,通常情况下你并不用在意顶点空间转换,因为所有内建的矩阵名字在Instanced Shader中都是被重定义过的。比如unity_ObjectToWorld实际上会变成unity_ObjectToWorldArray[unity_InstanceID]UNITY_MATRIX_MVP会变成mul(UNITY_MATRIX_VP, unity_ObjectToWorldArray[unity_InstanceID])。注意到如果直接使用UNITY_MATRIX_MVP,我们会引入一个额外的矩阵乘法运算,所以推荐使用UnityObjectToClipPos / UnityObjectToViewPos函数,它们会把这一次额外的矩阵乘法优化为向量-矩阵乘法。

Surface Shader
如果想把一个Surface Shader改写成支持Instancing的版本,你只需要加上“#pragma multi_compile_instancing” 就可以了。设置Instance ID的代码会自动生成。定义或访问每个Instance独有属性的方法同Custom Vertex / Fragment Shader
另外,你可以在Project窗口右键单击,选择Create->Shader->Standard Surface Shader (Instanced)来创建一个示例Shader

使用Instancing的限制
下列情况不能使用Instancing
使用Lightmap的物体
受不同Light Probe / Reflection Probe影响的物体
使用包含多个PassShader的物体,只有第一个Pass可以Instancing
前向渲染时,受多个光源影响的物体只有Base Pass可以instancingAdd Passes不行

另外,由于Constant Buffer的尺寸限制,一个Instanced Draw Call能画的物体数量是有上限的(参见UnityInstancing.cginc中的UNITY_MAX_INSTANCE_COUNT
最后需要再次强调的是,InstancingShader上有额外的开销,并不是总能提高帧率。永远要以实际Profiling的结果为准!

 

 

 

 

 

Unity 5.4 新功能:光照探头代理体

Unity 5.4已经进入到Beta阶段,其中的一个突出功能是光照探头代理体(LPPV)。在这里将会向大家介绍什么是LPPV,并且通过一些小实验来演示它是如何进行工作的。

什么是光照探头代理体 
LPPV是一个可以为无法使用烘焙光照贴图的大型动态物体提供更多光照信息的组件,想象一下蒙皮网格或者粒子系统。是的,接受烘焙光照信息的粒子系统,太棒了!

 


如何使用LPPV组件
LPPV组件从属于光探头组。这个组件位于 Component -> Rendering -> Light Probe Proxy Volume下,默认情况下,这个组件看起来是如下:

 


这个组件你需要添加到诸如网格甚至光照探头组这样的游戏对象中。那些要应用上LPPV的游戏对象需要具有MeshRenderer或者Renderer组件,并且将Light Probes属性设置为“Use Proxy Volume”

 


你可以通过设置Proxy Volume Override选项来使用其它GameObject上的LPPV组件,只需拖放这个GameObject到每一个你想要使用它的Renderer组件的属性域里面。
例如:如果你将LPPV组件添加到光照探头组对象中,那么你就可以通过Proxy Volume Override属性在所有Renderer组件中共享它:

 


设置包围盒:
包围盒的设置有以下三个选项:

· 自动局部

· 自动全局

· 自定义


自动局部:
这是默认的属性设置  包围盒会在局部空间内计算,插值光探头位置将在这个包围盒内产生。包围盒计算包括了当前以及其下所有层级的将Light Probes属性设置为Use Proxy VolumeRenderer组件,自动全局也是一样的方式。

 


自动全局:
将会计算世界坐标轴对齐的包围盒。自动全局以及自动局部选项应该与Proxy Volume Override属性联合使用在其它的Renderer组件上。另外你可以通过将同一个LPPV组件设置到层级的父节点来使这个层级下的所有GameObject使用这个LPPV组件。
这个模式与自动局部的区别在于在自动局部模式下,当从一个父GameObject下的多层级GameObject使用同一个LPPV组件时包围盒计算会更加耗时,但是计算出来的包围盒尺寸会更小,这就意味着光照数据会更加紧凑。

自定义:
该模式使你可以自己在UI中编辑包围盒,修改Inspector窗口中的尺寸以及起始点或者使用工具来在场景视图中编辑。包围盒在游戏对象的局部空间中指定。在这种情况下你需要确定所有的Renderer组件所在的GameObjectLPPV的包围盒内。

 


设置分辨率/密度
在设置完成包围盒后,下面你需要考虑代理体的密度和分辨率。要实现这个在分辨率模式下有两个选项:

自动:
这是默认的属性设置  为密度设置一个值,例如每单位的探头数量。每单位的探头数量在X,Y以及Z轴上计算,所以(探头数量)是由包围盒的尺寸决定的。

自定义:
通过下拉菜单来设置X,Y以及Z轴上的分辨率值。值从1开始以2的乘方递增直到32.你最多可以有32x32x32 个插值探头

 


在使用LPPV时性能度量的考虑:
请记住每个64个插值光探头的批量的插值计算需要大概0.15毫秒的CPU时间(i7 – 4G赫兹)(使用Profiler观察)。光探头插值计算是多线程的,任何小于或等于64个插值光照探头将不会是多线程的,将只在主线程中运行。
使用Unity的内置Profiler,在Timeline视图下你可以看到主线程上的BlendLightProbesJob,如果你将插值光探头数量增加到超过64个,你将同样在工作线程中看到BlendLightProbesJob

 


当只有一个批次的64个插值光探头的时候将只会运行在主线程上,当有多个批次(大于64)的时候将会安排在主线程上运行一个,其它的运行到工作线程上,但是这个行为只针对单个LPPV。如果你有多个LPPV,并且每个拥有少于64个插值光探头的话,那么他们都会运行在主线程上。

硬件需求:
该组件需要至少支持Shader Model 4的图形硬件以及相应的API支持,包括支持32位浮点格式以及线性过滤的3D纹理。
使用ShadeSHPerPixel的粒子系统着色器的范例:
标准着色器支持这个特性。如果你想将其添加到一个自定义着色器中,使用ShadeSHPerPixel函数。看看这个范例可以了解如何使用这个函数:

[C#] 纯文本查看 复制代码

Shader "Particles/AdditiveLPPV" {

  

Properties

{

    _MainTex ("Particle Texture", 2D) = "white" {}

    _TintColor ("Tint Color", Color) = (0.5,0.5,0.5,0.5)

}

  

Category

    {

    Tags {"Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent"}

    Blend SrcAlpha One

    ColorMask RGB

    Cull Off Lighting Off ZWrite Off

  

    SubShader

    {

        Pass

        {

            CGPROGRAM

            #pragma vertex vert

            #pragma fragment frag

            #pragma multi_compile_particles

            #pragma multi_compile_fog

            // Don’t forget to specify the target

            #pragma target 3.0

  

            #include "UnityCG.cginc"

            // You have to include this header to have access to ShadeSHPerPixel

            #include "UnityStandardUtils.cginc"

  

            fixed4 _TintColor;

            sampler2D _MainTex;

  

            struct appdata_t

            {

                   float4 vertex : POSITION;

                   float3 normal : NORMAL;

                   fixed4 color : COLOR;

                   float2 texcoord : TEXCOORD0;

            };

  

            struct v2f

            {

                   float4 vertex : SV_POSITION;

                   fixed4 color : COLOR;

                   float2 texcoord : TEXCOORD0;

                   UNITY_FOG_COORDS(1)

                   float3 worldPos : TEXCOORD2;

                   float3 worldNormal : TEXCOORD3;

            };

  

            float4 _MainTex_ST;

            v2f vert (appdata_t v)

            {

                  v2f o;

                  o.vertex = UnityObjectToClipPos(v.vertex);

                  o.worldNormal = UnityObjectToWorldNormal(v.normal);

                  o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;

                  o.color = v.color;

                  o.texcoord = TRANSFORM_TEX(v.texcoord,_MainTex);

                  UNITY_TRANSFER_FOG(o,o.vertex);

                  return o;

             }

              

             fixed4 frag (v2f i) : SV_Target

             {

                    half3 currentAmbient = half3(0, 0, 0);

                    half3 ambient = ShadeSHPerPixel(i.worldNormal, currentAmbient, i.worldPos);

                    fixed4 col = _TintColor * i.color * tex2D(_MainTex, i.texcoord);

                    >col.xyz += ambient;

                    UNITY_APPLY_FOG_COLOR(i.fogCoord, col, fixed4(0,0,0,0)); // fog towards black due to our blend mode

                    return col;

             }

             ENDCG

         }

      }

   }

}

 

 

 

 

 

 

 

Unity5 新功能解析--GI(全局光)

Unity5带来的最大的改变就是全新的GI,在烘焙引擎上抛弃了4的beast,使用了虚幻采用的Enlighten,引入了实时的全局光。这里对UNITY5的新的光照系统做一总结.

· 新加入了一种只用于烘焙的光照类型 Area Light

              面积光的光源有形状,是一个矩形区域,有位置,有方向,方向是超矩形的一面,矩形的背面没有光,并且随距离衰减直到没有。它用于模拟大量的光源和在一起的效果,如街道,但是因为计算复杂,所以只用于烘焙

· 全局光照

构成 : 可实时更新的lightmap + 可实时更新的光照探头(light probe)+ 可实时更新的cubemap(Reflection probe)
实时全局光只实时计算物体之间的bounce light(物体之间来回反射的光)
实时全局光的实现:静态物体之间的bounce light可以在预先计算阶段搞定(light map)
                                     被静态物体照射到的动态物体,通过实时更新的光照探头搞定
                                      被动态物体照射到的物体,还不支持
相比UNITY4来讲,多出来的实时全局光部分应该是多出了lightmap 光照探头这些可以实时更新 而不是定死的
如下图在光源变化下,静态物体的对地板的反射绿色光也在跟着变化
   
此外UNITY5里面的标准材质的自发光在全局光计算中可以当做光源,即可以照亮周围物体并产生阴影,这是一个很屌的效果!,如下图,

 ,可以调节emission的GI模式,
自发光的GI效果如图

 

这可以表现一个很真实的发光体,相信看到这美术同学应该有点小激动吧~








    Unity5 的全局光照除了新引入的实时GI之外,也有过去的离线烘焙的方式,或者也可以选择二者合用的方式(不过这不是一个省效率的方式)

· 1离线烘焙


    将light的Baking设为Baked,标记那些static的物体,在Lighting window中的Baked GI对应的就是烘焙的实时光,所以这是要把Precomputed Reatime GI关闭

· 2实时

   将light的baking设为realtime,标记那些static的物体,在lighting window中将Baked GI关闭,将Precomputed Realtime GI开启,注意默认Precomputed Realtime GI的resolution并不高,如果想得到比较不错的效果,可以将它调高。在运行时就可以看到实时的GI效果
 



· 3 烘焙GI加实时的局部光照

      这可能是更加主要的做法,即static的物件采用离线的烘焙GI,而非static的物件使用实时的局部光照,这需要将light调为mixed,然后将lightmap里面开启baked gi,而将realtime gi 关闭。

· 4 烘焙的GI叠加实时的GI,这种做法基本没什么好处,而且效率也很低,这种组合是将light设为mixed,然后将light setting里面的baked gi和 relatime gi全开启


· 通用的GI设置

       通常为了提升间接光照的质量,可以将light里面的Bounce Intensity提高,和lightsetting 里面 general gi的indirect intensity也提高。此外还可以在light setting里面设置天空盒和环境光。
      Unity5的scene视图里面有多提供了一个视图Irradiance 来查看动态物体间的间接光照
 

· 光照探头,unity5的关照探头是为了使动态物体能偶受静态物体的gi影响,比UNITY4多了光照探头的信息可以实时更新的,其余的使用设置同4基本是一样的


· 反射探头

       这是UNITY5的实时GI新增的一部分,我们可以在场景的某个区域创建一个Reflection Probe,这点的环境映射信息就会被保存下来,当有动态物体进入的时候,就可以被贴上这个cubemap。如下图是一个球进入了这个区域感受到了这个点处的环境映射。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值