Transfer Lightmaps in Unity | Unity中转移光照贴图

unity中光照贴图(lightmapping)的存储方式比较特殊,烘焙好的光照贴图存储在场景中,而参与烘焙的物体本身不记录光照贴图,只记录一组uv数据对应光照贴图。在显示的时候,shader通过这组uv坐标访问物体的光照贴图信息,再显示出来。 并且这些光照贴图没法用手动编辑,只能写脚本编辑。
而相对应的如果不在unity中烘焙,而在maya中烘焙,就是一张lightmapping放在shader的自发光贴图里面了。

所以问题在于,在unity中一个场景里烘焙的物体很难带着光照贴图放到另一个场景里。如果我们非要这么干,就得给被烘焙的Prefab加个脚本,记录光照贴图,在加入其它场景中重新加载光照贴图。

1. 光照贴图访问

首先是要访问一下Prefab里面所有子物体,从根节点遍历一下这个树就可以了,非常简单就不提了。
1

烘焙过的物体会有一个光照贴图的uv信息,以及所使用的光照贴图ID值。脚本中用物体的Render组件的lightmapIndexlightmapScaleOffset属性访问,lightmapScaleOffsetVector4类型,xyzw分别是Tiling X, Tiling Y, Offset X, Offset Y。比如:

而场景中存储的所有光照贴图用LightmapSettings这个类访问,典型使用方式如下:

LightmapData这个类会存两个属性,lightmapFarlightmapNear,类型是texture2D,也就是那张光照贴图了。

2. 贴图信息存储

我们要转移光照贴图先要记录光照贴图,信息记录在哪呢?首先想到直接存在脚本的类里,但是不可以,因为在物体放入新场景时会初始化这个脚本类,没法存下来。那么如果搞一个全局变量呢?或者一个静态类存储?这也不行,毕竟这样还是把信息存在内存里了,关闭程序再次打开信息就没有了。所以还得把信息存到硬盘上呀。

我们当然可以搞一些小手段把信息序列化存储在硬盘上,但好消息是unity提供了一个类ScriptableObject专门应对这种情况,可以参见unity官方参考的这一节. Unity也给了个视频教程.

需要注意的是,自己写一个继承ScriptableObject的类时,字段都需要是Serializable的,所以想直接存光照贴图有点困难,因为LightmapData[]没法序列化。也说不清定有方法把LightmapData序列化,笔者反正采用了把光照贴图的贴图存下来的方式。所以这个存信息的类如下:

这个类初始化的时候:
LightmapTransferHolder dataHolder = ScriptableObject.CreateInstance<LightmapTransferHolder>();

存储的时候:
AssetDatabase.CreateAsset(holder, pathname);

读取的时候:
LightmapTransferHolder holder = (LightmapTransferHolder) AssetDatabase.LoadAssetAtPath(pathname, typeof(LightmapTransferHolder));
就可以啦

3. 光照贴图读取

如果想让Prefab载入的时候就向场景里加载信息,需要加一个[ExecuteInEditMode]的属性,之后在重载一个Awake()函数,unity自动处理事件消息。
之后需要判断场景里是不是已经有了我们想加载的光照贴图,并对应上我们的光照贴图信息就好了。不要忘了销毁的时候删除使用的光照贴图,重载一个OnDestroy()函数。

以上基本就是要点,刚开始接触unity,请多指教。

发表评论

邮箱地址不会被公开。 必填项已用*标注