unsafe static void _RepackLightmap()
    {
        var gos      = Selection.gameObjects;
        var checkMSG = false;

REOPEN:
        if (gos.Length == 0)
        {
            UDebug.LogError("Please select a GameObject in hierarchy to process!");
            return;
        }
        var hierarchy = UnityUtils.GetHierarchyPath(gos[0].transform);

        if (!checkMSG)
        {
            checkMSG = true;
            if (!EditorUtility.DisplayDialog(Title, "请确认:处理的是原始场景,如果已经处理过,请重新加载场景。", "直接整", "好吧,重新加载场景"))
            {
                UnityEditor.SceneManagement.EditorSceneManager.OpenScene(currentScene);
                gos = new GameObject[] { GameObject.Find(hierarchy) };
                goto REOPEN;
            }
        }
        // 经过测试,这个值确实是输出到了最终lightmap纹理中纹理单位的间隔
        var    Padding = LightmapEditorSettings.padding;
        Bounds bounds;
        var    workingPath  = CleanTempFolder();
        var    allRenderers = CollectAllLightmapedRenderers(gos, out bounds).Values.ToList();
        // 把搜集到的原始Mesh重新保存成asset格式,便于后面的修改(FBX无法修改)
        var meshes = new Dictionary <Mesh, Mesh>();

        for (int i = 0; i < allRenderers.Count; ++i)
        {
            var ri      = allRenderers[i];
            var srcMesh = ri.mesh;
            if (!srcMesh.isReadable)
            {
                UDebug.LogError("Mesh \"{0}\" is not readable!");
                continue;
            }
            var mf = ri.renderer.transform.GetComponent <MeshFilter>();
            if (mf == null)
            {
                continue;
            }
            Mesh dstMesh = null;
            if (!meshes.TryGetValue(srcMesh, out dstMesh))
            {
                var assetPath = String.Format("{0}/{1}_{2}.mesh.asset", workingPath, srcMesh.name, meshes.Count);
                if (File.Exists(assetPath))
                {
                    AssetDatabase.DeleteAsset(assetPath);
                }
                AssetDatabase.CreateAsset(UnityEngine.Object.Instantiate <Mesh>(srcMesh), assetPath);
                dstMesh = AssetDatabase.LoadAssetAtPath <Mesh>(assetPath);
                meshes.Add(srcMesh, dstMesh);
            }
            //覆盖原始模型
            mf.sharedMesh = dstMesh;
        }
        if (meshes.Count > 0)
        {
            var litmapData = LoadAllLightmapData();
            if (litmapData == null)
            {
                UDebug.LogError("Load source lightmaps failed.");
                return;
            }
            var inputRects           = new List <NativeAPI.stbrp_rect>();
            var all_atlas_pixels     = new Dictionary <int, AtlasPixelsPage>();
            var lightmapRectInfoList = new List <LightmapRect>();
            using (var tp = new TexturePacker()) {
                for (int i = 0; i < allRenderers.Count; ++i)
                {
                    var ri            = allRenderers[i];
                    var r             = ri.renderer;
                    var uv2BoundsInfo = GetMeshUV2Bounds(r);
                    int lightmapIndex = uv2BoundsInfo.lightmapIndex;
                    if (lightmapIndex >= 0 && lightmapIndex < litmapData.Count)
                    {
                        var lightmapData      = litmapData[r.lightmapIndex];
                        var meshUVBounds      = uv2BoundsInfo.srcUVBounds;
                        var lightmapUVBounds  = uv2BoundsInfo.lightmapUVBounds;
                        var _lightmapUVBounds = lightmapUVBounds;

                        // 当前发现有些美术自己展开的UV有超过01现象,尝试自己模拟一下Repeat采样纹理坐标的计算
                        _lightmapUVBounds.x = MathLib.ClampRepeatUV(_lightmapUVBounds.x);
                        _lightmapUVBounds.y = MathLib.ClampRepeatUV(_lightmapUVBounds.y);
                        _lightmapUVBounds.z = MathLib.ClampRepeatUV(_lightmapUVBounds.z);
                        _lightmapUVBounds.w = MathLib.ClampRepeatUV(_lightmapUVBounds.w);

                        // 防止包围盒上下左右颠倒,重新翻转一下
                        if (_lightmapUVBounds.x > _lightmapUVBounds.z)
                        {
                            var temp = _lightmapUVBounds.x;
                            _lightmapUVBounds.x = _lightmapUVBounds.z;
                            _lightmapUVBounds.z = temp;
                        }
                        if (_lightmapUVBounds.y > _lightmapUVBounds.w)
                        {
                            var temp = _lightmapUVBounds.y;
                            _lightmapUVBounds.y = _lightmapUVBounds.w;
                            _lightmapUVBounds.w = temp;
                        }

                        // 纹理坐标到像素坐标转换,此处代码查看了网上流传出来unity4.3里面源码
                        var i_minx   = Mathf.FloorToInt(_lightmapUVBounds.x * ( float )lightmapData.width);
                        var i_miny   = Mathf.FloorToInt(_lightmapUVBounds.y * ( float )lightmapData.height);
                        var i_width  = Mathf.CeilToInt((_lightmapUVBounds.z - _lightmapUVBounds.x) * ( float )lightmapData.width);
                        var i_height = Mathf.CeilToInt((_lightmapUVBounds.w - _lightmapUVBounds.y) * ( float )lightmapData.height);

                        if (i_width <= 0 || i_height <= 0)
                        {
                            UDebug.LogError("Invalid LightmapUV: {0}", UnityUtils.GetHierarchyPath(r.transform));
                            continue;
                        }
                        var i_maxx = i_minx + i_width;
                        var i_maxy = i_miny + i_height;
                        i_minx = Mathf.Clamp(i_minx, 0, lightmapData.width);
                        i_maxx = Mathf.Clamp(i_maxx, 0, lightmapData.width);
                        i_miny = Mathf.Clamp(i_miny, 0, lightmapData.height);
                        i_maxy = Mathf.Clamp(i_maxy, 0, lightmapData.height);

                        // 传入自己的TexturePacker之前,把border大小加上去
                        var rt = default(NativeAPI.stbrp_rect);
                        rt.w = ( ushort )(i_width + Padding);
                        rt.h = ( ushort )(i_height + Padding);

                        var lightmapRect = new LightmapRect();
                        lightmapRect.renderer            = r;
                        lightmapRect.lightmapUVBounds    = lightmapUVBounds;
                        lightmapRect.meshUVBounds        = meshUVBounds;
                        lightmapRect.lightmapPixelBounds = new Vector4(i_minx, i_miny, i_maxx, i_maxy);
                        rt.id = lightmapRectInfoList.Count;
                        inputRects.Add(rt);
                        lightmapRectInfoList.Add(lightmapRect);
                    }
                }
                tp.PackRects(inputRects.ToArray());
                tp.ForEach(
                    (page, atlasSize, rt) => {
                    var lightmapRect = lightmapRectInfoList[rt.id];
                    var renderer     = lightmapRect.renderer;
                    var lightmapData = litmapData[renderer.lightmapIndex];
                    AtlasPixelsPage atlas_pixels;
                    if (!all_atlas_pixels.TryGetValue(page, out atlas_pixels))
                    {
                        atlas_pixels = new AtlasPixelsPage {
                            pixels = new Vector4[atlasSize * atlasSize],
                            size   = atlasSize
                        };
                        all_atlas_pixels.Add(page, atlas_pixels);
                    }
                    int i_minx = ( int )lightmapRect.lightmapPixelBounds.x;
                    int i_miny = ( int )lightmapRect.lightmapPixelBounds.y;
                    int i_maxx = ( int )lightmapRect.lightmapPixelBounds.z;
                    int i_maxy = ( int )lightmapRect.lightmapPixelBounds.w;

                    // lightmap像素块copy
                    fixed(Vector4 * _atlas_pixels = atlas_pixels.pixels)
                    {
                        for (int y = i_miny; y < i_maxy; y++)
                        {
                            int dy = y - i_miny + rt.y;
                            // 纹理坐标需要翻转一下,像素是翻转了的
                            int _dy        = atlasSize - 1 - dy;
                            int _sy        = lightmapData.height - 1 - y;
                            int _dy_stride = _dy * atlasSize;
                            int _sy_stride = _sy * lightmapData.width;
                            for (int x = i_minx; x < i_maxx; x++)
                            {
                                int dx = x - i_minx + rt.x;
                                _atlas_pixels[_dy_stride + dx] = lightmapData.pixels[_sy_stride + x];
                            }
                        }
                    }
                    // 计算在新的lightmap纹理下的纹理坐标包围盒,由于pack之前我们认为加了一个Padding,所以这里计算要减去
                    // 这里估计会有各种影藏的因素导致最终效果和原始效果出现偏差,黑边,偏移,防缩等
                    // 因为在复制像素的时候,包围盒因取整引入了误差,这里为了防止出现黑边,我人为的往里缩小了0.5
                    Vector4 uvBounds;
                    uvBounds.x = ( float )(rt.x + 0.5f) / ( float )atlasSize;
                    uvBounds.y = ( float )(rt.y + 0.5f) / ( float )atlasSize;
                    uvBounds.z = ( float )((rt.x + rt.w) - Padding - 0.5f) / ( float )atlasSize;
                    uvBounds.w = ( float )((rt.y + rt.h) - Padding - 0.5f) / ( float )atlasSize;
                    if (Mathf.Approximately(lightmapRect.meshUVBounds.z, lightmapRect.meshUVBounds.x) ||
                        Mathf.Approximately(lightmapRect.meshUVBounds.w, lightmapRect.meshUVBounds.y))
                    {
                        // 无效
                        renderer.lightmapIndex       = -1;
                        renderer.lightmapScaleOffset = new Vector4(1, 1, 0, 0);
                        UDebug.LogError("Invalid LightmapUV's bounds: {0}", UnityUtils.GetHierarchyPath(lightmapRect.renderer.transform));
                    }
                    else
                    {
                        // 计算新的ScaleOffset,映射到新的lightmap纹理
                        renderer.lightmapIndex       = page;
                        renderer.lightmapScaleOffset = MathLib.CalculateUVScaleOffset(lightmapRect.meshUVBounds, uvBounds);
                    }
                }
                    );
                if (all_atlas_pixels.Count > 0)
                {
                    var lightmapOutputPath = workingPath;
                    var lightmaps          = new LightmapData[all_atlas_pixels.Count];
                    var lightmapPathList   = new List <KeyValuePair <String, int> >(all_atlas_pixels.Count);
                    int pageIndex          = 0;
                    foreach (var pagePixels in all_atlas_pixels)
                    {
                        fixed(Vector4 *_atlas_pixels = pagePixels.Value.pixels)
                        {
                            EditorUtility.DisplayProgressBar(Title, "Saving lightmap atlas...", ( float )pageIndex / ( float )all_atlas_pixels.Count);
                            pageIndex++;
                            int atlasSize = pagePixels.Value.size;
                            var path      = String.Format("{0}/lightmap_{1}.exr", lightmapOutputPath, pagePixels.Key);

                            if (File.Exists(path))
                            {
                                AssetDatabase.DeleteAsset(path);
                            }
                            NativeAPI.SaveEXR(( IntPtr )_atlas_pixels, atlasSize, atlasSize, 4, 0, path);
                            lightmapPathList.Add(new KeyValuePair <String, int>(path, pagePixels.Key));
                        }
                    }
                    try {
                        AssetDatabase.Refresh();
                        pageIndex = 0;
                        for (int j = 0; j < lightmapPathList.Count; j++)
                        {
                            var path = lightmapPathList[j].Key;
                            var page = lightmapPathList[j].Value;
                            EditorUtility.DisplayProgressBar(Title, "Apply lightmap atlas...", ( float )pageIndex / ( float )all_atlas_pixels.Count);
                            pageIndex++;
                            var ti = AssetImporter.GetAtPath(path) as TextureImporter;
                            if (ti != null)
                            {
                                if (ti.textureType != TextureImporterType.Lightmap || ti.isReadable || ti.wrapMode != TextureWrapMode.Clamp)
                                {
                                    ti.textureType = TextureImporterType.Lightmap;
                                    ti.isReadable  = false;
                                    ti.wrapMode    = TextureWrapMode.Clamp;
                                    AssetDatabase.ImportAsset(ti.assetPath);
                                }
                                var tex = AssetDatabase.LoadAssetAtPath(path, typeof(Texture2D)) as Texture2D;
                                if (tex != null)
                                {
                                    lightmaps[page] = new LightmapData();
                                    lightmaps[page].lightmapLight = tex;
                                }
                            }
                        }
                    } finally {
                        LightmapSettings.lightmaps = lightmaps;
                    }
                }
            }
        }
    }