Posted on
2016-08-17
2017-02-18
by
maajor
unity中光照贴图(lightmapping)的存储方式比较特殊,烘焙好的光照贴图存储在场景中,而参与烘焙的物体本身不记录光照贴图,只记录一组uv数据对应光照贴图。在显示的时候,shader通过这组uv坐标访问物体的光照贴图信息,再显示出来。 并且这些光照贴图没法用手动编辑,只能写脚本编辑。
而相对应的如果不在unity中烘焙,而在maya中烘焙,就是一张lightmapping放在shader的自发光贴图里面了。
所以问题在于,在unity中一个场景里烘焙的物体很难带着光照贴图放到另一个场景里。如果我们非要这么干,就得给被烘焙的Prefab加个脚本,记录光照贴图,在加入其它场景中重新加载光照贴图。
1. 光照贴图访问
首先是要访问一下Prefab里面所有子物体,从根节点遍历一下这个树就可以了,非常简单就不提了。
烘焙过的物体会有一个光照贴图的uv信息,以及所使用的光照贴图ID值。脚本中用物体的
Render
组件的
lightmapIndex
和
lightmapScaleOffset
属性访问,
lightmapScaleOffset
是
Vector4
类型,xyzw分别是Tiling X, Tiling Y, Offset X, Offset Y。比如:
LightmapData
这个类会存两个属性,
lightmapFar
和
lightmapNear
,类型是
texture2D
,也就是那张光照贴图了。
2. 贴图信息存储
我们要转移光照贴图先要记录光照贴图,信息记录在哪呢?首先想到直接存在脚本的类里,但是不可以,因为在物体放入新场景时会初始化这个脚本类,没法存下来。那么如果搞一个全局变量呢?或者一个静态类存储?这也不行,毕竟这样还是把信息存在内存里了,关闭程序再次打开信息就没有了。所以还得把信息存到硬盘上呀。
我们当然可以搞一些小手段把信息序列化存储在硬盘上,但好消息是unity提供了一个类
ScriptableObject
专门应对这种情况,可以参见
unity官方参考的这一节
. Unity也给了个
视频教程
.
需要注意的是,自己写一个继承
ScriptableObject
的类时,字段都需要是Serializable的,所以想直接存光照贴图有点困难,因为
LightmapData[]
没法序列化。也说不清定有方法把
LightmapData
序列化,笔者反正采用了把光照贴图的贴图存下来的方式。所以这个存信息的类如下:
public class LightmapTransferHolder : ScriptableObject {
public LightmapData[] lightmapdata;
public List<Texture2D> lightmapTex;
public List<LightmapPara> lightmapInfo;
[System.Serializable]
public class LightmapPara
public int index;
public Vector4 ScaleOffset;
1
2
3
4
5
6
7
8
9
10
11
12
13
public
class
LightmapTransferHolder
:
ScriptableObject
{
public
LightmapData
[
]
lightmapdata
;
public
List
&
lt
;
Texture2D
&
gt
;
lightmapTex
;
public
List
&
lt
;
LightmapPara
&
gt
;
lightmapInfo
;
}
[
System
.
Serializable
]
public
class
LightmapPara
{
public
int
index
;
public
Vector4
ScaleOffset
;
}
这个类初始化的时候:
LightmapTransferHolder dataHolder = ScriptableObject.CreateInstance<LightmapTransferHolder>();
存储的时候:
AssetDatabase.CreateAsset(holder, pathname);
读取的时候:
LightmapTransferHolder holder = (LightmapTransferHolder) AssetDatabase.LoadAssetAtPath(pathname, typeof(LightmapTransferHolder));
3. 光照贴图读取
如果想让Prefab载入的时候就向场景里加载信息,需要加一个
[ExecuteInEditMode]
的属性,之后在重载一个
Awake()
函数,unity自动处理事件消息。
之后需要判断场景里是不是已经有了我们想加载的光照贴图,并对应上我们的光照贴图信息就好了。不要忘了销毁的时候删除使用的光照贴图,重载一个
OnDestroy()
函数。
以上基本就是要点,刚开始接触unity,请多指教。
This entry was posted in
Blog
and tagged
GAME
,
Unity
. Bookmark the
permalink
.