Skip to content

Instantly share code, notes, and snippets.

@chigirits
Last active July 5, 2020 12:55
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save chigirits/e7f1a1d734511dbc9ec9db1a585b01d5 to your computer and use it in GitHub Desktop.
Save chigirits/e7f1a1d734511dbc9ec9db1a585b01d5 to your computer and use it in GitHub Desktop.
Unity 2019用のアセットを2018にダウングレードしたらメッシュやマテリアルの参照が切れてしまう場合に復元するツール(無保証・Undo不可・バックアップをお取りの上ご自身の責任でご利用ください) 詳細: https://twitter.com/chigiri_vrc/status/1279759484085104640
// MeshRendererFixer
// (C) 2020 Chigiri Tsutsumi
// MIT License
//
// Unity 2019用のアセットを2018にダウングレードしたらメッシュやマテリアルの
// 参照が切れてしまう場合に、元の参照状態を復元するツールです。
// Assets/Chigiri/Editor/ というフォルダを作成し、その中に配置してください。
//
// 使い方
// 1. 2019でシーンを開いて
// 「メニュー/Chigiri/MeshRendererFixer/Export MeshRenderer Settings」
// →状態をファイルとして保存
// 2. 2018へのダウングレード後に同シーン(変更を加えないこと)を開いて
// 「メニュー/Chigiri/MeshRendererFixer/Import MeshRenderer Settings」
// → 先ほど保存したファイルを選択すると復元されます。
//
// シーン内のオブジェクトが対象ですので、プレハブの内容は復元されないことに注意してください。
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using System.IO;
using UnityEngine.SceneManagement;
public class MeshRendererFixer : MonoBehaviour
{
[Serializable]
public class MeshFilterData
{
public string o;
public string a;
public string n;
}
[Serializable]
public class MaterialData
{
public string a;
public string n;
}
[Serializable]
public class MeshRendererData
{
public string o;
public MaterialData[] m;
}
[Serializable]
public class Data
{
public MeshFilterData[] meshFilters;
public MeshRendererData[] meshRenderers;
}
static string FullPath(Transform t)
{
var result = "";
while (t != null)
{
result = "/" + t.gameObject.name + result;
t = t.parent;
}
return result;
}
static T LoadAsset<T>(string path, string name) where T : UnityEngine.Object
{
foreach (var asset in AssetDatabase.LoadAllAssetsAtPath(path))
{
if (asset is T && asset.name == name)
{
return asset as T;
}
}
return null;
}
[MenuItem("Chigiri/MeshRendererFixer/Export MeshRenderer Settings", false, 1)]
static void ExportMeshRendererSettings(MenuCommand command)
{
var filterData = new List<MeshFilterData>();
foreach (var filter in Resources.FindObjectsOfTypeAll<MeshFilter>())
{
if (!filter.gameObject.activeInHierarchy)
{
continue;
}
var objPath = FullPath(filter.transform);
if (filter.sharedMesh == null)
{
Debug.Log(objPath + ": No mesh is assigned");
continue;
}
var assetPath = AssetDatabase.GetAssetPath(filter.sharedMesh);
if (assetPath == "")
{
Debug.Log(objPath + ": Cannot resolve asset path");
continue;
}
if (!assetPath.StartsWith("Assets/"))
{
continue;
}
filterData.Add(new MeshFilterData { o = objPath, a = assetPath, n = filter.sharedMesh.name });
}
var rendererData = new List<MeshRendererData>();
foreach (var renderer in Resources.FindObjectsOfTypeAll<MeshRenderer>())
{
if (!renderer.gameObject.activeInHierarchy)
{
continue;
}
var objPath = FullPath(renderer.transform);
var materialData = new List<MaterialData>();
foreach (var mat in renderer.sharedMaterials)
{
var assetPath = AssetDatabase.GetAssetPath(mat);
var d = new MaterialData();
d.n = mat.name;
materialData.Add(d);
if (assetPath == "")
{
Debug.Log(objPath + ": Cannot resolve asset path");
continue;
}
if (!assetPath.StartsWith("Assets/"))
{
continue;
}
d.a = assetPath;
}
rendererData.Add(new MeshRendererData { o = objPath, m = materialData.ToArray() });
}
var data = new Data
{
meshFilters = filterData.ToArray(),
meshRenderers = rendererData.ToArray()
};
var json = JsonUtility.ToJson(data);
var saveName = SceneManager.GetActiveScene().name + ".MeshRendererFixer.json";
var savePath = EditorUtility.SaveFilePanel("Export MeshRenderer Settings", "", saveName, "json");
if (savePath != "")
{
File.WriteAllBytes(savePath, System.Text.Encoding.UTF8.GetBytes(json));
}
}
[MenuItem("Chigiri/MeshRendererFixer/Import MeshRenderer Settings", false, 1)]
static void ImportMeshRendererSettings(MenuCommand command)
{
var loadPath = EditorUtility.OpenFilePanel("Import MeshRenderer Settings", "", "json");
if (loadPath == "")
{
return;
}
var json = File.ReadAllText(loadPath);
var data = JsonUtility.FromJson<Data>(json);
foreach (var d in data.meshFilters)
{
var obj = GameObject.Find(d.o);
if (obj == null)
{
Debug.Log("GameObject not found: " + d.o);
continue;
}
var filter = obj.GetComponent<MeshFilter>();
if (filter == null)
{
Debug.Log("MeshFilter not found: " + d.o);
continue;
}
var mesh = LoadAsset<Mesh>(d.a, d.n);
if (mesh == null)
{
Debug.Log("Mesh not found: " + d.a + " > " + d.n);
continue;
}
filter.sharedMesh = mesh;
}
foreach (var d in data.meshRenderers)
{
var obj = GameObject.Find(d.o);
if (obj == null)
{
Debug.Log("GameObject not found: " + d.o);
continue;
}
var renderer = obj.GetComponent<MeshRenderer>();
if (renderer == null)
{
Debug.Log("MeshRenderer not found: " + d.o);
continue;
}
if (renderer.sharedMaterials.Length != d.m.Length)
{
Debug.Log("sharedMaterials length mismatch: " + d.o);
continue;
}
var newMats = new Material[d.m.Length];
for (var i = 0; i < d.m.Length; i++)
{
newMats[i] = renderer.sharedMaterials[i];
var m = d.m[i];
if (m.a == "")
{
continue;
}
var mat = LoadAsset<Material>(m.a, m.n);
if (mat == null)
{
Debug.Log("Material not found: " + m.a + " > " + m.n);
continue;
}
newMats[i] = mat;
}
renderer.sharedMaterials = newMats;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment