精华内容
下载资源
问答
  • 动态全局光照
    千次阅读
    2020-10-30 19:06:01

    我们知道全局光照是图形学中一项比较难实现的技术,因为真正要得到全局光照是需要一个点跟所有点的关系计算的,而这个计算如果用在计算机那是不太可能实现的。而现代技术利用了一些比如有向距离场,体素,辐照度等方式实现全局光照,还有就是越来越火的光纤追踪技术实现全局光照。但是这些技术的消耗都很大,包括内存,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的压力也会增大。但他确是一种实时的全局光照方式。当然如果我们只需要一些静态或可控的动态区域做全局光照,那么用烘焙和球谐光照就可以了。

     

     

     

    更多相关内容
  • unity 全局光照.pdf

    2021-02-01 18:22:18
    unity 全局光照.pdf
  • 在做项目的时候遇到一个...自己写的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 

    展开全文
  • 动态场景的全局光照实时绘制,一篇浙大的硕士论文,里面对于光照技术有很详细的讲解。
  • 游戏插件动态实时全局光照系统.zip模型资源unity模型资源下载游戏插件动态实时全局光照系统.zip模型资源unity模型资源下载游戏插件动态实时全局光照系统.zip模型资源unity模型资源下载 1.合个人学习技术做项目参考 2...
  • 详细介绍 Unity全局光照技术入门 知识。包括理论上的探讨,参数的详细说明,还有Shader中的应用等。
  • 提出一种全局光照的计算方法,使用体素结构存储简化场景的光照信息,并通过体素锥追踪方法来收集光照信息,计算间接光照。在计算过程中,每帧只更新动态场景的体素结构,既可以支持动态光源,又避免了更新静态场景的时间...
  • 针对全局光照尤其是多光源的全局光照的复杂性使其一直局限于离线应用的问题。对能量大的能代表多个光源的主光源,采用立即辐射度的方法,跟踪其光线产生虚拟点光源(VPLS:virtual Point Lights),这些VPLS再照亮场景...
  • 基于直接光照的全局光照模拟.rar,基于直接光照的全局光照模拟.docx
  • 针对大规模场景的全局光照渲染往往因为计算量过大而无法满足实时性要求的问题进行了研究,提出一种高性能的体素圆锥追踪(voxel cone tracking,VCT)全局光照算法。算法包括:a)在体素化阶段,提出一种新型的场景...
  • 为了解决传统的基于光辐射传输预计算(PRT)的全局光照技术在大规模场景下渲染效率低下的问题,在对PRT光照算法的本质进行分析的基础上,提出了一种基于四叉树的自适应网格细分算法.根据光照方程中的可见性函数,只在需要...
  • Unity全局光照

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

    直接光照和间接光照

    通过上一篇文章Unity局部光照、直接光照,我们了解到

    由光源照射到物体,经过物体A的反射(包括漫反射和镜面反射)进入相机的光称为直接光照(局部光照)。

    被直接光照照射的地方会形成光亮和阴影,而没有被照射的地方就会是一片死黑,这和现实世界肯定是有差异的。

    想象现实生活中的场景,一束光投进窗户,从而整个房间的阴暗角落也会被照亮。这就是因为在现实世界中,光照射到物体表面之后,会不断发生反射到其他物体的表面,再反射进入入眼的。在Unity中我们称这些物体表面反射的光为间接光照

    即,由光源照射到物体,经过物体A的反射到物体B、C、D,再物体B、C、D等反射进入相机的光称为间接光照。

     

    全局光照是什么?

    全局光照(global illumination),简称GI;Unity是从Unity5开始引入行业领先的实时全局光照技术Enlighten系统,用于模拟光从表面反射到其他表面(间接光)的方式,而不仅仅是直接从光源(直接光)照射到表面的光,使我们在Unity中构建的场景更加真实和有层次感。而不是没有光照的地方是一片死黑。

    简单来说,全局光照=直接光照+间接光照。

    我们可以看一下全局光照和局部光照的效果对比

    使用全局光照的场景要比没有使用的要真实和有层次的多,没有光照直接照射的地方,也会有一定的亮度。

     

    全局光照带来的问题

    现在我们知道了全局光照的作用了,但间接光照的算法非常复杂,计算速度太慢,不太可能完全实时计算;所以我们通过烘焙光照贴图来节省计算量,在达到好的效果的时候也兼顾性能。

     

    补充说明:

    1、Unity版本:Unity2019

    2、部分图片来源于网络如有侵权请私信删除

    展开全文
  • 尤其本书从一个个独立完整的全局光照解决方案来解析和讨论游戏引擎在渲染过程中对各种基础理论知识的运用,使读者能够从一个系统性的高度去理解计算机图形学中的各种概念,具有非常强的理论性。同时本书结合当下行业...
  • 光照也是实时渲染的最重要的部分之一,和反射一样,光照和阴影在实时渲染中的开销也很大,因此一部分计算被分流到预先计算/预算渲染中,而静态光照是指...1,静态光照可以处理辐射和全局光照 2,可以获得真实的阴影效

    光照也是实时渲染的最重要的部分之一,和反射一样,光照和阴影在实时渲染中的开销也很大,因此一部分计算被分流到预先计算/预算渲染中,而静态光照是指所有预先计算而非实时渲染的光照。

    静态光照和静态阴影

    从流程来看:
    1,静态光照是预先计算的,并将大部分结果存储在光照贴图中。
    2,性能方面很迅速,但是占用内存
    3,在预先计算光照时要花费较长的时间
    4,每当模型发生了变化,就要重新渲染
    5,模型需要光照贴图UV,这额外的准备步骤也需要消耗时间

    从质量来看:
    1,静态光照可以处理辐射和全局光照
    2,可以获得真实的阴影效果,包括真实而高质量的软阴影,效果比动态光照更好
    3,但是质量实际害取决于光照贴图分辨率和UV布局(纹理大小和UV布局质量决定光照质量)
    4,由于UV布局的关系,光照中还可能出现接缝
    5,光照贴图有一个上限,所以巨型模型可能会有不足的情况
    6,一旦被计算完成,光照和阴影就不能在运行时被移动了
    光照贴图本质上就是一张纹理,是一张烘焙有光照和阴影信息的图片,然后纹理会和底色相乘,因此它看起来就像是被光照亮了一样

    ILC(Indirect Lighting Cache)

    现在静态光照已经完成,纹理被烘焙到了光照贴图中。假如一个角色正在游戏世界中行走,它是一个动态模型,而这个是在前期烘焙的过程中不曾存在的,而这时它要对周围的光照做出反应,这种情况下会用到ILC——间接光照缓存,ILC在一个场景中存储了很多点。
    在这里插入图片描述

    在这里插入图片描述
    这些点都储存了光照信息,每一个点都存储了间接光照,当动态模型在游戏中移动时,UE4会找到最近的点,查询它的亮度,然后将它和自身混合。
    在光栅化之前,这些静态的信息就已经被确定了,因此这个过程发生在实时渲染之前的precalculate的过程。

    下面是静态渲染的性质:
    1,静态光照的渲染速度永远相同,无论是一盏光源,没有光源,还是几万个光源,速度都是相同的。
    2,光照贴图分辨率会影响内存和文件大小,而不是帧率。这一点和纹理一样
    3,烘焙时间会随着光照贴图分辨率,模型和光源数量以及质量设施的提升而增加。

    动态光照

    从流程上来说:
    1,动态光照借助Gbuffer缓冲实现实时渲染
    2,光源可以被随意改变,移动,添加或者删除
    3,不需要准备任何特殊的模型
    4,阴影对于性能的开销很大
    5,使用动态光照更复杂:使用静态光照时,只需要放置光源,设置渲染选项,点击构建就可以了,UE4就会帮助渲染。
    从质量上来说
    1,阴影的开销很大,所以通常需要降低阴影渲染质量或者降低其他画面的渲染质量,或者禁用一些功能来补偿。
    2,动态光照不会对大部分内容产生辐射或者全局光照。
    3,动态光照通常看起来更锐利。
    4,动态光照不会产生软阴影,往往不会达到正确的渲染效果。
    5,动态光照看起来更清晰更鲜活。
    6,动态光照能很好的使用动态阴影,并不关心目标有多大

    四种主要的动态阴影类型

    1,常规动态阴影RDS
    是指那些被设置成可移动,并正在投射的动态阴影。
    在这里插入图片描述

    2,逐个对象阴影
    固定阴影会混合使用完全依赖光照贴图的静态光照以及完全动态光照。
    3,级联阴影地图(Cascaded Shadow Maps)
    根据距离渲染动态阴影,并切换不同分辨率的贴图。可以在细节面板里设置。
    在这里插入图片描述
    4,距离场阴影(Distance Field Shadows)
    CSM更倾向于处理距离较近的阴影,而DFS就更善于处理长距离和大场景的阴影。它并不是很准确,但是开销很小。

    阴影的计算
    1,首先要知道点与点之间的距离
    2,要知道光源在哪里,以及光线经过时离几何体有多近
    3,几何体距离下一个击中的点有多远,阴影要覆盖多长的距离
    如果有某种方法能够存储模型之间的距离信息,实时计算所有这些数据,花费的时间就会更少。所以就会考虑用距离场阴影,这是目前唯一在UE4中真正实用的方法。

    渲染
    阴影被像素着色器计算和使用
    动态光照是以一个球体被渲染的
    渲染方式类似于遮罩
    球体内的任何像素都会进行着色运算来混合光照

    因此在使用动态光照时要注意
    1,动态光照在延时渲染中开销很低,但是在前向渲染中开销很高
    2,开销取决于像素着色器的操作,因此像素越多,渲染越慢
    3,光源离摄像机越近,影响到的像素越多,渲染也就越慢
    4,需要尽可能的缩小光圆半径
    5,尽量避免光照重叠

    展开全文
  • 预先计算的辐照度值通常与漫反射颜色或反照率映射相乘,存储...将光照和表面颜色分开会消耗更少的内存。 除了最严格的硬件平台外,现在很少使用预先计算的辐照度。根据定义,辐照度是针对给定法线方向计算的,因此我们
  • UE5全局光照系统Lumen解析与优化

    千次阅读 2022-06-18 00:44:33
    全局光照Global illumination (GI),又称间接光照,是指一系列让计算机场景光照更加真实自然的3D图形算法。通俗来讲,即计算机在进行图形渲染时,不仅要考虑从光源直接照射到物体表面的光,也要考虑到从其他表面反射...
  • 全局光照(简述)

    千次阅读 2020-05-11 22:05:23
    一、什么是全局光照 全局光照(Global Illumination,简称 GI), 作为图形学中比较酷的概念之一,是指既考虑场景中来自光源的直接光照,又考虑经过场景中其他物体反射后的间接光照的一种渲染技术。 即可以理解为:...
  • Unity 5 中的全局光照技术详解.doc Unity 5 中的全局光照技术详解.doc Unity 5 中的全局光照技术详解.doc Unity 5 中的全局光照技术详解.doc Unity 5 中的全局光照技术详解.doc
  • 1. 光与表面的交互 2. 采样与重建 3. 光线追踪 4. 基于预计算的光照技术 5. DXR与实时光线追踪
  • 1、全局光照GI 全局照明是一个系统,用于模拟光从表面反射到其他表面(间接光)的方式,而不仅仅是直接从光源(直接光)照射到表面的光。 全局光照=直接光+间接光 没有光照的地方是一片死黑;可以想象现实生活中...
  • 【UE4从零开始 082】全局光照

    千次阅读 2019-09-19 16:07:39
    Lightmass(全局光照) 创建具有复杂光交互作用的光照图,例如区域阴影和漫反射。它用于预计算 static(静态) 和 stationary(静止) 光源的照明贡献部分。 编辑器和全局光照之间的通信由 Swarm Agent 处理,它管理...
  • 搜索引擎-基于实时全局光照的3D绘制引擎研究和开发.pdf
  • 全局光照算法:IBL

    千次阅读 2022-02-28 13:10:59
    它们可以由渲染引擎捕捉, 也可以高动态范围图像的形式从相机获得. 局部光探头,用于从特定角度捕捉世界的某个区域。捕捉会投影到立方体或球体上, 具体取决于周围的几何体。局部探头比远程探头更精确,在
  • 谈及光照模式与阴影,不可避免的需要知道:全局光照阴影技术从何而来?为什么需要这些技术? 什么是全局光照? 全局照明(GI)是一个系统,用于模拟光从表面反射到其他表面(间接光)的方式,而不是仅限于直接从光源...
  • 什么是全局光照全局光照,指的就是模拟光线是如何在场景中进行传播的,不仅会考虑那些直接光照的效果,还会计算光线被不同的物体表面反射而产生的间接光照。 Unity使用实时+预计算的方式来模拟场景中的光照:...
  • 解析全局光照Global Illumination Explained 前言:Global Illumination全局光照技术是实时渲染的必然发展方向。我参考了一些研究成果,琢磨了一下,让更多的人可以理解这项“古老”的技术。 Front Line 虽然说...
  • 全局光照介绍 全局光照技术本身是一个很复杂的技术,有非常多方式实现。从管线来说有光栅化实现的全局光照,有光线追踪实现的更逼真的行为树。而我们当前主流的或者说更多人讨论的是光栅化下的全局光照。 而全局...
  • 局部光照与全局光照的区别

    千次阅读 2019-10-01 19:35:27
    全局光照(Global illumination) 简单的说就是考虑到环境中所有表面和光源相互作用的照射效果 采用Ray Tracing和Radiosity两种技术来计算全局光照 Ray Tracing用于计算镜面反射,灯光透过玻璃的效果和阴影,还有模拟...
  • 比利时的 鲁汶大学 计算机系教授 Philip Dutré 的全局光照教程,和他与合作者在 2002年 SIGGRAPH ppt

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 15,071
精华内容 6,028
关键字:

动态全局光照