1500字范文,内容丰富有趣,写作好帮手!
1500字范文 > unity 烘焙 光照贴图 以及一些灯光的相关问题(二)

unity 烘焙 光照贴图 以及一些灯光的相关问题(二)

时间:2022-08-30 10:48:42

相关推荐

unity 烘焙 光照贴图 以及一些灯光的相关问题(二)

在上一篇了解了光照以及光照贴图的一些相关属性后,在这篇具体讲讲相关的使用,以及自己预见的一些坑。

首先还是在上一篇的场景基础上,我们隐藏Realtime和Mixed光源,只留Baked的光源用来进行场景的烘焙。在Lighting设置中,只勾选Baked GI选项,Lighting Mode选择Subtractive。取消自动烘焙Auto Generate的勾选,点击Generate Lighting,手动生成Lightmap。同时Unity会在.scene文件同级目录下生成一个和scene名相同名称的文件夹,用于存放lightmap数据。相比自动生成的情况,在Baked Lightmaps中会多出一个Lighting Data Asset的参数,对应的LightingData.asset文件用于存放一些Lighting数据。

生成好之后运行Unity,修改Baked光源发现不影响场景的显示,一切都正常。

但是,当我们把静态场景存为Prefab的时候,就会出现一些问题了。而在实际的开发中,很多情况下会把静态的场景存为Prefab用于动态的加载。

我们将测试场景的物体放在同一个根目录下,然后将其转变为Prefab,点击运行。你会发现动态物体(胶囊体)也受到了baked光源的影响,变成了红色。关闭baked光源你会发现整个场景的物体都变黑了,baked的光源效果变成了realtime。

我们随便点击一个静态物体会发现其MeshRenderer中的Lightmapping属性关联的Lightmap不见了。造成这一现象的原因是,我们生成Lightmap的时候,其对应的信息都是和场景中GameObject的唯一ID相关联。当我们将这些GameObject变为Prefab时(包括后期加载该Prefab到场景中),唯一ID发生了变化,导致信息无法正确的关联起来。

有一个解决方案是,我们创建一个组件,挂载Prefab上。在烘焙完成后,这个组件会遍历该节点下所有静态物体的MeshRenderer,存储对应的Lightmap信息。当加载该Prefab的时候,将对应的Lightmap信息重新关联到对应的MeshRenderer上,代码如下:

注:由于很多时候美术可能会在一个新的场景中设置地图,然后会设置一些环境光,Fog等信息,我们程序在别的场景加载的时候,除了对应的地图Prefab外,这些信息也应该对应的设置,所以同Lightmap一起写在了脚本中。

注:由于Terrain比较特殊,如果地图中用到的话,需要单独读取信息。

using UnityEngine;using System.Collections.Generic;using UnityEngine.Rendering;/// <summary>/// 渲染信息/// </summary>[System.Serializable]public struct RendererInfo{public Renderer renderer;public int LightmapIndex;public Vector4 LightmapOffsetScale;}[System.Serializable]public class SettingProperty{[SerializeField]public Material Skybox;[SerializeField]public LightmapsMode Mode;[SerializeField]public Texture2D[] LightmapsColor;[SerializeField]public Texture2D[] LightmapsDir;[SerializeField]public Texture2D[] ShadowMask;[SerializeField]public LightProbes Probes;[SerializeField]public Color AmbientColor;[SerializeField]public AmbientMode AmbientMode;[SerializeField]public Color SkyColor;[SerializeField]public Color EquatorColor;[SerializeField]public Color GroundColor;[SerializeField]public bool UseFog;[SerializeField]public Color FogColor;[SerializeField]public FogMode FogMode = FogMode.Linear;[SerializeField]public float FogDensity;[SerializeField]public float LinearFogStartDistance = 0;[SerializeField]public float LinearFogEndDistance = 300;[SerializeField]public RendererInfo[] RendererInfos;[SerializeField]public RendererInfo TerrainRendererInfo;}public class LightmapConfig: MonoBehaviour{static LightmapConfig _instance;public static LightmapConfig sInstance { get { return _instance; } }public SettingProperty Setting;private SettingProperty OriginalSetting;private static Stack<LightmapConfig> sConfigStack = new Stack<LightmapConfig>();void Awake(){_instance = this;SwichLightmapConfig();sConfigStack.Push(this);}void OnDestroy(){if (sConfigStack.Count > 0){sConfigStack.Pop();if (sConfigStack.Count > 0){_instance = sConfigStack.Peek();_instance.SwichLightmapConfig();}}}public void StoreCurrentConfig(){Setting = new SettingProperty();StoreSettings(ref Setting);}//读取信息public virtual void StoreSettings(ref SettingProperty prop){prop.Skybox = RenderSettings.skybox;prop.AmbientColor = RenderSettings.ambientLight;prop.AmbientMode = RenderSettings.ambientMode;prop.SkyColor = RenderSettings.ambientSkyColor;prop.EquatorColor = RenderSettings.ambientEquatorColor;prop.GroundColor = RenderSettings.ambientGroundColor;prop.UseFog = RenderSettings.fog;prop.FogColor = RenderSettings.fogColor;prop.FogMode = RenderSettings.fogMode;prop.FogDensity = RenderSettings.fogDensity;prop.LinearFogStartDistance = RenderSettings.fogStartDistance;prop.LinearFogEndDistance = RenderSettings.fogEndDistance;prop.LightmapsColor = new Texture2D[LightmapSettings.lightmaps.Length];prop.LightmapsDir = new Texture2D[LightmapSettings.lightmaps.Length];prop.ShadowMask = new Texture2D[LightmapSettings.lightmaps.Length];for (int i = 0; i < LightmapSettings.lightmaps.Length; i++){prop.LightmapsColor[i] = LightmapSettings.lightmaps[i].lightmapColor;prop.LightmapsDir[i] = LightmapSettings.lightmaps[i].lightmapDir;prop.ShadowMask[i] = LightmapSettings.lightmaps[i].shadowMask;}List<RendererInfo> renderers = new List<RendererInfo>();MeshRenderer[] subRenderers = GetComponentsInChildren<MeshRenderer>();foreach (MeshRenderer meshRenderer in subRenderers){if (meshRenderer.lightmapIndex == -1) continue;RendererInfo renderInfo = new RendererInfo();renderInfo.renderer = meshRenderer;renderInfo.LightmapIndex = meshRenderer.lightmapIndex;renderInfo.LightmapOffsetScale = meshRenderer.lightmapScaleOffset;renderers.Add(renderInfo);}prop.RendererInfos = renderers.ToArray();Terrain terrain = GetComponentInChildren<Terrain>();if (terrain != null){prop.TerrainRendererInfo = new RendererInfo();prop.TerrainRendererInfo.LightmapIndex = terrain.lightmapIndex;prop.TerrainRendererInfo.LightmapOffsetScale = terrain.lightmapScaleOffset;}}//重新设置public virtual void ApplyConfig(SettingProperty prop){RenderSettings.skybox = prop.Skybox;RenderSettings.ambientLight = prop.AmbientColor;RenderSettings.fog = prop.UseFog;RenderSettings.fogColor = prop.FogColor;RenderSettings.fogMode = prop.FogMode;RenderSettings.fogDensity = prop.FogDensity;RenderSettings.fogStartDistance = prop.LinearFogStartDistance;RenderSettings.fogEndDistance = prop.LinearFogEndDistance;RenderSettings.ambientMode = prop.AmbientMode;RenderSettings.ambientSkyColor = prop.SkyColor;RenderSettings.ambientEquatorColor = prop.EquatorColor;RenderSettings.ambientGroundColor = prop.GroundColor;if (prop.LightmapsColor != null && prop.LightmapsColor.Length > 0){LightmapData[] lds = new LightmapData[prop.LightmapsColor.Length];for (int i = 0; i < prop.LightmapsColor.Length; i++){lds[i] = new LightmapData();lds[i].lightmapColor = prop.LightmapsColor[i];lds[i].lightmapDir = prop.LightmapsDir[i];lds[i].shadowMask = prop.ShadowMask[i];}LightmapSettings.lightmaps = lds;}else{LightmapSettings.lightmaps = null;}for (int i = 0; i < prop.RendererInfos.Length; i++){RendererInfo info = prop.RendererInfos[i];info.renderer.lightmapIndex = info.LightmapIndex;info.renderer.lightmapScaleOffset = info.LightmapOffsetScale;}Terrain terrain = GetComponentInChildren<Terrain>();if (terrain != null){terrain.lightmapIndex = prop.TerrainRendererInfo.LightmapIndex;terrain.lightmapScaleOffset = prop.TerrainRendererInfo.LightmapOffsetScale;}}void RestoreLightmapConfig(){if (OriginalSetting != null){ApplyConfig(OriginalSetting);}}public void SwichLightmapConfig(){if (Setting != null){OriginalSetting = new SettingProperty();StoreSettings(ref OriginalSetting);ApplyConfig(Setting);}}}

然后我们在Editor目录下创建一个脚本,如下,功能是该组件在Inspector添加一个按钮,点击后保存信息。

using UnityEditor;using UnityEngine;using System.Collections;[CustomEditor(typeof(LightmapConfig))]public class LightmapConfigInspector : Editor{public override void OnInspectorGUI(){GUI.changed = false;LightmapConfig config = target as LightmapConfig;Undo.RecordObject(config, "ModifyLightmapConfig");if(GUILayout.Button("Store Current Setting")){config.StoreCurrentConfig();}base.OnInspectorGUI();if (GUI.changed){EditorUtility.SetDirty(config);}}}

脚本搞好之后,我们在父节点上挂载LightmapConfig组件,然后重新烘焙后,点击Store Current Setting按钮,即可保存好Lightmap等信息。

然后运行Unity,会发现静态物体的Lightmap信息都关联上了。但是Baked的光源还是起到了realtime的效果,只有关闭了baked光源才正常。

针对烘焙光源全是Baked的话,我们可以在运行的时候取消这些光源,达到正确的效果。但是如果有mixed的光源,依旧还是会存在问题(即,mixed光源对静态物体进行烘焙,但是运行后还是产生影响,但是mixed光源不能像baked光源一样取消,因为它还需要对动态物体产生效果)

所以最终还是建议使用多场景的方式来处理。即在程序的Scene中,加载美术烘焙好的地图Scene(UnityEngine.SceneManagement.LoadSceneMode.Additive)

注:在Unity.2.3中,若不设置Map Scene为ActiveScene会出现花屏的现象,在中则正常。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。