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

    我们知道全局光照是图形学中一项比较难实现的技术,因为真正要得到全局光照是需要一个点跟所有点的关系计算的,而这个计算如果用在计算机那是不太可能实现的。而现代技术利用了一些比如有向距离场,体素,辐照度等方式实现全局光照,还有就是越来越火的光纤追踪技术实现全局光照。但是这些技术的消耗都很大,包括内存,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 

    展开全文
  • Unity 全局光照LightMap 动态加载

    千次阅读 2016-01-11 11:03:12
    Unity 全局光照LightMap 动态加载

    Unity5 里面, 当场景里的物体保存成Prefab之后,LightMap的信息就会丢失。Fuck。。

    所以最后就写了个脚本,把每个Render里的lightmap纪录下来,当prefab实例化之后,重新设置。

    上代码。。


    相关设置:



    注意事项:检查下是否勾选了 Static -> BatchingStatic ,如果勾选了,一定要去除勾选 !!!!!!

    using UnityEngine;  
    using System.Collections;  
    using System.Collections.Generic;
    using UnityEngine.Rendering;
    
    public class PrefabLightmapData : MonoBehaviour {
    
    	//LightMap信息
    	[System.Serializable]  
    	public struct RendererInfo  
    	{  
    		public Renderer     renderer;  
    		public int          lightmapIndex;  
    		public Vector4      lightmapOffsetScale;  
    	}
    
    	//场景中的Fog信息
    	[System.Serializable]  
    	public struct FogInfo  
    	{  
    		public bool         fog;  
    		public FogMode      fogMode;  
    		public Color        fogColor;
    		public float        fogStartDistance;
    		public float        fogEndDistance;
    		public float 		fogDensity;
    	}
    
    
    	public FogInfo fogInfo;
    	public List<RendererInfo> m_RendererInfo; 
    	public List<Texture2D> lightmapNear;
    	public List<Texture2D> lightmapFar;
    	public LightmapData[] lightmapData;
    	public LightmapsMode lightmapsMode;
    
    	//地形的LightMap信息
    	public Terrain terrain;
    	public RendererInfo terrainRendererInfo;
    
    	//设置光照信息
    	[ContextMenu("SetUp")]
    	public void SetUp(){  
    		lightmapData = new LightmapData[lightmapNear.Count > lightmapFar.Count ? lightmapNear.Count : lightmapFar.Count];
    		for(int i = 0; i < lightmapData.Length; i ++){
    			lightmapData[i]=new LightmapData();
    			lightmapData[i].lightmapFar = i < lightmapFar.Count ? lightmapFar[i] : null;
    			lightmapData[i].lightmapNear = i < lightmapNear.Count ? lightmapNear[i] : null;
    		}
    		LightmapSettings.lightmapsMode = lightmapsMode;
    		LightmapSettings.lightmaps=lightmapData;
    		LoadLightmap();
    		RenderSettings.fog = fogInfo.fog;
    		RenderSettings.fogMode = fogInfo.fogMode;
    		RenderSettings.fogColor = fogInfo.fogColor;
    		RenderSettings.fogStartDistance = fogInfo.fogStartDistance;
    		RenderSettings.fogEndDistance = fogInfo.fogEndDistance;
    		RenderSettings.fogDensity = fogInfo.fogDensity;
    	}
    
    	//保存光照信息
    	[ContextMenu("SaveData")]
    	public void SaveData(){  
    		SaveLightmap ();
    	}
    	
    	public void SaveLightmap()
    	{  
    		fogInfo = new FogInfo ();
    		fogInfo.fog = RenderSettings.fog;
    		fogInfo.fogMode = RenderSettings.fogMode;
    		fogInfo.fogColor = RenderSettings.fogColor;
    		fogInfo.fogStartDistance = RenderSettings.fogStartDistance;
    		fogInfo.fogEndDistance = RenderSettings.fogEndDistance;
    
    		lightmapNear = new List<Texture2D>();
    		lightmapFar = new List<Texture2D>();
    		for(int i = 0; i < LightmapSettings.lightmaps.Length; i ++){
    			LightmapData data = LightmapSettings.lightmaps[i];
    			if(data.lightmapNear != null){
    				lightmapNear.Add(data.lightmapNear);
    			}
    
    			if(data.lightmapFar != null){
    				lightmapFar.Add(data.lightmapFar);
    			}
    		}
    		m_RendererInfo = new List<RendererInfo> ();
    		var renderers = GetComponentsInChildren<MeshRenderer>();  
    		foreach (MeshRenderer r in renderers) {  
    			if (r.lightmapIndex != -1) {  
    				RendererInfo info = new RendererInfo();  
    				info.renderer = r;  
    				info.lightmapOffsetScale = r.lightmapScaleOffset;  
    				info.lightmapIndex = r.lightmapIndex;  
    				m_RendererInfo.Add(info);  
    			}  
    		}
    
    		terrain = GetComponentInChildren<Terrain> ();
    		if (terrain != null) {
    			terrainRendererInfo = new RendererInfo();
    			terrainRendererInfo.lightmapOffsetScale = terrain.lightmapScaleOffset;  
    			terrainRendererInfo.lightmapIndex = terrain.lightmapIndex;  
    		}
    		lightmapsMode = LightmapSettings.lightmapsMode;
    	}  
    	
    	public void LoadLightmap()  
    	{  
    		if (m_RendererInfo.Count <= 0) return;  
    
    		if (terrain != null) {
    			terrain.lightmapScaleOffset = terrainRendererInfo.lightmapOffsetScale;
    			terrain.lightmapIndex = terrainRendererInfo.lightmapIndex;
    		}
    
    		foreach (var item in m_RendererInfo) {  
    			item.renderer.lightmapIndex = item.lightmapIndex;  
    			item.renderer.lightmapScaleOffset = item.lightmapOffsetScale;  
    		}  
    	}
    }
    

    当场景中LightMap烘培好了之后,在perfab根节点上面挂上这个脚本,右键-》SaveData,之后apply prefab。

    在运行时场景初始化完成之后。调用SetUp方法,即可挂载lightMap。


    重点!!我遇上个问题,需要保持原来存在的渲染场景,assetbundle才的LightMap能正常。否则就不会有LightMap,希望谁来个提示。

    如果把原来渲染lightmap的场景删了,那么在手机上就会加载不到。
    我估摸着是因为assetbundle的时候,没有把lightmap的贴图打包进去,只保存了引用的关系。
    所以如果场景删了,那么lightmap的贴图也丢了。

    如有疑问,请回复哦~~



    展开全文
  • 动态场景的全局光照实时绘制,一篇浙大的硕士论文,里面对于光照技术有很详细的讲解。
  • 全局光照

    2019-06-29 14:59:22
    gi is a system that models(动态模拟的意思) how light is bounced off of surfaces onto other surfaces (indirect light) rather than being limited to just the light that hits a surface direct...

    global illumination

    gi is a system that models(动态模拟的意思) how light is bounced off of surfaces onto other surfaces (indirect light) rather than being limited to just the light that hits a surface directly from a light source (direct light).

    modelling (模拟)indirect lighting allows for effects that make the virtual world seem more realistic and connected(更加逼真,更加连续), since objects affect each other’s appearance. once classic example is ‘color bleeding’ where, for example, sunlight hitting a red sofa will casuse red light to be bounced onto the wall behind it.

    another is when sunlight hits the floor at the opening of a cave and bounces around inside so the inner parts of the cave are illuminated too.

    global illumination in the scene view. note the subtle effect of indirect lighting.

    gi concepts

    traditionally, video games and other realtime graphics applications have been limited to direct lighting, while the calculations required for indirect lighting were too slow so they could only be used in non-realtime situations such as CG animated films. a way for games to work around this limitation is to calcualte indirect light only for objects and surfaces that are known ahead of time to not move around (that are static). thay way the slow computation can be done ahead of time, but since the objects do not move, the indirect light that is pre-calcualted this way will still be correct at runtime.

    unity supports this technique, called baked gi (also known as baked lightmaps), which is named after “the bake” the process in which the indirect light is precalcualted and stored (baked). in addition to indirect light, bakded gi also takes advantage of the greater computation time avaiable to generate more realistic soft shadows from area lights and indirect light than what can normally be archieved with realtime techniques.

    additionally, unity 5.0 adds support for a new technique called precomputed realtime gi. it still requires a precomputation phase similar to the bake mentioned above, and it is still limited to static objects.

    however, it does not just precompute how light bounces in the scene at the time it is built, but rather it precomputes all possible light bounces and encodes this information for use at runtime.

    so essentially for all static objects it answers the question “if any light hits this surface, where does it bounce to?”

    unity then saves this information about which paths light can propagate by later use.

    the final lighting is done at runtime by feeding the actual lights present into these previously computed light propagation paths.

    this means that the number and type of lights, their position, direction and other propertiers can all be changed and the indirect lighting will update accrodingly. similarly it is also possible to change material properties of obejcts, such as their color, how much light they emit themselves.

    limitations of gi

    both baked gi and precomputed realtime gi have the only static objects can be included in the bake/precomputation— so moving objects can not bounce light onto other objects and vice versa.反之亦然

    however they can still pick up bounce light from static objects using LightProbes. light probes are positions in the scene where the light is measured (probed) during the bake/precompuation, and then at runtime the indirect light that hits non-static objects is approximated using the values from the probes

    so for example a red ball that rolls up next to a white wall would not bleed its color onto the wall, but a white ball next to a red wall could pick up a red color bleed from the wall via the light probes.

    展开全文
  • 烘焙和采样光照贴图 显示直射光 创建自发光材质 通过探针和LPPV采样光线 支持预计算的实时全局光照 这是Unity可编程渲染管线系列教程的第八部分。我们不仅将支持静态的全局光照还会支持动态全局光照。 ...
  • Unity支持多种计算场景全局光照的方法其中一种是为场景中的表面使用Enlighten来烘培包含全局光照信息的光照贴图另一种方法是将全局光照信息烘焙到光照探针中这两个系统可以结合使用来实现场景中的不同效果光照贴图...
  • Unity Shader 学习笔记(33) 全局光照(GI)、反射探针、线性空间和伽马空间、高动态范围(HDR) 参考书籍:《Unity Shader 入门精要》 【《Real-Time Rendering 3rd》 提炼总结】(八) 第九章 · 全局光照:光线...
  • 在今天推出的LayaAir 2.10beta版里,3D渲染效果再次得以提升,增加了DirectLightMap全局光照贴图、增加了深度渲染管线DepthPass,增加了Camera截屏功...
  • 在今天推出的LayaAir 2.10beta版里,3D渲染效果再次得以提升,增加了DirectLightMap全局光照贴图、增加了深度渲染管线DepthPass,增加了Camera截屏功能,增加了后期处理Enable参数,支持动态切换shaderPass,一次...
  • 今天,我们继续给大家解答Unity 5 全局光照系统Enlighten中的其他常见问题。 为什么烘焙的point灯光会有一圈圈的色阶变化?  大家在烘焙lightmap的时候可能会发现类似下图的奇怪效果。
  • unity5 新的全局光照系统,开销比较大,大部分功能只有PC平台上才能跑得动,但也有部分移动设备上也可以使用 1 Static Light 原Lightmap光照贴图烘培 2 Emission 用材质的自发光来照亮影响周围物体,支持动态...
  • 这篇文章主要讲全局光照,在看教程的时候就有一个点不是很理解,就是作者开启物体的static这个选项。在网上查找一些资料,有的说”static表示物体时静态的,多用于静止不动的物体,此外static有多种,有的用于烘焙,...
  • 光照也是实时渲染的最重要的部分之一,和反射一样,光照和阴影在实时渲染中的开销也很大,因此一部分计算被分流到预先计算/预算渲染中,而静态光照是指...1,静态光照可以处理辐射和全局光照 2,可以获得真实的阴影效
  • 写在前面Unity的光照贴图在5.0版本做出了重大的改善,从 Beast全局光照系统替换为Enlighten全局光照系统。Lighting Data Asset记录了整个场景的GI数据(Global Illumination (GI)不仅记录直接从光源击中表面的光...
  • SH)模拟动态全局光照是游戏引擎里通用的解决方案。针对SH的介绍大部分过于偏学术,在实际的应用中去理解会更浅显易懂一些。实时计算间接光照是一个难题,因为要计算最少一次积分。数学上常常把很难在某个空间得到...
  • UE4光照学习笔记

    2021-02-01 23:26:25
    结合使用静态光照动态光照 光照特效 反射 雾和立体光源 全局烘焙ligthmass进阶 其他光照技巧 关于体积雾的设置 光照基础 四种基本光照Actor SkyLight是一种特殊的光照:采集一张天空360度全景图...
  • 文中的描述是,介绍了一种用于计算散射光传递的新技术,并演示如何用它来计算运动场景中的全局光照。主要是一种用GPU加速环境光遮蔽计算的技术,并将此算法变成了实时的解决方案。 【核心要点】 ...
  • 在unity5新版本中,是完全新的光照系统,由以下三部分组成:Enlighten + Probes + Screen Space Reflection Enlighten Enlighten是全局的基础光照,由于它不能...除了静态的光照实现,动态全局光照实现则由Probes
  • Unity全局照明.md

    2021-01-25 15:18:36
    把光源对静态物体的光照效果提前烘培到一张lightmap,然后把lightmap采样到物体表面以产生全局光照效果。 ###LightMap 静态物体使用 bake lightmap Light Probes 光照探针是为了让动态物品也可以受bake GI的影响。 ...
  •  其全新的立体像素全局光照(VXGI)技术首次让游戏GPU能够提供实时的动态全局光照效果。由于光线能够在游戏环境中逼真地互动,因此场景的逼真度大幅提升,可为游戏玩家带来更强烈的临场感。  基于Maxwell架
  • 依据视觉感光适应性对乘性光照图像进行动态范围调整, 并同反射图像相乘获取全局增强结果; 将全局增强结果同原始图像融合, 并对低照度区域进行颜色校正, 获取"视觉匹配"结果. 实验证明本文算法的场景再现...
  • 重要资料集合

    2011-04-25 15:21:00
    动态全局光照、延迟光照、自然光照与动态软阴影、体积化视野范围雾化、动态模糊与景深等等技术的应用让游戏宛如真实世界 http://www.hxsd.com/news/cg-game/20100805/28908_8.html 2:什么是渲染器...
  • 烘焙技术可以将场景中静态物体烘焙出真实的光影...原理:在场景 中先放置一些灯光效果的采样点,收集指定区域的明暗信息,利用内部的差值运算,将详细作用到的动态的游戏模型上,这样也不会全局实时光照那样消耗性能...
  • 和Epic Game公司的虚幻引擎5惊艳了全球游戏业,其Nanite虚拟微多边形几何技术和Lumen动态全局光照技术带来了产业界的飞跃。Nanite虚拟几何技术的出现意味着由数以亿计的多边形组成的影视级艺术作品可以被直接导入...
  • 今天还是跟大家聊一聊最近很火的虚拟引擎,Epic Game公司的虚幻引擎5惊艳了全球游戏业,其Nanite虚拟微多边形几何技术和Lumen动态全局光照技术带来了产业界的飞跃。Nanite虚拟几何技术的出现意味着由数以亿计的...
  • 首先,使用哪一款游戏引擎去制作一款游戏,并不是根据使用者的喜好来制定的。开发者们的喜好千奇百怪,但最终能...其Nanite虚拟微多边形几何技术和Lumen动态全局光照技术,几乎可以算得上是一次渲染界的产业革命了。...

空空如也

空空如也

1 2 3 4 5
收藏数 82
精华内容 32
关键字:

动态全局光照