无限大地图:lightmap拆分
来源:互联网 发布:centos 7.3 安装vftp 编辑:程序博客网 时间:2024/05/10 11:07
无缝地图涉及到地形、物件的分块加载,同样,lightmap也需要动态加载。而场景烘焙时,所有物件都是一起烘焙的,那怎么把某些物件指定烘焙到某一张lightmap贴图中?网上找了很久,也没有看到具体的实现方式,还是要自己从头造车,结合网上的一些理论,经过实践,分享2个方法
1. 设置自定义LightmapParameters,设置Bake tag,相同tag的物件,会烘焙到同一张lightmap中。Terrain_1_1是新创建的LightmapParameters,替换掉默认的Pamameters
2. 通过计算Renderer的uv,从完整Lightmap贴图中抠出来指定某个范围的贴图,然后与想要合并到一起的其他贴图生成一个新的lightmap贴图
第一个方法是最省事的,但是有一个问题,LightmapParameters看起来只有手动设置,Unity没有提供api,貌似不能用代码来实现自动化。那么只能使用黑科技了(反编译UnityEditor.dll得来的方法)
//创建LightmapParameters资源文件 public static void CreateLightmapParameterFile(string path, int bakeTag) { LightmapParameters lp = new LightmapParameters(); lp.bakedLightmapTag = bakeTag; AssetDatabase.CreateAsset(lp, path); AssetDatabase.ImportAsset(path); } public static void SetRenderLightmapParameters(Renderer renderer, string giparamsFile) { SerializedObject so = new SerializedObject(renderer); var sp = so.FindProperty("m_LightmapParameters"); sp.objectReferenceValue = AssetDatabase.LoadAssetAtPath(giparamsFile, typeof(LightmapParameters)); so.ApplyModifiedProperties(); }
重点在so.FindProperty("m_LightmapParameters");这是一个不对外的成员变量,通过反射来获取,然后设置objectReferenceValue ,关联之前创建的LightmapParameters文件。后面就简单了,自己实现吧
下面是第二个方法,Renderer里面有个变量lightmapScaleOffset,这个变量记录了光照uv的缩放和偏移量,通过计算可以得到该Renderer在lightmap完整贴图中的范围,然后就能扣出来
这里总结一下流程
a:通过uv2和Renderer的LightmapScaleOffset计算Lightmap贴图中的占用范围(bound)
b:抠图,打包图集,获得新的范围(bound)
c:已知新的bound和原始uv2,计算新的LightmapScaleOffset
//获取uv2 public static Vector2[] GetMeshUV2(Mesh m) { //如果不存在uv2,则使用uv代替 var uv2 = m.uv2; if (uv2 == null || uv2.Length == 0) uv2 = m.uv; return uv2; } //计算uv的范围 public static Vector4 GetBounds(Vector2[] uv, Renderer r) { if (uv != null) { var __uv = new Vector2[uv.Length]; Array.Copy(uv, __uv, uv.Length); uv = __uv; var minx = float.MaxValue; var miny = float.MaxValue; var maxx = float.MinValue; var maxy = float.MinValue; for (var _j = 0; _j < uv.Length; ++_j) { var _uv = uv[_j]; if (_uv.x < minx) { minx = _uv.x; } if (_uv.y < miny) { miny = _uv.y; } if (_uv.x > maxx) { maxx = _uv.x; } if (_uv.y > maxy) { maxy = _uv.y; } } var bounds = new Vector4(minx, miny, maxx, maxy); return bounds; } return Vector4.zero; }//通过与LightmapScaleOffset计算出原始uv范围对应Lightmap贴图中的范围 public static Vector4 CalcBoundWithLightmapScaleOffset(Vector4 sourceBounds, Vector4 lightmapScaleOffset) { var scaleBounds = new Vector4(sourceBounds.x * lightmapScaleOffset.x + lightmapScaleOffset.z, sourceBounds.y * lightmapScaleOffset.y + lightmapScaleOffset.w, sourceBounds.z * lightmapScaleOffset.x + lightmapScaleOffset.z, sourceBounds.w * lightmapScaleOffset.y + lightmapScaleOffset.w); return scaleBounds; }//这里就是扣图了public static Texture2D PickTexture(Texture2D sourceTex, Vector4 bounds) { var blockW = (int)((bounds.z - bounds.x) * sourceTex.width); var blockH = (int)((bounds.w - bounds.y) * sourceTex.height); int startX = (int)(bounds.x * sourceTex.width); int startY = (int)(bounds.y * sourceTex.height); //startY = (tex.height - startY - blockH); if (blockH == 0 || blockW == 0) return null; var colors = sourceTex.GetPixels(startX, startY, blockW, blockH); Texture2D tex2d = new Texture2D(blockW, blockH); tex2d.SetPixels(colors); tex2d.Apply(); return tex2d; }//从整lightmap贴图中扣指定物件的光照贴图 public static Texture2D PickLightmap(GameObject go, out Vector4 bound) { bound = Vector4.zero; if (go == null) return null; var meshFilter = go.GetComponent<MeshFilter>(); var renderer = go.GetComponent<Renderer>(); if (meshFilter == null || renderer == null) return null; var tex = GetFullLightmap(renderer); var uv2s = GetMeshUV2(meshFilter.sharedMesh); //var bounds = GetBounds(uv2s, renderer); var sourceBounds = LightMapUtil.GetBounds(uv2s, renderer); var scaleBounds = CalcBoundWithLightmapScaleOffset(sourceBounds, renderer.lightmapScaleOffset); bound = sourceBounds; return PickTexture(tex, scaleBounds); }
以上代码,重点是uv2和LightmapScaleOffset的计算,算出一个矩形范围。这里把图扣出来了,然后是把若果抠出来的图合并到一个新的Texture,要用到矩形排序算法,因为时间关系,这个算法我也没有深入了解,所以写了一个很简陋的算法,待优化
【本文由“科技有点”发布,2017年10月21日】
阅读全文
1 0
- 无限大地图:lightmap拆分
- 无限大地图:lightmap拆分
- Lightmap
- 3D游戏场景中 无限大地图 加载与效率优化思路
- Unity 场景分页插件 World Streamer 支持无限大地图的解决方案(一)
- Unity 场景分页插件 World Streamer 支持无限大地图的解决方案(二)
- LightMap 生成
- 制作lightMap
- lightmap Snapshot
- LightMap烘焙
- java Swing设置无限大
- 速度无限大的概念
- 拆分
- 无限大的两个整数相加
- 崑山科大跨院系 技转商机无限大
- 快速LightMap烘焙
- About Lightmap Baking
- 快速LightMap烘焙 .
- Zookeeper
- Java_Object_wait()、notify()、notifyAll()
- Sat Oct 21 17:54:29 CST 2017 There was an unexpected error (type=Not Found, status=404).
- 心得
- 写给自己的JAVA工程师之路-MySQL函数
- 无限大地图:lightmap拆分
- [参考]matlab数字滤波器设计函数一览
- 用callback增强链表模块来实现命令行菜单小程序V2.8
- 数字图像处理--形态学
- spfa算法
- dos开wifi
- 一次运维事故调查报告--cpu负载过高
- 人人都是架构师-读书笔记
- laravel常用扩展包