精华内容
下载资源
问答
  • 我们知道全局光照是图形学中一项比较难实现的技术,因为真正要得到全局光照是需要一个点跟所有点的关系计算的,而这个计算如果用在计算机那是不太可能实现的。而现代技术利用了一些比如有向距离场,体素,辐照度等...

    我们知道全局光照是图形学中一项比较难实现的技术,因为真正要得到全局光照是需要一个点跟所有点的关系计算的,而这个计算如果用在计算机那是不太可能实现的。而现代技术利用了一些比如有向距离场,体素,辐照度等方式实现全局光照,还有就是越来越火的光纤追踪技术实现全局光照。但是这些技术的消耗都很大,包括内存,cpu,gpu的运算量。那么自然会有一种ss系列的方式来实现全局光照,这种方式会比前面几种都容易实现并且运算量相对小。

    屏幕空间的全局光照也叫SSGI,是一个相对来说比较快速得到间接光的一种全局光照技术,是基于屏幕空间大小来实现的,也就是说不会得到屏幕外的颜色或者光照。他也不是基于光源的,而是基于当前的颜色来做扰动采样整合得到的光照信息,最后需要做一些抗锯齿的操作来让他噪点比较合理。这种方式更合理的使用在密闭空间内,这样的效果会比较理想。

    SSGI一般会有几个步骤:

    1.采样不同lod的深度图信息并得到其中最大的深度值。(要执行多少次寻找就看你设置多少次pass)

    2.用光线步进的方式,并用噪音图采样以圆的周长来找周围的像素点的颜色,这个颜色是根据当前场景颜色做的(所以ssgi一般放到最后处理)。采样的点存储到rt上

    3.这时的rt是带有比较明显的锯齿的rt,需要用taa方式过滤一次

    4.最后在横向和纵向做两次模糊处理。

    5.这样就得到了ssgi的漫反射方向的间接光照了,最后只需要把场景图和这个间接光rtcombina一下就好了。

     

    大体实现:

    1.获取深度图信息的核心代码是

    float2 uv = i.uv.xy;
    		
        half4 minDepth = half4(
            _SSGi_HierarchicalDepth_RT.SampleLevel( sampler_SSGi_HierarchicalDepth_RT, uv, _SSGi_HiZ_PrevDepthLevel, int2(-1.0,-1.0) ).r,
            _SSGi_HierarchicalDepth_RT.SampleLevel( sampler_SSGi_HierarchicalDepth_RT, uv, _SSGi_HiZ_PrevDepthLevel, int2(-1.0, 1.0) ).r,
            _SSGi_HierarchicalDepth_RT.SampleLevel( sampler_SSGi_HierarchicalDepth_RT, uv, _SSGi_HiZ_PrevDepthLevel, int2(1.0, -1.0) ).r,
            _SSGi_HierarchicalDepth_RT.SampleLevel( sampler_SSGi_HierarchicalDepth_RT, uv, _SSGi_HiZ_PrevDepthLevel, int2(1.0, 1.0) ).r
        );
    
    	return max( max(minDepth.r, minDepth.g), max(minDepth.b, minDepth.a) );

    采样上下左右四个方向的深度获取最深的。

    2.光线步进采样周围像素点的核心代码(有注释):

    float2 UV = i.uv.xy;
    
    	//当前像素深度
    	float SceneDepth = tex2Dlod(_CameraDepthTexture, float4(UV, 0, 0)).r;
    	//转成摄像机方向的线性深度
    	float EyeDepth = LinearEyeDepth(SceneDepth);
    	//float LinearDepth = Linear01Depth(SceneDepth);
    
    	half Roughness = clamp(1 - tex2D(_CameraGBufferTexture1, UV).a, 0.02, 1);
    	float3 WorldNormal = tex2D(_CameraGBufferTexture2, UV) * 2 - 1;
    	float3 ViewNormal = mul((float3x3)(_SSGi_WorldToCameraMatrix), WorldNormal);
    
    	//摄像机位置,z轴表示深度
    	float3 ScreenPos = GetScreenSpacePos(UV, SceneDepth);
    	//通过摄像机的逆矩阵转换到世界坐标
    	float3 WorldPos = GetWorldSpacePos(ScreenPos, _SSGi_InverseViewProjectionMatrix);
    	//通过投影矩阵的逆矩阵转换到摄像机空间
    	float3 ViewPos = GetViewSpacePos(ScreenPos, _SSGi_InverseProjectionMatrix);
    	//摄像机空间方向
    	float3 ViewDir = GetViewDir(WorldPos, ViewPos);
    
    	//基于世界法线建立切线空间
    	float3x3 TangentBasis = GetTangentBasis( WorldNormal );
    	//uint3 p1 = Rand3DPCG16( uint3( (float)0xffba * abs(WorldPos) ) );
    	//uint2 p = (uint2(UV * 3) ^ 0xa3c75a5cu) ^ (p1.xy);
    
    	half Out_Mask = 0;
    	half3 Out_Color = 0;
    	
    	[loop]
    	for (uint i = 0; i < (uint)_SSGi_NumRays; i++)
    	{
    		//uint3 Random = Rand3DPCG16( int3( p, ReverseBits32(i) ) );
    		//half2 Hash = float2(Random.xy ^ Random.z) / 0xffffu;     
    		//根据扰动图片采样来获取周边的像素和深度
    		half2 Hash = tex2Dlod(_SSGi_Noise, half4((UV + sin( i + _SSGi_Jitter.zw )) * _SSGi_RayCastSize.xy / _SSGi_NoiseSize.xy, 0, 0)).xy;
    
    		float3 L;
    		//基于圆偏移的点
    		L.xy = UniformSampleDiskConcentric( Hash );
    		L.z = sqrt( 1 - dot( L.xy, L.xy ) );
    		//世界空间
    		float3 World_L = mul( L, TangentBasis );
    		//转摄像机空间
    		float3 View_L = mul((float3x3)(_SSGi_WorldToCameraMatrix),  World_L);
    
    		float3 rayStart = float3(UV, ScreenPos.z);
    		//对方向最一些偏移,也是基于圆做偏移
    		float4 rayProj = mul ( _SSGi_ProjectionMatrix, float4(ViewPos + View_L, 1.0) );
    		float3 rayDir = normalize( (rayProj.xyz / rayProj.w) - ScreenPos);
    		rayDir.xy *= 0.5;
    		//找偏移附近的uv
    		float4 RayHitData = Hierarchical_Z_Trace(_SSGi_HiZ_MaxLevel, _SSGi_HiZ_StartLevel, _SSGi_HiZ_StopLevel, _SSGi_NumSteps_HiZ, _SSGi_Thickness, 1 / _SSGi_RayCastSize.xy, rayStart, rayDir, _SSGi_HierarchicalDepth_RT, sampler_SSGi_HierarchicalDepth_RT);
    
    		//根据偏移采样场景颜色
    		float3 SampleColor = tex2Dlod(_SSGi_SceneColor_RT, half4(RayHitData.xy, 0, 0));
    		float4 SampleNormal = tex2Dlod(_CameraGBufferTexture2, half4(RayHitData.xy, 0, 0)) * 2 - 1;
    		float Occlusion = 1 - saturate( dot(World_L, SampleNormal) ); 
    
    		SampleColor *= Occlusion;
    		SampleColor *= rcp( 1 + Luminance(SampleColor) );
    
    		Out_Color += SampleColor;
    		//对场景大小的遮罩决定显示范围
    		Out_Mask += Square( RayHitData.a * GetScreenFadeBord(RayHitData.xy, _SSGi_ScreenFade) );
    	}
    	Out_Color /= _SSGi_NumRays;
    	Out_Color *= rcp( 1 - Luminance(Out_Color) );
    	Out_Mask /= _SSGi_NumRays;
    
    	//颜色用附近采样的颜色,透明度用深度决定
    	[branch]
    	if(_SSGi_MaskRay == 1) {
    		return half4( Out_Color * saturate(Out_Mask * 2), EyeDepth );
    	} else {
    		return half4( Out_Color, EyeDepth );
    	}

    3.做一次TAA,主要是获取aabb的裁剪盒子,然后得到最小颜色,最大颜色,然后clamp进行过渡,再融合上一帧的颜色和当前帧的颜色。

    half2 UV = i.uv.xy;
    	half3 WorldNormal = tex2D(_CameraGBufferTexture2, UV).rgb * 2 - 1;
    	half2 Velocity = tex2D(_CameraMotionVectorsTexture, UV);
    
    	/Get AABB ClipBox
    	half SS_Indirect_Variance = 0;
    	half4 SS_Indirect_CurrColor = 0;
    	half4 SS_Indirect_MinColor, SS_Indirect_MaxColor;
    	ResolverAABB(_SSGi_RayCastRT, 0, 10, _SSGi_TemporalScale, UV, _SSGi_ScreenSize.xy, SS_Indirect_Variance, SS_Indirect_MinColor, SS_Indirect_MaxColor, SS_Indirect_CurrColor);
    
    	/Clamp TemporalColor
    	half4 SS_Indirect_PrevColor = tex2D(_SSGi_TemporalPrev_RT, UV - Velocity);
    	SS_Indirect_PrevColor = clamp(SS_Indirect_PrevColor, SS_Indirect_MinColor, SS_Indirect_MaxColor);
    
    	/Combine TemporalColor
    	half Temporal_BlendWeight = saturate(_SSGi_TemporalWeight * (1 - length(Velocity) * 2));
    	half4 SS_IndirectColor = lerp(SS_Indirect_CurrColor, SS_Indirect_PrevColor, Temporal_BlendWeight);
    
    	return SS_IndirectColor;

    4.做横向和纵向两次模糊(blur里面会对颜色和深度都做模糊处理,颜色直接用相加然后除于相加的数量得到,深度需要用2的n次幂来得到一条曲线,下面的CrossBilateralWeight就是深度的过滤方式):

    float4 Bilateralfilter_X(PixelInput i) : SV_Target
    {
    	half2 UV = i.uv.xy;
    	const float Radius = 12.0;
    	return BilateralBlur( Radius, UV, half2(1.0 / _SSGi_ScreenSize.x, 0), _SSGi_TemporalPrev_RT );
    }
    
    float4 Bilateralfilter_Y(PixelInput i) : SV_Target
    {
    	half2 UV = i.uv.xy;
    	const float Radius = 12.0;
    	return BilateralBlur( Radius, UV, half2(0, 1.0 / _SSGi_ScreenSize.y), _SSGi_TemporalPrev_RT );
    }
    
    float CrossBilateralWeight(float BLUR_RADIUS, float r, float Depth, float originDepth) 
    {
    	const float BlurSigma = BLUR_RADIUS * 0.5;
    	const float BlurFalloff = 1.0 / (2.0 * BlurSigma * BlurSigma);
    
        float dz = (originDepth - Depth) * _ProjectionParams.z * 0.25;
    	return exp2(-r * r * BlurFalloff - dz * dz);
    }

    5.合并就简单了,就是用当前场景颜色和上面算出来的间接光照相加。

    half2 UV = i.uv.xy;
    
    	half3 BaseColor = tex2D(_CameraGBufferTexture0, UV);
    	half3 SceneColor = tex2D(_SSGi_SceneColor_RT, UV);
    	half3 IndirectIrradiance = tex2D(_SSGi_Bilateral_RT, UV) * _SSGi_GiIntensity;
    
    	return (IndirectIrradiance * BaseColor) + SceneColor ;

    总结:ssgi的diffuse方式实现简单,得到的结果也不错,但是他并不是正确的,是一个模拟周围颜色的过程,当你要得到更好的结果时需要扩大获取深度和颜色扰动的范围,同样gpu的压力也会增大。但他确是一种实时的全局光照方式。当然如果我们只需要一些静态或可控的动态区域做全局光照,那么用烘焙和球谐光照就可以了。

     

     

     

    展开全文
  • 在做项目的时候遇到一个...自己写的shader的间接光照模型在烘焙的时候效果不对,他不会对周围的物体产生间接光照,而且烘焙出来的lightmap很亮,跟老的shader烘焙出来的效果完全不同。 老的shader(正确的lightma...

    在做项目的时候遇到一个问题,之前把项目中的surface shader进行了一些优化,换成了新的vertex&fragment shader,效果都一致了,但是场景烘焙后问题就出来了。自己写的shader的间接光照模型在烘焙的时候效果不对,他不会对周围的物体产生间接光照,而且烘焙出来的lightmap很亮,跟老的shader烘焙出来的效果完全不同。

    老的shader(正确的lightmap):

    新的shader:

    最后发现是没有加metaPass的原因。

    unity在背后会根据surface shader(不只是自己写的,还包含unity自带的shader,很多也都是surface shader)生成一个包含多个Pass的顶点片元着色器,其中也包含了meta Pass,这个Pass块是为了给光照映射和动态全局光照提取表面信息的。你可以找到一个表面着色器,然后在Inspector面板中点击show generated code查看转换好的V&F代码。代码很长,metaPass一般在最后。

    unity5把烘焙系统由Beast换成了Enlighten,Enlighten需要Unity提供材质的Albdeo(反射率)和自发光(emissive)的纹理,从而用来计算间接光照。而这两个贴图都是Unity自己在GPU上渲染得到的。既然需要GPU渲染,那就需要用提供一个相应的Pass来专门让Unity用来进行这种渲染,就是meta Pass。一句话总结,metaPass主要是Unity用来计算Albedo和emissive,然后提供给enlighten用的。

    一、原理

    为什么要这两个值也很好理解,设想一下一个物体要相对周围物体产生光照影响,一般有两种情况:

    1.作为发光体,直接将光线投射到其他物体上,对应着上面的emissive。

    2.光线照射到该物体上然后反射(可能经过多次)到周围物体上,最后被后者反射到人眼中,而当要计算前者能反射多少,以及哪些成分的光线到后者身上就要用到Albedo。

    可以看一下Enlighten官方Blog给出的Radiosity Equation公式:

    对于全局光照处理,目前有两种主流算法,光线追踪和辐射度算法,Enlighten所使用的即是这种。上图中的公式实际上是对RenderEquation的一种简化变形, RenderEquation是一种理想模型,也是目前所有光照处理的理论基础。

    上面的模型中实际上把一个像素点的受光情况(这里只考虑间接光照)分成了自发光Le和 来自其它光源的间接光照。其中Pi是材质属性,这里我们可以简单的理解成Albedo反射率,这反应了该点对应的材质对不同波段光的反射能力。那上面公式中后面的一团就不难理解了,实际上就是对从各个方向收集到的反射光的和最后乘上一个材质反射能力,从而得到最后的实际光照结果。这也是为什么在在metapass里enlighten需要Unity给它提供Albedo和emission纹理了。

    二、代码

    Pass  
    {  
        Name "Meta"
        Tags {"LightMode" = "Meta"}
        Cull Off
    
        CGPROGRAM
        #pragma vertex vert_meta
        #pragma fragment frag_meta
    
        #include "Lighting.cginc"
        #include "UnityMetaPass.cginc"
    
        struct v2f
        {
            float4 pos:SV_POSITION;
            float2 uv:TEXCOORD1;
            float3 worldPos:TEXCOORD0;
        };
    
        uniform fixed4 _Color;
        uniform sampler2D _MainTex;
        v2f vert_meta(appdata_full v)
        {
            v2f o;
            UNITY_INITIALIZE_OUTPUT(v2f,o);
            o.pos = UnityMetaVertexPosition(v.vertex,v.texcoord1.xy,v.texcoord2.xy,unity_LightmapST,unity_DynamicLightmapST);
            o.uv = v.texcoord.xy;
            return o;
        }
    
        fixed4 frag_meta(v2f IN):SV_Target
        {
             UnityMetaInput metaIN;
             UNITY_INITIALIZE_OUTPUT(UnityMetaInput,metaIN);
             metaIN.Albedo = tex2D(_MainTex,IN.uv).rgb * _Color.rgb;
             metaIN.Emission = 0;
             return UnityMetaFragment(metaIN);
        }
    
        ENDCG
    }

    上面的代码是最简化的一版,最开始的LightMode的Tag,unity要通过它来找到MetaPass,Unity文档中有比较完整的代码。_Color和_MainTex是在Properties里声明的贴图和调和颜色。后面会把他俩相乘作为Albedo的结果,这也正是我们在正常的光照处理里所做的。

    其中:

    1.Unity_INITIALIZE_OUTPUT(v2f,o);

    是一个清零操作,当顶点着色器函数返回结果的时候,如果要返回的结构体没有全部赋值过,那么unity会报错,必须全部赋值,这个宏就是用来清零的,省着手动赋值为0,并不是所有的着色器语言都支持,有些情况下必须手动赋值。

    2.UnityMetaVertexPosition(v.vertex,v.texcoord1.xy,v.texcoord2.xy,unity_LightmapST,unity_DynamicLightmapST)

    参数中的uv1,uv2分别是模型在静态光照贴图(static lightmap)和动态光照贴图(实时GI)中的uv坐标。lightmapST和dynlightmapST的值应该是经过特殊构造以用来确定其在烘焙空间中的位置。

    3.UnityObjectToClipPos(vertex)

    只是做了模型空间到齐次空间的转换。

    4.

    struct UnityMetaInput
     {
         half3 Albedo;
         half3 Emission;
     };
    metaIN.Albedo = tex2D(_MainTex,IN.uv).rgb * _Color.rgb;
    metaIN.Emission = 0;

    根据项目实际需求计算这两个值,然后赋值给UnityMetaInput中。

    5.UnityMetaFragment(metaIN);

    三、注意事项

    上面的代码可以直接用,但是效果可能会有问题,直接用我烘焙出来的效果如下图:

     

    大家会发现比起没有加metaPass烘焙出来的lightmap,要好上太多了,曝光严重的问题解决了,但是会发现新烘焙的有点深,不通透,黑的地方有点重,有颜色的地方饱和度有点高。

    这是因为每个项目,每种shader的计算都是有自己的需求的,我们计算Albedo和emission都是有差异的,就如上面的代码,反射率Albedo的计算一般大多项目都是用的

    Albedo = tex2D(_MainTex,IN.uv).rgb * _Color.rgb。

    _Color和_MainTex是在Properties里声明的贴图和调和颜色。后面会把他俩相乘作为Albedo的结果,这也正是我们在正常的光照处理里所做的。

    emission在上面的代码中直接给赋值为0了,因为有很多建筑shader不需要这个属性,也没有计算它。但是有些环境建筑的shader确实计算了自发光,那么就要把算出来的emission值赋值给metaIN.Emission了,要跟项目中的属性值一致,才能得到正确的效果,比如我的:

    fixed4 diffTex;

     diffTex = tex2D(_MainTex, i.uv);

     float2 uvScreen = i.screenPos.xy / max(i.screenPos.w, 1);

    fixed4 em = tex2D(_EmissionTex, i.uv);

     fixed3 Emission = _EmissionColor * em * _EmissionPower + _EmissionNight * em
     + diffTex.rgb * _EmissionMain + GetCpLightColor(uvScreen, diffTex.rgb);

    metaIN.Emission = Emission;

    还有的shader计算了SpecularColor,那么有时候也有必要进行赋值,一切根据项目来定,比如我的:

    _Shininess("Shininess", Range(0.03, 1)) = 0.08

    fixed Specular = _Shininess;

    metaIN.SpecularColor = Specular;

    我也是查看了项目中原来的老的surface shader生成的V&F shader的meta Pass的块才看到需要这些属性的值参与计算,所以我们要进行适当的修改来变成我们想要的效果。

    四、补充

    上面讨论的都是间接光照,并没有说明烘焙时直接光照Unity是如何处理的,查看别人的资料的一些理解:

    Enlighten实际上会把光源也作为一个物体,但对于光源来说实际上只有Le而后面的项是没有意义的。而Enlighten在渲染场景光照的时候实际上是一个迭代的过程,在不考虑任何模型物体自发光的情况下,第一次遍历时候实际上对由于某一点的Bi来说,它的第二项只有那些光源物体会对它造成影响,也就是只有光源的Lj是一个非0值。当第二次遍历的时候由于上一次遍历,很多表面的Lj都已经是非0值,那么Bi的第二项的计算结果就会有更多的有效项,这实际就产生了间接光照了。

    下面是原文地址,我参考的这篇文章加上项目中的实践来写的:

    http://www.cnblogs.com/Esfog/p/MetaPass_In_Unity5.html 

    展开全文
  • 全局光照

    千次阅读 2018-02-12 15:38:37
    原文连接:全局光照 全局光照 GI概念 GI的局限性 GI效果的例子 全局光照 全局光照是一种表达光线从表面反射到另一个表面(间接光)的工作方式的模型,而不仅限于从光源直接击中表面的光(直接光)。...

    原文连接:全局光照

    全局光照

    全局光照是一种表达光线从表面反射到另一个表面(间接光)的工作方式的模型,而不仅限于从光源直接击中表面的光(直接光)。使用间接光能使虚拟世界看起来更加真实和相互连接,因为物体之间相互影响显示效果。一个经典的例子是“颜色出血”效果。比如太阳光照射一个红色沙发时,红光会被反射到沙发后面的墙上。另一个例子是太阳照射一个洞穴入口处的地面时向内部各个方向反射,洞穴内部也会被照亮。
    alt text
    场景中的全局光照。注意间接光微妙影响

    GI概念

    传统的视频游戏和其他的实时图形应用一直被限制于直接光照,因为间接光需要的计算太慢而只能使用在CG动画电影一类的非实时情况。一种绕过这种限制计算物体和表面间接光的方式,仅适用于事先知道在游戏中不会移动的物体(也就是静态的)。这样耗时的计算可以事先进行,由于物体不会移动,预计算的间接光在运行时仍然是正确的。Unity支持的这种烘焙GI(也被称为烘焙光照贴图),名称来源于”the back”:间接光预处理和存储(烘焙)的过程。除了间接光照,烘焙GI利用足够多的计算时间为面积光和间接光生成的柔软阴影比正常使用实时技术得到的效果更真实。
    另外,Unity 5.0增加了一个称为Precomputed Realtime GI的新技术。它也需要和上面提到的烘焙模式相似的预处理阶段,同样也限定于静态物体。但是它不是只预处理场景生成时的光线反射,而是预处理所有可能的光照反射并且编码这些信息以在运行时使用。因此基本上对所有静态物体,这个技术回答了“任何光照射这个表面时,它向什么方向反射?”这个问题。Unity将光线能传播的路径保存起来在后面使用。最终的光照在运行时将实际的光照呈现到之前计算的光线传播路径中完成。
    这意味着光照的数量和类型,它们的位置、方向及其他属性都可以被修改,并且间接光照会相应更新。同样也可以改变物体的材质属性,比如颜色,它们吸收多少光或它们自身发出多少光。虽然预处理实时GI也能得到柔软的阴影,它们形成的阴影通常比烘焙GI的效果要粗糙,除非是场景非常小的情况下。同时注意由于预处理实时GI在运行时的少数帧时间内迭代进行最终的光照处理,因此如果光照发生了很大变化,将需要较多帧数光照才能完全生效。尽管这个过程在实时应用中足够快,如果目标平台的资源非常受限制,采用烘焙GI能得到更好的运行时效果。

    GI的局限性

    烘培GI和预处理实时GI都有一个局限性,它们只能将静态物体包含到烘培/预处理结果中。因此移动的物体不能向其他物体反射光照,反之也不行。但是它们仍可以使用光探测器获取静态物体的反射光。光探测器位于场景中的一些位置上,在烘培/预处理过程中收集(探测)光照,在运行时照射非静态物体的间接光照就可以通过任意时刻离物体最近的探测器来近似表示。例如,一个红球滚到白墙附近时,不会将红色发散(bleed)到墙上,但是一个红墙附近的白球能通过光探测器获取墙壁上散出的红色。

    GI效果的例子

    • 改变一个定向光的方向和颜色来模拟太阳划过天空。改变定向光时,同时改变天空盒可以在运行时制造真实的一天之内的时间变化效果。(实际上新增加的内置天空盒程序很容易实现这个功能)
    • 在一天之中,透过窗户到达室内的阳光在地板上移动,并且光照真实地反射到房间周围和天花板上。当阳光照射红色沙发时,红色的光反射到沙发后面的墙上。将沙发的颜色从红色改编为绿色,沙发后面墙上溅射的颜色也会从红色变为绿色。
    • 调整一个霓虹标记的材质散射属性,当打开时开始向周围环境中发光。
      下面的内容将讨论使用这些特征的细节。
    展开全文
  • 动态场景的全局光照实时绘制,一篇浙大的硕士论文,里面对于光照技术有很详细的讲解。
  • 1、全局光照GI 全局照明是一个系统,用于模拟光从表面反射到其他表面(间接光)的方式,而不仅仅是直接从光源(直接光)照射到表面的光。 全局光照=直接光+间接光 没有光照的地方是一片死黑;可以想象现实生活中...

    上一篇我们了解了,直接光照、间接光照和全局光照,也知道全局光照会带来的计算量的问题。这一篇我们就要来看看Unity提供的解决方法。

     

    Unity的全局光照模式

    我们可以首选打开Uinty的照明设置面板,Window->rendering->lighting setting,这个面板是Unity全局照明(GI)功能的主要控制面板。通过Lighting窗口,你可以调整GI进程中的各个方面,根据需要来自定义场景或优化质量,性能和存储空间。 这个窗口还包括环境光,雾效、光晕等设置。这里我们先只关注红色框内的部分。

    Unity提供了两种全局光照模式,实时全局光照和烘焙全局光照。看到这儿的小伙伴可能要骂人了,不是说计算量大,不能实时计算的吗?其实这里的实时只是部分实时,后面会详细讲到。

     

    物体的动静和light组件的模式

    在讲两种全局光照模式之间,我们先讲一下物体的动静和light组件的模式,这二者是和光照模式相互配合的。

    在Unity中,物体是可以区分静态和动态的,你需要明确指出哪些物体是静止的,并且在游戏中永远不会移动、旋转和缩放。

    注意:灯光也是要区分动态和静态的,因为灯光在Unity中可能会发生移动,旋转等

     

    混合光照——烘焙全局光照(Baked Gloabl lllumination)

    控制“混合”和“烘焙”光照是否使用烘焙全局照明。如果启用,“混合”光照将使用指定的“照明模式”进行烘焙,“烘焙”光照将完全烘焙,且在运行时无法调整。

    1、这里说的“混合”和“烘焙”光照就是上面说的light组件的mixed和baked模式

    2、如果light组件是baked模式,则该组件产生的直接光照、间接光照和阴影都烘焙成全局光照贴图,运行时是无法调整的。这就要求光照要是静态的,光照下的物体也要是静态的

    我们烘焙之后,把场景中的灯光关掉,发现场景中的光照信息都还是在的

    3、如果light组件是“混合”模式,将使用指定的“照明模式”进行烘焙。这里提到了照明模式,我们将对照明模式做解释

     

    照明模式lighting mode

    Unity提供了三种照明模式,对三种模式的解释

    我们将场景中的cubeA立方体改动动态物体,其他仍然保持静态,等华灯落下,我们来看看它们的正面目

    1、subtractive 减性

    混合灯光为静态物体提供烘焙直接照明和间接照明。动态对象接受实时直接光照,并使用场景中的主方向光在静态对象上投射阴影

    • 关闭灯光,静态物体的灯光没有变化,说明静态物体的直接照明和间接照明都是烘焙成贴图了
    • 关闭灯光,cubeA全黑的,说明动态物体的直接光照是实时的,没有间接光照

    2、ShadowMask

    混合灯光提供实时直接照明。间接照明会被烘焙到光照贴图和光照探测器中。会为烘焙阴影生产Shadowmasks和光照探测器遮挡。运行时使用的“Shadowmask模式”可以在“质量设置”面板中设置

    • 关闭灯光,静态物体的的直接光照没有了,说明静态物体的直接照明是实时的,间接照明是烘焙的
    • 关闭灯光,cubeA全黑的,说明动态物体的直接光照是实时的,没有间接光照

    3、baked indirect 间接烘焙

    混合灯光提供实时直接照明,而间接照明则会被烘焙到光照贴图和光照探测器中。

    • 关闭灯光,静态物体的的直接光照没有了,说明静态物体的直接照明是实时的,间接照明是烘焙的
    • 关闭灯光,cubeA全黑的,说明动态物体的直接光照是实时的,没有间接光照(这和ShadowMask是一致的)
    灯光后,cubeA只有直接光照
    关闭灯光后,cubeA没有任何光照
    光源已经移动到远处,场景中已经没有直接照明,但间接照明还在

    baked indirect最高配的光照模式,同时也最耗性能

     

    三种照明模式总结:

    三种模式有一个共同点,对于静态物体的间接光照,一定都是烘焙的,这就导致

    1、如果光源改变位置或方向的话,静态物体的间接光照是不变的

    2、对于动态物体压根不支持间接光照

    3、在shadowMask和baked indirect模式下,无论光源变化,至少静态和动态物体的直接光照一直都是正确的

     

    实时全局光照(Realtime Gloabl lllumination)

    所谓的实时并非真的完全实时的,准确的说应该是预计算Precomputed

    启动实时全局光照的时候,Unity仅预先计算表面到表面的信息:物体间光线可能会经过的路径,会预先计算好了反射以及二次反射的一些条件,并把这些计算好的数据存了起来,你要计算场景中的光和影的时候,实时全局光照会把数据拿出一部分来去运用到你的计算,所以我们看到实时全局光照也是有贴图的。

    下面我们看下实时全局光照的烘焙特性,实时全局光照只对“实时”的光照组件有效

    • 关闭灯光,漆黑一片。说明静态物体的直接照明是实时的,间接照明也是实时的

    • 将scene的绘制模式切换到Indirect模式,发现CubeA消失了,说明动态物体没有间接光照
    • 灯光位置变化后,静态物体的直接光照和间接照明都发生了变化

    灯光的高度是6,距离拉进了,直接光照和间接光照都发生了变化
    将scene的绘制模式切换到Indirect模式,发现CubeA消失了

     

     

    两种全局光照总结:

    1、实时全局光照和烘焙全局光照下,都不支持动态物体的间接光照

    2、如果灯光改变,需要使用实时全局光照

    3、混合光照和实时光照是可以同时使用的

    两种模式都勾选上
    spot是realtime模式,point是mixed模式

     

     

    灯光探针

    由于实时全局光照和烘焙全局光照只能作用于static的物体,所以导致运动的物体和场景中的光线无法融合在一起,显得不真实。

    而Light Probes组件可以通过Probe收集光影信息,然后对运动物体附近的几个probe进行差值运算,最后将光照作用于物体上。

     

    其他:

    1、Unity2019已经提示实时全局光照(已弃用)

    Enlighten即将弃用。请确保您的项目在弃用日期之后不再需要Enlighten支持

    Unity官方有解释,由于Geomerics公司停止推出产品级的Enlighten,因此Unity必须移除

    2023年之前都是可以用的

    2、3D软件和Unity的烘焙思路差异

    烘焙既可以在具有烘焙功能的3D建模软件中来完成,也可以在Unity3d中来烘焙

    当然,在Unity3d中烘焙兼容性更好。Unity3d的烘焙是美工的一个环节,关系到Unity作品的颜值和卖相

    3、Unity3d的最终作品是供受众对3D场景进行实时操作的,就像其他3D软件场景编辑状态的操作,而一般的3D软件最终作品是将场景渲染成图片或图片序列呈现给受众的,两者的最终作品有本质的区别,简单地说,前者呈现给受众的是3D场景,后者呈现给受众的是图片或图片序列(动画)。尽管如此,两者都必须有较强的立体感和较好的光影视觉效果,否则是不被受众所接受的。

     

    遗留问题:

    预计算的实时GI模型?

     

    灯光设置成mixed,就能同时满足动态和静态物体的需求

    注意:环境光没有mixed模式

     

    参考:

    unity3d 为什么要烘焙/unity3d 烘焙作用是为了什么【2020】

    写给美术看的Unity全局光照详解(参数篇)

    展开全文
  • 全局光照模型相比于局部光照模型不仅包括从光源发出的直接光照的作用,还需考虑场景物体间反射和折射等间接光照的因素,因此渲染的结果要远优于局部光照.能实现真实光照效果的全局光照渲染技术吸引了国内外众多学者的...
  • Unity 全局光照LightMap 动态加载

    千次阅读 2016-01-11 11:03:12
    Unity 全局光照LightMap 动态加载
  • 摘要:全局光照渲染技术是计算机图形学领域的热点问题之一,目前该领域中主要存在两个核心问题需要解决:渲染质量和渲染速度.而文物数字化领域对渲染技术具有以下需求:展示交互性以及渲染保真度.本文侧重于保证渲染...
  • 基于直接光照的全局光照模拟,看看有点收获,但不是很大。
  • Unity全局光照

    2020-12-01 17:19:10
    全局光照(global illumination),简称GI;Unity是从Unity5开始引入行业领先的实时全局光照技术Enlighten系统 全局光照是什么? 想象现实生活中的场景,一束光投进窗户,从而整个房间的阴暗角落也会被照亮,这...
  • 游戏引擎全局光照技术(更新第4章)游戏引擎全局光照技术(更新第4章)游戏引擎全局光照技术(更新第4章)
  • unity 全局光照.pdf

    2021-02-01 18:22:18
    unity 全局光照.pdf
  • Unity 5 中的全局光照技术详解.doc Unity 5 中的全局光照技术详解.doc Unity 5 中的全局光照技术详解.doc Unity 5 中的全局光照技术详解.doc Unity 5 中的全局光照技术详解.doc
  • 提出一种全局光照的计算方法,使用体素结构存储简化场景的光照信息,并通过体素锥追踪方法来收集光照信息,计算间接光照。在计算过程中,每帧只更新动态场景的体素结构,既可以支持动态光源,又避免了更新静态场景的时间...
  • Global Illumination(全局光照) 本文档主要是对Unity官方手册的个人理解与总结(其实以翻译记录为主:&amp;amp;amp;amp;gt;) 仅作为个人学习使用,不得作为商业用途,欢迎转载,并请注明出处。 文章中...
  • 实时全局光照总结

    2021-06-27 13:00:32
    全局光照只考虑一次间接光照,核心问题是怎么找出次级光源以及如何高效的计算全局光照。 RSM shadow map中存储了次级光源的信息,这些次级光源被当作diffuse材质,可以像四面八方反射光线,简单理解就是把每一个...
  • 全局光照(简述)

    千次阅读 2020-05-11 22:05:23
    一、什么是全局光照 全局光照(Global Illumination,简称 GI), 作为图形学中比较酷的概念之一,是指既考虑场景中来自光源的直接光照,又考虑经过场景中其他物体反射后的间接光照的一种渲染技术。 即可以理解为:...
  • 局部光照与全局光照的区别

    千次阅读 2019-10-01 19:35:27
    全局光照(Global illumination) 简单的说就是考虑到环境中所有表面和光源相互作用的照射效果 采用Ray Tracing和Radiosity两种技术来计算全局光照 Ray Tracing用于计算镜面反射,灯光透过玻璃的效果和阴影,还有模拟...
  • Unity5 全局光照

    2017-03-15 00:50:33
    转载自:Unity 5 中的全局光照技术详解 简介 全局光照,简称GI,是一个用来模拟光的互动和反弹等复杂行为的算法,要精确的仿真全局光照非常有挑战性,付出的代价也高,正因为如此,现代游戏会先一定程度的预先...
  • 详细介绍 Unity全局光照技术入门 知识。包括理论上的探讨,参数的详细说明,还有Shader中的应用等。
  • Lightmass静态全局光照

    千次阅读 2016-06-04 16:42:32
    Lightmass静态全局光照概述版本遗留支持在新的地图中使用旧的UE3光照转换一个现有地图来使用LightmassLightmass功能区域光源和阴影带符号的距离场阴影漫反射的交互反射角色光照限制源于自发光的网格物体的区域光源...
  • 全局光照技术:从离线到实时渲染》是一本聚焦于渲染领域的计算机图形学图书,它同时包含了离线和实时渲染的内容,探讨了渲染中最常用的约十种全局光照技术的概念,原理以及相互之间的联系,并以这些全局光照技术为...
  • 针对大规模场景的全局光照渲染往往因为计算量过大而无法满足实时性要求的问题进行了研究,提出一种高性能的体素圆锥追踪(voxel cone tracking,VCT)全局光照算法。算法包括:a)在体素化阶段,提出一种新型的场景...
  • UE4 Lightmass 全局光照

    千次阅读 2019-01-13 15:27:09
    UE4 Lightmass 全局光照
  • 可编程渲染管线8 全局光照

    千次阅读 2019-05-07 21:14:59
    烘焙和采样光照贴图 显示直射光 创建自发光材质 通过探针和LPPV采样光线 支持预计算的实时全局光照 这是Unity可编程渲染管线系列教程的第八部分。我们不仅将支持静态的全局光照还会支持动态全局光照。 ...
  • 什么是全局光照全局光照,指的就是模拟光线是如何在场景中进行传播的,不仅会考虑那些直接光照的效果,还会计算光线被不同的物体表面反射而产生的间接光照。 Unity使用实时+预计算的方式来模拟场景中的光照:...
  • 为了解决传统的基于光辐射传输预计算(PRT)的全局光照技术在大规模场景下渲染效率低下的问题,在对PRT光照算法的本质进行分析的基础上,提出了一种基于四叉树的自适应网格细分算法.根据光照方程中的可见性函数,只在需要...
  • Unity 场景渲染之全局光照(五)

    千次阅读 2019-04-22 19:39:56
    全局光照(简称GI)分为直接光照和简接光照 直接光照 间接光照 改正上面一句话(平行光经由墙面反射的光会照亮这个区域,这就是间接光照的由来) 全局光照又分为实时全局光照和烘焙全局光照 实时全局...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 13,077
精华内容 5,230
关键字:

动态全局光照