mirror of
https://github.com/vrm-c/UniVRM.git
synced 2026-08-28 13:54:45 -05:00
implement MaterialValueBinding
This commit is contained in:
@@ -17,9 +17,10 @@ namespace VRM
|
||||
{
|
||||
public String RelativePath;
|
||||
public int Index;
|
||||
public string ValueName; // _Color
|
||||
public float MinValue;
|
||||
public float MaxValue;
|
||||
public string ValueName;
|
||||
public Vector4 TargetValue;
|
||||
|
||||
public Vector4 BaseValue; // <- Get From RelativePath/Materials[Index][ValueName]
|
||||
}
|
||||
|
||||
[CreateAssetMenu(menuName = "VRM/BlendShapeClip")]
|
||||
@@ -66,8 +67,7 @@ namespace VRM
|
||||
if (sr != null)
|
||||
{
|
||||
var m = sr.sharedMaterials[x.Index];
|
||||
var color = m.GetColor(x.ValueName);
|
||||
color.a = x.MinValue + (x.MaxValue - x.MinValue) * value;
|
||||
var color = x.BaseValue + (x.TargetValue - x.BaseValue) * value;
|
||||
m.SetColor(x.ValueName, color);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ namespace VRM
|
||||
|
||||
if (m_prefab != null)
|
||||
{
|
||||
m_scene = PreviewSceneManager.GetOrCreate(m_prefab, m_target.Values);
|
||||
m_scene = PreviewSceneManager.GetOrCreate(m_prefab, m_target.Values, m_target.MaterialValues);
|
||||
if (m_scene != null)
|
||||
{
|
||||
m_scene.gameObject.SetActive(false);
|
||||
@@ -110,6 +110,7 @@ namespace VRM
|
||||
if (m_scene != null)
|
||||
{
|
||||
//Debug.LogFormat("OnDestroy");
|
||||
m_scene.Clean();
|
||||
GameObject.DestroyImmediate(m_scene.gameObject);
|
||||
m_scene = null;
|
||||
}
|
||||
@@ -138,7 +139,7 @@ namespace VRM
|
||||
|
||||
if (m_changed && m_scene!=null)
|
||||
{
|
||||
m_scene.Bake(m_target.Values);
|
||||
m_scene.Bake(m_target.Values, m_target.MaterialValues);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -214,7 +215,7 @@ namespace VRM
|
||||
return changed;
|
||||
}
|
||||
|
||||
public static int MaterialValueBindingHeight = 60;
|
||||
public static int MaterialValueBindingHeight = 90;
|
||||
public static bool DrawMaterialValueBinding(Rect position, SerializedProperty property,
|
||||
PreviewSceneManager scene)
|
||||
{
|
||||
@@ -233,20 +234,44 @@ namespace VRM
|
||||
|
||||
y += height;
|
||||
rect = new Rect(position.x, y, position.width, height);
|
||||
int blendShapeIndex;
|
||||
if (IntPopup(rect, property.FindPropertyRelative("Index"), scene.GetMaterialNames(pathIndex), out blendShapeIndex))
|
||||
int materialIndex;
|
||||
if (IntPopup(rect, property.FindPropertyRelative("Index"), scene.GetMaterialNames(pathIndex), out materialIndex))
|
||||
{
|
||||
changed = true;
|
||||
}
|
||||
|
||||
/*
|
||||
y += height;
|
||||
rect = new Rect(position.x, y, position.width, height);
|
||||
if (FloatSlider(rect, property.FindPropertyRelative("Weight"), 100))
|
||||
int propIndex;
|
||||
if (StringPopup(rect, property.FindPropertyRelative("ValueName"), scene.GetMaterialPropNames(pathIndex, materialIndex), out propIndex))
|
||||
{
|
||||
changed = true;
|
||||
}
|
||||
*/
|
||||
|
||||
if (propIndex >= 0)
|
||||
{
|
||||
var propTypes = scene.GetMaterialPropTypes(pathIndex, materialIndex);
|
||||
if (propTypes != null && propIndex < propTypes.Length)
|
||||
{
|
||||
switch (propTypes[propIndex])
|
||||
{
|
||||
case ShaderUtil.ShaderPropertyType.Color:
|
||||
{
|
||||
var baseValues= scene.GetMaterialPropBaseValues(pathIndex, materialIndex);
|
||||
property.FindPropertyRelative("BaseValue").vector4Value = baseValues[propIndex];
|
||||
|
||||
// max
|
||||
y += height;
|
||||
rect = new Rect(position.x, y, position.width, height);
|
||||
if (ColorProp(rect, property.FindPropertyRelative("TargetValue")))
|
||||
{
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
@@ -308,5 +333,19 @@ namespace VRM
|
||||
}
|
||||
}
|
||||
|
||||
static bool ColorProp(Rect rect, SerializedProperty prop)
|
||||
{
|
||||
var oldValue = (Color)prop.vector4Value;
|
||||
var newValue = EditorGUI.ColorField(rect, prop.displayName, oldValue);
|
||||
if (newValue != oldValue)
|
||||
{
|
||||
prop.vector4Value = newValue;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,15 @@
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
using UniGLTF;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
#endif
|
||||
|
||||
namespace VRM
|
||||
{
|
||||
[Serializable]
|
||||
public class MeshPreviewItem
|
||||
{
|
||||
public string Path
|
||||
@@ -25,11 +30,15 @@ namespace VRM
|
||||
private set;
|
||||
}
|
||||
|
||||
public int BlendShapeCount
|
||||
public string[] BlendShapeNames
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
public int BlendShapeCount
|
||||
{
|
||||
get { return BlendShapeNames.Length; }
|
||||
}
|
||||
|
||||
Material[] m_materials;
|
||||
public Material[] Materials
|
||||
@@ -38,14 +47,65 @@ namespace VRM
|
||||
private set
|
||||
{
|
||||
m_materials = value;
|
||||
m_MaterialNames = value.Select(x => x.name).ToArray();
|
||||
m_materialNames = value.Select(x => x.name).ToArray();
|
||||
|
||||
#if UNITY_EDITOR
|
||||
int i = 0;
|
||||
foreach (var x in value)
|
||||
{
|
||||
var propNames = Enumerable.Range(0, ShaderUtil.GetPropertyCount(x.shader))
|
||||
.Where(y => ShaderUtil.GetPropertyType(x.shader, y) == ShaderUtil.ShaderPropertyType.Color)
|
||||
.Select(y => ShaderUtil.GetPropertyName(x.shader, y))
|
||||
.ToArray();
|
||||
m_materialPropNamesList.Add(propNames);
|
||||
|
||||
var propTypes = Enumerable.Range(0, ShaderUtil.GetPropertyCount(x.shader))
|
||||
.Select(y => ShaderUtil.GetPropertyType(x.shader, y))
|
||||
.Where(y => y == ShaderUtil.ShaderPropertyType.Color)
|
||||
.ToArray();
|
||||
m_materialPropTypesList.Add(propTypes);
|
||||
|
||||
var propValues = propNames.Select(y => (Vector4)x.GetColor(y)).ToArray();
|
||||
m_materialPropDefaultValueList.Add(propValues);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
string[] m_MaterialNames;
|
||||
string[] m_materialNames;
|
||||
public string[] MaterialsNames
|
||||
{
|
||||
get { return m_MaterialNames; }
|
||||
get { return m_materialNames; }
|
||||
}
|
||||
|
||||
List<string[]> m_materialPropNamesList = new List<string[]>();
|
||||
public string[] GetMaterialPropNames(int materialIndex)
|
||||
{
|
||||
if(m_materialPropNamesList==null || materialIndex<0 || materialIndex >= m_materialPropNamesList.Count)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return m_materialPropNamesList[materialIndex];
|
||||
}
|
||||
|
||||
List<ShaderUtil.ShaderPropertyType[]> m_materialPropTypesList = new List<ShaderUtil.ShaderPropertyType[]>();
|
||||
public ShaderUtil.ShaderPropertyType[] GetMaterialPropTypes(int materialIndex)
|
||||
{
|
||||
if (m_materialPropTypesList == null || materialIndex < 0 || materialIndex >= m_materialPropTypesList.Count)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return m_materialPropTypesList[materialIndex];
|
||||
}
|
||||
|
||||
List<Vector4[]> m_materialPropDefaultValueList = new List<Vector4[]>();
|
||||
public Vector4[] GetMaterialPropBaseValues(int materialIndex)
|
||||
{
|
||||
if (m_materialPropDefaultValueList == null || materialIndex < 0 || materialIndex >= m_materialPropDefaultValueList.Count)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return m_materialPropDefaultValueList[materialIndex];
|
||||
}
|
||||
|
||||
Transform m_transform;
|
||||
@@ -64,7 +124,7 @@ namespace VRM
|
||||
m_transform = transform;
|
||||
}
|
||||
|
||||
public void Bake(BlendShapeBinding[] values)
|
||||
public void Bake(BlendShapeBinding[] values, MaterialValueBinding[] materialValues)
|
||||
{
|
||||
if (SkinnedMeshRenderer == null) return;
|
||||
|
||||
@@ -84,16 +144,50 @@ namespace VRM
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (materialValues != null)
|
||||
{
|
||||
// clear
|
||||
for (int i = 0; i < Materials.Length; ++i)
|
||||
{
|
||||
var names = m_materialPropNamesList[i];
|
||||
var defaultValues = m_materialPropDefaultValueList[i];
|
||||
for (int j = 0; j < names.Length; ++j)
|
||||
{
|
||||
Materials[i].SetColor(names[j], defaultValues[j]);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var x in materialValues)
|
||||
{
|
||||
if(x.RelativePath == Path)
|
||||
{
|
||||
var material = Materials[x.Index];
|
||||
material.SetColor(x.ValueName, x.TargetValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SkinnedMeshRenderer.BakeMesh(Mesh);
|
||||
}
|
||||
|
||||
public static MeshPreviewItem Create(Transform t, Transform root)
|
||||
public void Clean()
|
||||
{
|
||||
foreach (var x in Materials)
|
||||
{
|
||||
UnityEngine.Object.DestroyImmediate(x);
|
||||
}
|
||||
}
|
||||
|
||||
public static MeshPreviewItem Create(Transform t, Transform root, Func<Material, Material> getOrCreateMaterial)
|
||||
{
|
||||
var meshFilter = t.GetComponent<MeshFilter>();
|
||||
var meshRenderer = t.GetComponent<MeshRenderer>();
|
||||
var skinnedMeshRenderer = t.GetComponent<SkinnedMeshRenderer>();
|
||||
if (meshFilter != null && meshRenderer != null)
|
||||
{
|
||||
// copy
|
||||
meshRenderer.sharedMaterials = meshRenderer.sharedMaterials.Select(x => getOrCreateMaterial(x)).ToArray();
|
||||
return new MeshPreviewItem(t.RelativePathFrom(root), t)
|
||||
{
|
||||
Mesh = meshFilter.sharedMesh,
|
||||
@@ -102,14 +196,17 @@ namespace VRM
|
||||
}
|
||||
else if (skinnedMeshRenderer != null)
|
||||
{
|
||||
// copy
|
||||
skinnedMeshRenderer.sharedMaterials = skinnedMeshRenderer.sharedMaterials.Select(x => getOrCreateMaterial(x)).ToArray();
|
||||
if (skinnedMeshRenderer.sharedMesh.blendShapeCount > 0)
|
||||
{
|
||||
// bake required
|
||||
var sharedMesh = skinnedMeshRenderer.sharedMesh;
|
||||
return new MeshPreviewItem(t.RelativePathFrom(root), t)
|
||||
{
|
||||
SkinnedMeshRenderer = skinnedMeshRenderer,
|
||||
Mesh = new Mesh(), // for bake
|
||||
BlendShapeCount = skinnedMeshRenderer.sharedMesh.blendShapeCount,
|
||||
BlendShapeNames = Enumerable.Range(0, sharedMesh.blendShapeCount).Select(x => sharedMesh.GetBlendShapeName(x)).ToArray(),
|
||||
Materials = skinnedMeshRenderer.sharedMaterials
|
||||
};
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace VRM
|
||||
public GameObject Prefab;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
public static PreviewSceneManager GetOrCreate(GameObject prefab, BlendShapeBinding[] values)
|
||||
public static PreviewSceneManager GetOrCreate(GameObject prefab, BlendShapeBinding[] values, MaterialValueBinding[] materialValues)
|
||||
{
|
||||
if (prefab == null)
|
||||
{
|
||||
@@ -50,7 +50,7 @@ namespace VRM
|
||||
);
|
||||
go.name = "__PREVIEW_SCENE_MANGER__";
|
||||
manager = go.AddComponent<PreviewSceneManager>();
|
||||
manager.Initialize(prefab, values);
|
||||
manager.Initialize(prefab, values, materialValues);
|
||||
|
||||
// HideFlags are special editor-only settings that let you have *secret* GameObjects in a scene, or to tell Unity not to save that temporary GameObject as part of the scene
|
||||
go.hideFlags |= HideFlags.DontSaveInEditor;
|
||||
@@ -66,7 +66,15 @@ namespace VRM
|
||||
}
|
||||
#endif
|
||||
|
||||
private void Initialize(GameObject prefab, BlendShapeBinding[] values)
|
||||
public void Clean()
|
||||
{
|
||||
foreach(var x in m_meshes)
|
||||
{
|
||||
x.Clean();
|
||||
}
|
||||
}
|
||||
|
||||
private void Initialize(GameObject prefab, BlendShapeBinding[] values, MaterialValueBinding[] materialValues)
|
||||
{
|
||||
Prefab = prefab;
|
||||
|
||||
@@ -81,23 +89,29 @@ namespace VRM
|
||||
}
|
||||
*/
|
||||
|
||||
var map = new Dictionary<Material, Material>();
|
||||
Func<Material, Material> getOrCreateMaterial = src =>
|
||||
{
|
||||
Material dst;
|
||||
if(!map.TryGetValue(src, out dst))
|
||||
{
|
||||
dst = new Material(src);
|
||||
map.Add(src, dst);
|
||||
}
|
||||
return dst;
|
||||
};
|
||||
|
||||
m_meshes = transform.Traverse()
|
||||
.Select(x => MeshPreviewItem.Create(x, transform))
|
||||
.Select(x => MeshPreviewItem.Create(x, transform, getOrCreateMaterial))
|
||||
.Where(x => x != null)
|
||||
.ToArray()
|
||||
;
|
||||
m_blendShapeMeshes = m_meshes
|
||||
.Where(x => x.SkinnedMeshRenderer != null
|
||||
&& x.SkinnedMeshRenderer.sharedMesh.blendShapeCount>0)
|
||||
.ToArray();
|
||||
|
||||
foreach(var x in m_meshes)
|
||||
{
|
||||
if (x.SkinnedMeshRenderer != null)
|
||||
{
|
||||
var mesh = x.SkinnedMeshRenderer.sharedMesh;
|
||||
m_blendShapeNameMap.Add(m_blendShapeNameMap.Count,
|
||||
Enumerable.Range(0, mesh.blendShapeCount).Select(y => mesh.GetBlendShapeName(y)).ToArray());
|
||||
}
|
||||
}
|
||||
|
||||
Bake(values);
|
||||
Bake(values, materialValues);
|
||||
|
||||
m_rendererPathList = m_meshes.Select(x => x.Path).ToArray();
|
||||
m_skinnedMeshRendererPathList = m_meshes
|
||||
@@ -107,6 +121,7 @@ namespace VRM
|
||||
}
|
||||
|
||||
MeshPreviewItem[] m_meshes;
|
||||
MeshPreviewItem[] m_blendShapeMeshes;
|
||||
public IEnumerable<MeshPreviewItem> EnumRenderItems
|
||||
{
|
||||
get
|
||||
@@ -133,14 +148,14 @@ namespace VRM
|
||||
get { return m_skinnedMeshRendererPathList; }
|
||||
}
|
||||
|
||||
Dictionary<int, string[]> m_blendShapeNameMap = new Dictionary<int, string[]>();
|
||||
public string[] GetBlendShapeNames(int skinnedMeshIndex)
|
||||
public string[] GetBlendShapeNames(int blendShapeMeshIndex)
|
||||
{
|
||||
string[] names = null;
|
||||
if(m_blendShapeNameMap.TryGetValue(skinnedMeshIndex, out names))
|
||||
if (blendShapeMeshIndex >= 0 && blendShapeMeshIndex < m_blendShapeMeshes.Length)
|
||||
{
|
||||
return names;
|
||||
var item = m_blendShapeMeshes[blendShapeMeshIndex];
|
||||
return item.BlendShapeNames;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -153,8 +168,53 @@ namespace VRM
|
||||
return null;
|
||||
}
|
||||
|
||||
public string[] GetMaterialPropNames(int rendererIndex, int materialIndex)
|
||||
{
|
||||
if(rendererIndex<0 || rendererIndex >= m_meshes.Length)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if(materialIndex<0 || materialIndex >= m_meshes[rendererIndex].MaterialsNames.Length)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return m_meshes[rendererIndex].GetMaterialPropNames(materialIndex);
|
||||
}
|
||||
|
||||
public ShaderUtil.ShaderPropertyType[] GetMaterialPropTypes(int rendererIndex, int materialIndex)
|
||||
{
|
||||
if (rendererIndex < 0 || rendererIndex >= m_meshes.Length)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (materialIndex < 0 || materialIndex >= m_meshes[rendererIndex].MaterialsNames.Length)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return m_meshes[rendererIndex].GetMaterialPropTypes(materialIndex);
|
||||
}
|
||||
|
||||
public Vector4[] GetMaterialPropBaseValues(int rendererIndex, int materialIndex)
|
||||
{
|
||||
if (rendererIndex < 0 || rendererIndex >= m_meshes.Length)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (materialIndex < 0 || materialIndex >= m_meshes[rendererIndex].MaterialsNames.Length)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return m_meshes[rendererIndex].GetMaterialPropBaseValues(materialIndex);
|
||||
}
|
||||
|
||||
Bounds m_bounds;
|
||||
public void Bake(BlendShapeBinding[] values)
|
||||
public void Bake(BlendShapeBinding[] values, MaterialValueBinding[] materialValues)
|
||||
{
|
||||
//Debug.LogFormat("Bake");
|
||||
m_bounds = default(Bounds);
|
||||
@@ -162,7 +222,7 @@ namespace VRM
|
||||
{
|
||||
foreach (var x in m_meshes)
|
||||
{
|
||||
x.Bake(values);
|
||||
x.Bake(values, materialValues);
|
||||
m_bounds.Expand(x.Mesh.bounds.size);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user