unity可否将多张地图载入到同一个场景中,同时保留lightmap信息

2024-12-31 22:03:51
推荐回答(1个)
回答1:

为什么要动态更新Lightmap

项目内需要对项目进行动态更新或者制作如白天黑夜等,同一场景不同光照渲染的情况。

将场景(.unity)文件转换成(.prefab)文件,能够更加自由的操作场景资源的更换。

修改功能支持

添加多张光照贴图烘焙

具体代码如下:

using UnityEngine;
using System.Collections.Generic;
using System.IO;
using GOE.Scene;
using UnityEditor;
using UnityEditor.SceneManagement;
using UnityEngine.SceneManagement;
using SceneManager = UnityEngine.SceneManagement.SceneManager;

///


/// 描述:动态烘焙场景光照模型,并产生对应的Prefab文件
/// 创建时间:2016-06-15
///

public sealed class LightMapEditor
{

private const string LightMapsDir = "Resources/Lightmaps/";

private static List sceneLightmaps = new List();

public static void UpdateLightmaps()
{
PrefabLightmapData pld = GameObject.FindObjectOfType();
if (pld == null) return;

LightmapSettings.lightmaps = null;
PrefabLightmapData.ApplyLightmaps(pld.mRendererInfos , pld.mLightmapFars , pld.mLightmapNears);

Debug.Log("Prefab Lightmap updated");
}

public static void GenLightmap()
{
genBakeLightmapAndPrefab(false);

EditorSceneManager.SaveOpenScenes();
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();

Debug.Log("----------------Update to Prefab Lightmap Finish -------------------------");
}

///
/// 生成lightmap和prefab资源
///

private static void genBakeLightmapAndPrefab()
{
if (Lightmapping.giWorkflowMode != Lightmapping.GIWorkflowMode.OnDemand)
{
Debug.LogError("ExtractLightmapData requires that you have baked you lightmaps and Auto mode is disabled.");
return;
}
Debug.ClearDeveloperConsole();

PrefabLightmapData[] pldArr = GameObject.FindObjectsOfType();
if (pldArr == null || pldArr.Length <= 0)
{
EditorUtility.DisplayDialog("提示", "没有找到必要的脚本PrefabLightmapData,请检查场景", "OK");
return;
}

Lightmapping.Bake();
sceneLightmaps.Clear();

string path = Path.Combine(Application.dataPath, LightMapsDir);
if (!Directory.Exists(path))
{
Directory.CreateDirectory(path);
}

Scene curScene = EditorSceneManager.GetActiveScene();
string sceneName = Path.GetFileNameWithoutExtension(curScene.name);
string scenePath = Path.GetDirectoryName(curScene.path) + "/" + sceneName + "/";
string resourcesPath = Path.GetDirectoryName(curScene.path) + "/" + sceneName + "_lightmap/" + sceneName;

foreach (PrefabLightmapData pld in pldArr)
{
GameObject gObj = pld.gameObject;
List renderers = new List();
List lightmapFars = new List();
List lightmapNears = new List();

genLightmapInfo(scenePath, resourcesPath, gObj, renderers, lightmapFars, lightmapNears);

pld.mRendererInfos = renderers.ToArray();
pld.mLightmapFars = lightmapFars.ToArray();
pld.mLightmapNears = lightmapNears.ToArray();

GameObject targetPrefab = PrefabUtility.GetPrefabParent(gObj) as GameObject;

if (targetPrefab != null)
{
//自定义存放的路径
PrefabUtility.ReplacePrefab(gObj, targetPrefab);
}
else
{
//默认路径
string prefabPath = Path.GetDirectoryName(curScene.path) + "/" + sceneName + ".prefab";
PrefabUtility.CreatePrefab(prefabPath, gObj, ReplacePrefabOptions.ConnectToPrefab);
}

//改变当前场景中的光照贴图信息
PrefabLightmapData.ApplyLightmaps(pld.mRendererInfos, pld.mLightmapFars, pld.mLightmapNears);
}
}

private static void genLightmapInfo(string scenePath , string resourcePath , GameObject root,
List renderers, List lightmapFars,
List lightmapNears)
{
MeshRenderer[] subRenderers = root.GetComponentsInChildren();

LightmapData[] srcLightData = LightmapSettings.lightmaps;

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;

Texture2D lightmapFar = srcLightData[meshRenderer.lightmapIndex].lightmapFar;
Texture2D lightmapNear = srcLightData[meshRenderer.lightmapIndex].lightmapNear;

int sceneCacheIndex = addLightmap(scenePath, resourcePath, renderInfo.LightmapIndex, lightmapFar,
lightmapNear);

renderInfo.LightmapIndex = lightmapFars.IndexOf(sceneLightmaps[sceneCacheIndex].LightmapFar);
if (renderInfo.LightmapIndex == -1)
{
renderInfo.LightmapIndex = lightmapFars.Count;
lightmapFars.Add(sceneLightmaps[sceneCacheIndex].LightmapFar);
lightmapNears.Add(sceneLightmaps[sceneCacheIndex].LightmapNear);
}

renderers.Add(renderInfo);
}
}

private static int addLightmap(string scenePath, string resourcePath, int originalLightmapIndex,
Texture2D lightmapFar,
Texture2D lightmapNear)
{

for (int i = 0; i < sceneLightmaps.Count; i++)
{
if (sceneLightmaps[i].OriginalLightmapIndex == originalLightmapIndex)
{
return i;
}
}

RemapTexture2D remapTex = new RemapTexture2D();
remapTex.OriginalLightmapIndex = originalLightmapIndex;
remapTex.OrginalLightmap = lightmapFar;

string fileName = scenePath + "Lightmap-" + originalLightmapIndex;
remapTex.LightmapFar = getLightmapAsset(fileName + "_comp_light.exr", resourcePath + "_light",
originalLightmapIndex);

if(lightmapNear != null)
remapTex.LightmapNear = getLightmapAsset(fileName + "_comp_dir.exr", resourcePath + "_dir",
originalLightmapIndex);

sceneLightmaps.Add(remapTex);

return sceneLightmaps.Count - 1;
}

private static Texture2D getLightmapAsset(string fileName, string resourecPath, int originalLightmapIndex)
{
TextureImporter importer = AssetImporter.GetAtPath(fileName) as TextureImporter;
if (importer == null) return null;
importer.isReadable = true;
AssetDatabase.ImportAsset(fileName , ImportAssetOptions.ForceUpdate);

Texture2D assetLightmap = AssetDatabase.LoadAssetAtPath(fileName);
string assetPath = resourecPath + "_" + originalLightmapIndex + ".asset";
Texture2D newLightmap = GameObject.Instantiate(assetLightmap);

string dir = Path.GetDirectoryName(assetPath);
if (!Directory.Exists(dir)) Directory.CreateDirectory(dir);

// byte[] bytes = newLightmap.EncodeToPNG();
// File.WriteAllBytes(assetPath, bytes);
AssetDatabase.CreateAsset(newLightmap , assetPath);

newLightmap = AssetDatabase.LoadAssetAtPath(assetPath);

importer.isReadable = false;
AssetDatabase.ImportAsset(assetPath , ImportAssetOptions.ForceUpdate);
return newLightmap;
}
}

PrefabLightData

用于还原和记录光照数据

using UnityEngine;
using System.Collections;
using System.Collections.Generic;

namespace GOE.Scene
{
///
/// 描述:光照模型预设
///

[DisallowMultipleComponent , ExecuteInEditMode]
public class PrefabLightmapData : MonoBehaviour
{
[SerializeField]
public RendererInfo[] mRendererInfos;

[SerializeField]
public Texture2D[] mLightmapFars;

[SerializeField]
public Texture2D[] mLightmapNears;

void Awake()
{
ApplyLightmaps(mRendererInfos , mLightmapFars , mLightmapNears);

//设置原来烘焙时的光照模式,这个不设置正确,默认模式就会只显示光照贴图
LightmapSettings.lightmapsMode = LightmapsMode.NonDirectional;
}

void Start()
{
// StaticBatchingUtility.Combine(this.gameObject);
}

///
/// 应用光照模型,根据指定的渲染信息
///

///
///
///
public static void ApplyLightmaps(RendererInfo[] rendererInfos, Texture2D[] lightmapFars,
Texture2D[] lightmapNears)
{
if (rendererInfos == null || rendererInfos.Length <= 0)
{
Debug.LogWarning("<> renderer info is null !");
return;
}

LightmapData[] settingLightMaps = LightmapSettings.lightmaps;
int[] lightmapOffsetIndex = new int[lightmapFars.Length];
List combinedLightmaps = new List();

bool existAlready = false;
for (int i = 0; i < lightmapFars.Length; i++)
{
existAlready = false;
for (int j = 0; j < settingLightMaps.Length; j++)
{
if (lightmapFars[i] == settingLightMaps[j].lightmapFar)
{
lightmapOffsetIndex[i] = j;
existAlready = true;
break;
}
}