Created
October 11, 2019 12:28
-
-
Save gatosyocora/4886ca95364bd4f8d2c58c434a5bec07 to your computer and use it in GitHub Desktop.
Unityアプリで任意の場所にあるmatファイルをランタイムロードするプログラム(暫定なのでエラー処理とか書いてないです)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.Collections; | |
using System.Collections.Generic; | |
using UnityEngine; | |
using System.Windows.Forms; | |
using System.IO; | |
using YamlDotNet; | |
using YamlDotNet.RepresentationModel; | |
using System.Text.RegularExpressions; | |
// Copyright (c) 2019 gatosyocora | |
// Released under the MIT license | |
// https://opensource.org/licenses/MIT | |
// Use YamlDotNet for Unity | |
public class RuntimeMaterialLoader : MonoBehaviour { | |
private Dictionary<string, string> guid2PathDict; | |
/// <summary> | |
/// マテリアルファイルを読み込む | |
/// </summary> | |
public void LoadMaterialFile() | |
{ | |
string filePath = ChooseFile(); | |
// シェーダーファイルのランタイムロードはつらいのでとりあえずUnlit/Texture | |
Material mat = new Material(Shader.Find("Unlit/Texture")); | |
/// guidリストをつくるための開始フォルダを決めるために取得 | |
var rootFolderPath = GetRootFolderPath(filePath, "Assets"); | |
guid2PathDict = GetPairGuidAndFilePath(rootFolderPath); | |
var yaml = new YamlStream(); | |
using (var file = new StreamReader(filePath, System.Text.Encoding.UTF8)) | |
{ | |
yaml.Load(file); | |
} | |
var mapping = (YamlMappingNode)yaml.Documents[0].RootNode; | |
var materialInfo = (YamlMappingNode)mapping.Children["Material"]; | |
var properties = (YamlMappingNode)materialInfo["m_SavedProperties"]; | |
mat.name = ((YamlScalarNode)materialInfo["m_Name"]).Value; | |
// テクスチャ情報 | |
var textures = (YamlSequenceNode)properties["m_TexEnvs"]; | |
foreach (YamlMappingNode texture in textures) | |
{ | |
foreach (var child in texture) | |
{ | |
var key = ((YamlScalarNode)child.Key).Value; | |
var values = (YamlMappingNode)child.Value; | |
var tex = (YamlMappingNode)values["m_Texture"]; | |
var scale = (YamlMappingNode)values["m_Scale"]; | |
var offset = (YamlMappingNode)values["m_Offset"]; | |
var texID = ((YamlScalarNode)tex["fileID"]).Value; | |
// guidのキーが含まれているかどうか | |
foreach (var k in tex) | |
{ | |
if (((YamlScalarNode)k.Key).Value == "guid") | |
{ | |
string texGuid = ((YamlScalarNode)tex["guid"]).Value; | |
Texture2D texture2d = LoadTextureWithGuid(texGuid); | |
mat.SetTexture(key, texture2d); | |
mat.SetTextureScale( | |
key, | |
new Vector2( | |
float.Parse(((YamlScalarNode)scale["x"]).Value), | |
float.Parse(((YamlScalarNode)scale["y"]).Value) | |
) | |
); | |
mat.SetTextureOffset( | |
key, | |
new Vector2( | |
float.Parse(((YamlScalarNode)offset["x"]).Value), | |
float.Parse(((YamlScalarNode)offset["y"]).Value) | |
) | |
); | |
} | |
} | |
// Debug.LogFormat("{0}, {1}", key, texID); | |
} | |
} | |
// float情報 | |
var floats = (YamlSequenceNode)properties["m_Floats"]; | |
foreach (YamlMappingNode f in floats) | |
{ | |
foreach (var child in f) | |
{ | |
var key = ((YamlScalarNode)child.Key).Value; | |
var value = ((YamlScalarNode)child.Value).Value; | |
// Debug.LogFormat("{0}, {1}", key, value); | |
mat.SetFloat(key, float.Parse(value)); | |
} | |
} | |
// 色情報 | |
var colors = (YamlSequenceNode)properties["m_Colors"]; | |
foreach (YamlMappingNode color in colors) | |
{ | |
foreach (var child in color) | |
{ | |
var key = ((YamlScalarNode)child.Key).Value; | |
var value = (YamlMappingNode)child.Value; | |
var r = float.Parse(((YamlScalarNode)value["r"]).Value); | |
var g = float.Parse(((YamlScalarNode)value["g"]).Value); | |
var b = float.Parse(((YamlScalarNode)value["b"]).Value); | |
var a = float.Parse(((YamlScalarNode)value["a"]).Value); | |
// Debug.LogFormat("{0}, ({1}, {2}, {3}, {4})", key, r, g, b, a); | |
mat.SetColor(key, new Color(r, g, b, a)); | |
} | |
} | |
var renderer = this.gameObject.GetComponent<MeshRenderer>(); | |
renderer.sharedMaterial = mat; | |
} | |
/// <summary> | |
/// ダイアログを表示してファイルを選択する | |
/// </summary> | |
/// <returns></returns> | |
private string ChooseFile() | |
{ | |
OpenFileDialog ofd = new OpenFileDialog(); | |
ofd.FileName = "default.html"; | |
ofd.InitialDirectory = @"C:\"; | |
ofd.Title = "開くファイルを選択してください"; | |
ofd.RestoreDirectory = true; | |
//ダイアログを表示する | |
if (ofd.ShowDialog() == DialogResult.OK) | |
{ | |
return ofd.FileName; | |
} | |
else | |
{ | |
return ""; | |
} | |
} | |
/// <summary> | |
/// guidを使ってテクスチャを読み込む | |
/// </summary> | |
/// <param name="guid"></param> | |
/// <returns></returns> | |
private Texture2D LoadTextureWithGuid(string guid) | |
{ | |
Texture2D texture = null; | |
string path = GetFilePathFromGuid(guid); | |
if (File.Exists(path)) | |
{ | |
var fs = new FileStream(path, FileMode.Open, FileAccess.Read); | |
var reader = new BinaryReader(fs); | |
var binary = reader.ReadBytes((int)reader.BaseStream.Length); | |
reader.Close(); | |
fs.Dispose(); | |
fs = null; | |
texture = new Texture2D(0, 0); | |
texture.LoadImage(binary); | |
binary = null; | |
} | |
return texture; | |
} | |
/// <summary> | |
/// guidからファイルパスへ変換する | |
/// </summary> | |
/// <param name="guid"></param> | |
/// <returns></returns> | |
private string GetFilePathFromGuid(string guid) | |
{ | |
if (guid2PathDict == null) | |
return ""; | |
string value = ""; | |
if (guid2PathDict.TryGetValue(guid, out value)) | |
{ | |
return value; | |
} | |
else | |
{ | |
return ""; | |
} | |
} | |
//TODO pngに対応したmetaファイルだけ取得とかできそう | |
/// <summary> | |
/// guidとファイルパスのセットを取得する | |
/// </summary> | |
/// <param name="rootFolderPath"></param> | |
/// <returns></returns> | |
private Dictionary<string, string> GetPairGuidAndFilePath(string rootFolderPath) | |
{ | |
var dict = new Dictionary<string, string>(); | |
var info = new DirectoryInfo(rootFolderPath); | |
var files = info.GetFiles("*.meta", SearchOption.AllDirectories); | |
foreach (var f in files) | |
{ | |
var yaml = new YamlStream(); | |
using (var file = new StreamReader(f.FullName, System.Text.Encoding.UTF8)) | |
{ | |
yaml.Load(file); | |
} | |
var mapping = (YamlMappingNode)yaml.Documents[0].RootNode; | |
var guid = ((YamlScalarNode)mapping["guid"]).Value; | |
dict.Add(guid, new Regex(".meta").Replace(f.FullName, "")); | |
} | |
return dict; | |
} | |
/// <summary> | |
/// ルートフォルダのパスを取得する | |
/// </summary> | |
/// <param name="filePath"></param> | |
/// <param name="rootFolderName"></param> | |
/// <returns></returns> | |
private string GetRootFolderPath(string filePath, string rootFolderName) | |
{ | |
var regex = new Regex(rootFolderName + ".*"); | |
var path = regex.Replace(filePath, ""); | |
return path + rootFolderName; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment