add VRM scripts

This commit is contained in:
ousttrue
2018-03-27 16:40:11 +09:00
parent 77b59c75d7
commit 2b34694ab3
158 changed files with 10771 additions and 0 deletions

View File

@@ -0,0 +1,200 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using UnityEditor;
using UnityEngine;
namespace VRM
{
[CustomPropertyDrawer(typeof(BoneMeshEraser.EraseBone))]
public class EraseBoneDrawer : PropertyDrawer
{
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
//EditorGUI.BeginProperty(position, label, property);
var leftWidth = 0.6f;
var rightWidth = 1.0f - leftWidth;
var leftSide = new Rect(position.x, position.y, position.width * leftWidth, position.height);
var rightSide = new Rect(position.width * leftWidth, position.y, position.width * rightWidth, position.height);
{
EditorGUI.PropertyField(leftSide, property.FindPropertyRelative("Bone"), new GUIContent("", ""));
EditorGUI.PropertyField(rightSide, property.FindPropertyRelative("Erase"));
}
//EditorGUI.EndProperty();
}
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
{
var height = base.GetPropertyHeight(property, label);
return height;
}
}
public class BoneMeshEraserWizard : ScriptableWizard
{
const string ASSET_SUFFIX = ".asset";
[SerializeField]
SkinnedMeshRenderer m_skinnedMesh;
[SerializeField]
Animator m_animator;
[SerializeField]
Transform EraseRoot;
[SerializeField]
BoneMeshEraser.EraseBone[] m_eraseBones;
[MenuItem("GameObject/UnityEditorScripts/BoneMeshEraser Wizard")]
static void CreateWizard()
{
ScriptableWizard.DisplayWizard<BoneMeshEraserWizard>("BoneMeshEraser", "Erase triangles by bone", "Erase");
}
private void OnEnable()
{
var root = Selection.activeGameObject;
if (root != null)
{
m_animator = root.GetComponent<Animator>();
m_skinnedMesh = root.GetComponent<SkinnedMeshRenderer>();
OnValidate();
}
}
void OnValidate()
{
//Debug.Log("OnValidate");
if (m_skinnedMesh == null)
{
m_eraseBones = new BoneMeshEraser.EraseBone[] { };
return;
}
if (EraseRoot == null)
{
if (m_animator != null)
{
EraseRoot = m_animator.GetBoneTransform(HumanBodyBones.Head);
//Debug.LogFormat("head: {0}", EraseRoot);
}
}
m_eraseBones = m_skinnedMesh.bones.Select(x =>
{
var eb = new BoneMeshEraser.EraseBone
{
Bone = x,
};
if (EraseRoot != null)
{
// 首の子孫を消去
if (eb.Bone.Ancestor().Any(y => y == EraseRoot))
{
//Debug.LogFormat("erase {0}", x);
eb.Erase = true;
}
}
return eb;
})
.ToArray();
}
void OnWizardUpdate()
{
helpString = "select target skinnedMesh and animator";
}
static int IndexOf(Transform[] list, Transform target)
{
for (int i = 0; i < list.Length; ++i)
{
if (list[i] == target)
{
return i;
}
}
return -1;
}
SkinnedMeshRenderer _Erase(GameObject go)
{
if (go == null)
{
Debug.LogWarning("select root object in hierarchy");
return null;
}
if (m_skinnedMesh == null)
{
Debug.LogWarning("no skinnedmesh");
return null;
}
var bones = m_skinnedMesh.bones;
var eraseBones = m_eraseBones
.Where(x => x.Erase)
.Select(x => bones.IndexOf(x.Bone))
.ToArray();
var meshNode = new GameObject("BoneMeshEraser");
meshNode.transform.SetParent(go.transform, false);
var erased = meshNode.AddComponent<SkinnedMeshRenderer>();
erased.sharedMesh = BoneMeshEraser.CreateErasedMesh(m_skinnedMesh.sharedMesh, eraseBones);
erased.sharedMaterials = m_skinnedMesh.sharedMaterials;
erased.bones = m_skinnedMesh.bones;
return erased;
}
void Erase()
{
var go = Selection.activeGameObject;
var renderer = _Erase(go);
if (renderer == null)
{
return;
}
// save mesh to Assets
var assetPath = string.Format("{0}{1}", go.name, ASSET_SUFFIX);
var prefab = PrefabUtility.GetPrefabParent(go);
if (prefab != null)
{
var prefabPath = AssetDatabase.GetAssetPath(prefab);
assetPath = string.Format("{0}/{1}{2}",
Path.GetDirectoryName(prefabPath),
Path.GetFileNameWithoutExtension(prefabPath),
ASSET_SUFFIX
);
}
Debug.LogFormat("CreateAsset: {0}", assetPath);
AssetDatabase.CreateAsset(renderer.sharedMesh, assetPath);
}
void OnWizardCreate()
{
//Debug.Log("OnWizardCreate");
Erase();
// close
}
void OnWizardOtherButton()
{
//Debug.Log("OnWizardOtherButton");
Erase();
}
}
}

View File

@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: 881b00db73f639c48a3f043a775fa61a
timeCreated: 1518503829
licenseType: Free
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,238 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using UniHumanoid;
using UnityEditor;
using UnityEngine;
namespace VRM
{
public static class BoneNormalizer
{
/// <summary>
/// 回転とスケールを除去したヒエラルキーをコピーする
/// </summary>
/// <param name="src"></param>
/// <param name="dst"></param>
static void CopyAndBuild(Transform src, Transform dst, Dictionary<Transform, Transform> boneMap)
{
boneMap[src] = dst;
foreach (Transform child in src)
{
var dstChild = new GameObject(child.name);
dstChild.transform.SetParent(dst);
dstChild.transform.position = child.position; // copy position only
//dstChild.AddComponent<UniHumanoid.BoneGizmoDrawer>();
CopyAndBuild(child, dstChild.transform, boneMap);
}
}
static IEnumerable<Transform> Traverse(this Transform t)
{
yield return t;
foreach (Transform child in t)
{
foreach (var x in child.Traverse())
{
yield return x;
}
}
}
public static GameObject Execute(GameObject go, Dictionary<Transform, Transform> boneMap)
{
//
// T-Poseにする
//
{
var animator = go.GetComponent<Animator>();
if (animator == null)
{
throw new ArgumentException("Animator with avatar is required");
}
var avatar = animator.avatar;
if (avatar == null)
{
throw new ArgumentException("avatar is required");
}
if (!avatar.isValid)
{
throw new ArgumentException("invalid avatar");
}
if (!avatar.isHuman)
{
throw new ArgumentException("avatar is not human");
}
HumanPoseTransfer.SetTPose(avatar, go.transform);
}
//
// 回転・スケールの無いヒエラルキーをコピーする
//
var normalized = new GameObject(go.name + "(normalized)");
normalized.transform.position = go.transform.position;
CopyAndBuild(go.transform, normalized.transform, boneMap);
//
// 新しいヒエラルキーからAvatarを作る
//
{
var src = go.GetComponent<Animator>();
var map = Enum.GetValues(typeof(HumanBodyBones))
.Cast<HumanBodyBones>()
.Where(x => x != HumanBodyBones.LastBone)
.Select(x => new { Key = x, Value = src.GetBoneTransform(x) })
.Where(x => x.Value != null)
.ToDictionary(x => x.Key, x => boneMap[x.Value])
;
var animator = normalized.AddComponent<Animator>();
var vrmHuman = go.GetComponent<VRMHumanoidDescription>();
var avatarDescription = AvatarDescription.Create();
if (vrmHuman != null && vrmHuman.Description != null)
{
avatarDescription.armStretch = vrmHuman.Description.armStretch;
avatarDescription.legStretch = vrmHuman.Description.legStretch;
avatarDescription.upperArmTwist = vrmHuman.Description.upperArmTwist;
avatarDescription.lowerArmTwist = vrmHuman.Description.lowerArmTwist;
avatarDescription.upperLegTwist = vrmHuman.Description.upperLegTwist;
avatarDescription.lowerLegTwist = vrmHuman.Description.lowerLegTwist;
avatarDescription.feetSpacing = vrmHuman.Description.feetSpacing;
avatarDescription.hasTranslationDoF = vrmHuman.Description.hasTranslationDoF;
}
avatarDescription.SetHumanBones(map);
var avatar = avatarDescription.CreateAvatar(normalized.transform);
avatar.name = go.name + ".normalized";
animator.avatar = avatar;
var humanPoseTransfer = normalized.AddComponent<HumanPoseTransfer>();
humanPoseTransfer.Avatar = avatar;
}
//
// 各メッシュから回転・スケールを取り除いてBinding行列を再計算する
//
foreach (var src in go.transform.Traverse())
{
var dst = boneMap[src];
{
//
// SkinnedMesh
//
var srcRenderer = src.GetComponent<SkinnedMeshRenderer>();
if (srcRenderer != null && srcRenderer.enabled)
{
var mesh = new Mesh();
var srcMesh = srcRenderer.sharedMesh;
mesh.name = srcMesh.name + ".baked";
srcRenderer.BakeMesh(mesh);
//var m = src.localToWorldMatrix;
var m = default(Matrix4x4);
m.SetTRS(Vector3.zero, src.rotation, Vector3.one);
mesh.vertices = mesh.vertices.Select(x => m.MultiplyPoint(x)).ToArray();
mesh.normals = mesh.normals.Select(x => m.MultiplyVector(x).normalized).ToArray();
mesh.uv = srcMesh.uv;
mesh.tangents = srcMesh.tangents;
mesh.subMeshCount = srcMesh.subMeshCount;
for (int i = 0; i < srcMesh.subMeshCount; ++i)
{
mesh.SetIndices(srcMesh.GetIndices(i), srcMesh.GetTopology(i), i);
}
mesh.boneWeights = srcMesh.boneWeights;
for (int i = 0; i < srcMesh.blendShapeCount; ++i)
{
var vertices = srcMesh.vertices;
var normals = srcMesh.normals;
var tangents = (srcMesh.tangents != null && srcMesh.tangents.Any())
? srcMesh.tangents.Select(x => (Vector3)x).ToArray()
: null
;
srcMesh.GetBlendShapeFrameVertices(i, 0, vertices, normals, tangents);
var name = srcMesh.GetBlendShapeName(i);
if (string.IsNullOrEmpty(name))
{
name = String.Format("{0}", i);
}
var s = src.lossyScale.x;
try
{
mesh.AddBlendShapeFrame(name,
srcMesh.GetBlendShapeFrameWeight(i, 0),
vertices.Select(x => m.MultiplyPoint(x) * s).ToArray(),
normals.Select(x => m.MultiplyVector(x).normalized).ToArray(),
tangents
);
}
catch (Exception)
{
Debug.LogWarningFormat("{0}.{1}", mesh.name, srcMesh.GetBlendShapeName(i));
throw;
}
}
// recalc bindposes
var bones = srcRenderer.bones.Select(x => boneMap[x]).ToArray();
mesh.bindposes = bones.Select(x =>
x.worldToLocalMatrix * dst.transform.localToWorldMatrix).ToArray();
mesh.RecalculateBounds();
var dstRenderer = dst.gameObject.AddComponent<SkinnedMeshRenderer>();
dstRenderer.sharedMaterials = srcRenderer.sharedMaterials;
dstRenderer.sharedMesh = mesh;
dstRenderer.bones = bones;
if (srcRenderer.rootBone != null)
{
dstRenderer.rootBone = boneMap[srcRenderer.rootBone];
}
if (!bones.Any() && srcRenderer.rootBone != null)
{
dstRenderer.rootBone = boneMap[srcRenderer.rootBone];
}
}
}
{
//
// not SkinnedMesh
//
var srcFilter = src.GetComponent<MeshFilter>();
if (srcFilter != null)
{
var srcRenderer = src.GetComponent<MeshRenderer>();
if (srcRenderer!=null && srcRenderer.enabled)
{
var dstFilter = dst.gameObject.AddComponent<MeshFilter>();
dstFilter.sharedMesh = srcFilter.sharedMesh;
var dstRenderer = dst.gameObject.AddComponent<MeshRenderer>();
dstRenderer.sharedMaterials = srcRenderer.sharedMaterials;
}
}
}
}
return normalized;
}
}
}

View File

@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: b330ec419f98af14687c302638922ab0
timeCreated: 1519379418
licenseType: Free
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,359 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using UnityEditor;
using UnityEngine;
namespace VRM
{
/// <summary>
/// 複数のメッシュをまとめる
/// </summary>
[DisallowMultipleComponent]
public static class MeshIntegrator
{
const string MENU_KEY = "GameObject/UnityEditorScripts/MeshIntegrator";
const int MENU_PRIORITY = 0;
const string ASSET_SUFFIX = ".mesh.asset";
const string ASSET_WITH_BLENDSHAPE_SUFFIX = ".blendshape.asset";
[MenuItem(MENU_KEY, true, MENU_PRIORITY)]
private static bool ExportValidate()
{
return Selection.activeObject != null && Selection.activeObject is GameObject;
}
[MenuItem(MENU_KEY, false, MENU_PRIORITY)]
private static void ExportFromMenu()
{
var go = Selection.activeObject as GameObject;
Integrate(go);
}
public static SkinnedMeshRenderer Integrate(GameObject go)
{
var without_blendshape = _Integrate(go, false);
if (without_blendshape == null)
{
return null;
}
// save mesh to Assets
var assetPath = string.Format("{0}{1}", go.name, ASSET_SUFFIX);
var prefab = PrefabUtility.GetPrefabParent(go);
if (prefab != null)
{
var prefabPath = AssetDatabase.GetAssetPath(prefab);
assetPath = string.Format("{0}/{1}{2}",
Path.GetDirectoryName(prefabPath),
Path.GetFileNameWithoutExtension(prefabPath),
ASSET_SUFFIX
);
}
Debug.LogFormat("CreateAsset: {0}", assetPath);
AssetDatabase.CreateAsset(without_blendshape.sharedMesh, assetPath);
return without_blendshape;
}
struct SubMesh
{
public List<int> Indices;
public Material Material;
}
class BlendShape
{
public int VertexOffset;
public string Name;
public float FrameWeight;
public Vector3[] Positions;
public Vector3[] Normals;
public Vector3[] Tangents;
}
class Integrator
{
public List<SkinnedMeshRenderer> Renderers { get; private set; }
public List<Vector3> Positions { get; private set; }
public List<Vector3> Normals { get; private set; }
public List<Vector2> UV { get; private set; }
public List<Vector4> Tangents { get; private set; }
public List<BoneWeight> BoneWeights { get; private set; }
public List<SubMesh> SubMeshes
{
get;
private set;
}
public List<Matrix4x4> BindPoses { get; private set; }
public List<Transform> Bones { get; private set; }
public List<BlendShape> BlendShapes { get; private set; }
public void AddBlendShapesToMesh(Mesh mesh)
{
Dictionary<string, BlendShape> map = new Dictionary<string, BlendShape>();
foreach (var x in BlendShapes)
{
BlendShape bs = null;
if (!map.TryGetValue(x.Name, out bs))
{
bs = new BlendShape();
bs.Positions = Positions.ToArray();
bs.Normals = Normals.ToArray();
bs.Tangents = Tangents.Select(y => (Vector3)y).ToArray();
bs.Name = x.Name;
bs.FrameWeight = x.FrameWeight;
map.Add(x.Name, bs);
}
var j = x.VertexOffset;
for (int i = 0; i < x.Positions.Length; ++i, ++j)
{
bs.Positions[j] = x.Positions[i];
bs.Normals[j] = x.Normals[i];
bs.Tangents[j] = x.Tangents[i];
}
}
foreach (var kv in map)
{
//Debug.LogFormat("AddBlendShapeFrame: {0}", kv.Key);
mesh.AddBlendShapeFrame(kv.Key, kv.Value.FrameWeight,
kv.Value.Positions, kv.Value.Normals, kv.Value.Tangents);
}
}
public Integrator()
{
Renderers = new List<SkinnedMeshRenderer>();
Positions = new List<Vector3>();
Normals = new List<Vector3>();
UV = new List<Vector2>();
Tangents = new List<Vector4>();
BoneWeights = new List<BoneWeight>();
SubMeshes = new List<SubMesh>();
BindPoses = new List<Matrix4x4>();
Bones = new List<Transform>();
BlendShapes = new List<BlendShape>();
}
static BoneWeight AddBoneIndexOffset(BoneWeight bw, int boneIndexOffset)
{
if (bw.weight0 > 0) bw.boneIndex0 += boneIndexOffset;
if (bw.weight1 > 0) bw.boneIndex1 += boneIndexOffset;
if (bw.weight2 > 0) bw.boneIndex2 += boneIndexOffset;
if (bw.weight3 > 0) bw.boneIndex3 += boneIndexOffset;
return bw;
}
public void Push(SkinnedMeshRenderer renderer)
{
var mesh = renderer.sharedMesh;
if (mesh == null)
{
Debug.LogWarningFormat("{0} has no mesh", renderer.name);
return;
}
Renderers.Add(renderer);
var indexOffset = Positions.Count;
var boneIndexOffset = Bones.Count;
Positions.AddRange(mesh.vertices);
Normals.AddRange(mesh.normals);
UV.AddRange(mesh.uv);
Tangents.AddRange(mesh.tangents);
if (mesh.vertexCount == mesh.boneWeights.Length)
{
BoneWeights.AddRange(mesh.boneWeights.Select(x => AddBoneIndexOffset(x, boneIndexOffset)).ToArray());
}
else
{
BoneWeights.AddRange(Enumerable.Range(0, mesh.vertexCount).Select(x => new BoneWeight()).ToArray());
}
BindPoses.AddRange(mesh.bindposes);
Bones.AddRange(renderer.bones);
for (int i = 0; i < mesh.subMeshCount; ++i)
{
var indices = mesh.GetIndices(i).Select(x => x + indexOffset);
var mat = renderer.sharedMaterials[i];
var sameMaterialSubMeshIndex = SubMeshes.FindIndex(x => ReferenceEquals(x.Material, mat));
if (sameMaterialSubMeshIndex >= 0)
{
SubMeshes[sameMaterialSubMeshIndex].Indices.AddRange(indices);
}
else
{
SubMeshes.Add(new SubMesh
{
Indices = indices.ToList(),
Material = mat,
});
}
}
for (int i = 0; i < mesh.blendShapeCount; ++i)
{
var positions = (Vector3[])mesh.vertices.Clone();
var normals = (Vector3[])mesh.normals.Clone();
var tangents = mesh.tangents.Select(x => (Vector3)x).ToArray();
mesh.GetBlendShapeFrameVertices(i, 0, positions, normals, tangents);
BlendShapes.Add(new BlendShape
{
VertexOffset = indexOffset,
FrameWeight = mesh.GetBlendShapeFrameWeight(i, 0),
Name = mesh.GetBlendShapeName(i),
Positions = positions,
Normals = normals,
Tangents = tangents,
});
}
}
}
static IEnumerable<Transform> Traverse(Transform parent)
{
if (parent.gameObject.activeSelf)
{
yield return parent;
foreach (Transform child in parent)
{
foreach (var x in Traverse(child))
{
yield return x;
}
}
}
}
static public IEnumerable<SkinnedMeshRenderer> EnumerateRenderer(Transform root, bool hasBlendShape)
{
foreach (var x in Traverse(root))
{
var renderer = x.GetComponent<SkinnedMeshRenderer>();
if (renderer != null)
{
if (renderer.sharedMesh != null)
{
if (renderer.gameObject.activeSelf)
{
if (renderer.sharedMesh.blendShapeCount > 0 == hasBlendShape)
{
yield return renderer;
}
}
}
}
}
}
static IEnumerable<Transform> Ancestors(Transform self)
{
yield return self;
if (self.parent != null)
{
foreach (var x in Ancestors(self.parent))
{
yield return x;
}
}
}
static SkinnedMeshRenderer _Integrate(GameObject go, bool hasBlendShape)
{
var meshNode = new GameObject();
if (hasBlendShape)
{
meshNode.name = "MeshIntegrator(BlendShape)";
}
else
{
meshNode.name = "MeshIntegrator";
}
meshNode.transform.SetParent(go.transform, false);
var renderers = EnumerateRenderer(go.transform, hasBlendShape).ToArray();
// Root objectを選出する
var root = renderers.Select(x => x.rootBone != null ? x.rootBone : x.transform)
.Select(x => Ancestors(x).Reverse().ToArray())
.Aggregate((a, b) =>
{
int i = 0;
for(; i<a.Length && i<b.Length; ++i)
{
if (a[i] != b[i])
{
break;
}
}
return a.Take(i).ToArray();
})
.Last()
;
Debug.LogFormat("root bone: {0}", root.name);
// レンダラから情報を集める
var integrator = new Integrator();
foreach(var x in renderers)
{
integrator.Push(x);
}
var mesh = new Mesh();
mesh.name = "integrated";
if (integrator.Positions.Count > ushort.MaxValue)
{
#if UNITY_2017_3_OR_NEWER
Debug.LogFormat("exceed 65535 vertices: {0}", integrator.Positions.Count);
mesh.indexFormat = UnityEngine.Rendering.IndexFormat.UInt32;
#else
throw new NotImplementedException(String.Format("exceed 65535 vertices: {0}", integrator.Positions.Count.ToString()));
#endif
}
mesh.vertices = integrator.Positions.ToArray();
mesh.normals = integrator.Normals.ToArray();
mesh.uv = integrator.UV.ToArray();
mesh.tangents = integrator.Tangents.ToArray();
mesh.boneWeights = integrator.BoneWeights.ToArray();
mesh.subMeshCount = integrator.SubMeshes.Count;
for (var i = 0; i < integrator.SubMeshes.Count; ++i)
{
mesh.SetIndices(integrator.SubMeshes[i].Indices.ToArray(), MeshTopology.Triangles, i);
}
mesh.bindposes = integrator.BindPoses.ToArray();
if (hasBlendShape)
{
integrator.AddBlendShapesToMesh(mesh);
}
var integrated = meshNode.AddComponent<SkinnedMeshRenderer>();
integrated.sharedMesh = mesh;
integrated.sharedMaterials = integrator.SubMeshes.Select(x => x.Material).ToArray();
integrated.bones = integrator.Bones.ToArray();
return integrated;
}
}
}

View File

@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: 648920943c26bde4b920119bdbb38f70
timeCreated: 1518194696
licenseType: Free
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,174 @@
#pragma warning disable 0414, 0649
using UnityEditor;
using UnityEngine;
using System.Linq;
using System;
using System.Collections.Generic;
namespace VRM
{
public class MeshIntegratorWizard : ScriptableWizard
{
[SerializeField]
GameObject m_root;
[SerializeField]
Material[] m_uniqueMaterials;
[Serializable]
struct MaterialKey
{
public string Shader;
public KeyValuePair<string, object>[] Properties;
public override bool Equals(object obj)
{
if(!(obj is MaterialKey))
{
return base.Equals(obj);
}
var key = (MaterialKey)obj;
return Shader == key.Shader
&& Properties.SequenceEqual(key.Properties)
;
}
public override int GetHashCode()
{
return base.GetHashCode();
}
}
[Serializable]
struct MaterialList
{
public Material[] Materials;
public MaterialList(Material[] list)
{
Materials = list;
}
}
[SerializeField]
MaterialList[] m_duplicateMaterials;
[Header("Result")]
public Mesh integrated;
[MenuItem("GameObject/UnityEditorScripts/MeshInregrator Wizard")]
static void CreateWizard()
{
ScriptableWizard.DisplayWizard<MeshIntegratorWizard>("MeshIntegrator", "Integrate and close window", "Integrate");
}
private void OnEnable()
{
m_root = Selection.activeGameObject;
OnValidate();
}
static object GetPropertyValue(Shader shader, int i, Material m)
{
var propType = ShaderUtil.GetPropertyType(shader, i);
switch (propType)
{
case ShaderUtil.ShaderPropertyType.Color:
return m.GetColor(ShaderUtil.GetPropertyName(shader, i));
case ShaderUtil.ShaderPropertyType.Range:
case ShaderUtil.ShaderPropertyType.Float:
return m.GetFloat(ShaderUtil.GetPropertyName(shader, i));
case ShaderUtil.ShaderPropertyType.Vector:
return m.GetVector(ShaderUtil.GetPropertyName(shader, i));
case ShaderUtil.ShaderPropertyType.TexEnv:
return m.GetTexture(ShaderUtil.GetPropertyName(shader, i));
default:
throw new NotImplementedException(propType.ToString());
}
}
static MaterialKey GetMaterialKey(Material m)
{
var key = new MaterialKey
{
Shader = m.shader.name,
};
key.Properties = Enumerable.Range(0, ShaderUtil.GetPropertyCount(m.shader))
.Select(x => new KeyValuePair<string, object>(
ShaderUtil.GetPropertyName(m.shader, x),
GetPropertyValue(m.shader, x, m))
)
.OrderBy(x => x.Key)
.ToArray()
;
return key;
}
void OnValidate()
{
Debug.Log("OnValidate");
if (m_root == null)
{
m_uniqueMaterials = new Material[] { };
m_duplicateMaterials = new MaterialList[] { };
return;
}
m_uniqueMaterials = MeshIntegrator.EnumerateRenderer(m_root.transform, false)
.SelectMany(x => x.sharedMaterials)
.Distinct()
.ToArray();
m_duplicateMaterials = m_uniqueMaterials
.GroupBy(x => GetMaterialKey(x), x => x)
.Select(x => new MaterialList(x.ToArray()))
.Where(x => x.Materials.Length > 1)
.ToArray()
;
}
void OnWizardUpdate()
{
helpString = "select target mesh root";
}
void Integrate()
{
if (m_root == null)
{
Debug.LogWarning("no root object");
return;
}
var renderer = MeshIntegrator.Integrate(m_root);
if (renderer == null)
{
return;
}
integrated = renderer.sharedMesh;
}
void OnWizardCreate()
{
Debug.Log("OnWizardCreate");
Integrate();
// close
}
void OnWizardOtherButton()
{
Debug.Log("OnWizardOtherButton");
Integrate();
}
}
}

View File

@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: 744f66c7013807b4cae1d38d2ecfff38
timeCreated: 1518503829
licenseType: Free
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: