mirror of
https://github.com/vrm-c/UniVRM.git
synced 2026-08-26 21:04:14 -05:00
impl importer, exporter and editor
This commit is contained in:
@@ -99,6 +99,21 @@ namespace UniVRM10
|
||||
}
|
||||
}
|
||||
|
||||
public static bool Vec3Prop(Rect rect, SerializedProperty prop)
|
||||
{
|
||||
var oldValue = prop.vector3Value;
|
||||
var newValue = EditorGUI.Vector3Field(rect, prop.displayName, oldValue);
|
||||
if (newValue != oldValue)
|
||||
{
|
||||
prop.vector3Value = newValue;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static Rect AdvanceRect(ref float x, float y, float w, float h)
|
||||
{
|
||||
var rect = new Rect(x, y, w, h);
|
||||
|
||||
@@ -110,6 +110,10 @@ namespace UniVRM10
|
||||
int subMeshCount = item.Mesh.subMeshCount;
|
||||
for (int i = 0; i < subMeshCount; i++)
|
||||
{
|
||||
if (item.SkinnedMeshRenderer != null)
|
||||
{
|
||||
item.SkinnedMeshRenderer.BakeMesh(item.Mesh);
|
||||
}
|
||||
m_previewUtility.DrawMesh(item.Mesh,
|
||||
item.Position, item.Rotation,
|
||||
item.Materials[i], i);
|
||||
|
||||
@@ -0,0 +1,131 @@
|
||||
using System;
|
||||
using UnityEditor;
|
||||
using UnityEditorInternal;
|
||||
using UnityEngine;
|
||||
|
||||
|
||||
namespace UniVRM10
|
||||
{
|
||||
public class ReorderableNodeTransformBindingList
|
||||
{
|
||||
ReorderableList m_ValuesList;
|
||||
SerializedProperty m_valuesProp;
|
||||
bool m_changed;
|
||||
|
||||
public ReorderableNodeTransformBindingList(SerializedObject serializedObject, PreviewSceneManager previewSceneManager, int height)
|
||||
{
|
||||
m_valuesProp = serializedObject.FindProperty(nameof(VRM10Expression.NodeTransformBindings));
|
||||
m_ValuesList = new ReorderableList(serializedObject, m_valuesProp);
|
||||
m_ValuesList.elementHeight = height * 4;
|
||||
m_ValuesList.drawElementCallback =
|
||||
(rect, index, isActive, isFocused) =>
|
||||
{
|
||||
var element = m_valuesProp.GetArrayElementAtIndex(index);
|
||||
rect.height -= 4;
|
||||
rect.y += 2;
|
||||
if (DrawNodeTransformBinding(rect, element, previewSceneManager, height))
|
||||
{
|
||||
m_changed = true;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
///
|
||||
/// NodeTransform List のElement描画
|
||||
///
|
||||
static bool DrawNodeTransformBinding(Rect position, SerializedProperty property,
|
||||
PreviewSceneManager scene, int height)
|
||||
{
|
||||
bool changed = false;
|
||||
if (scene != null)
|
||||
{
|
||||
var y = position.y;
|
||||
var rect = new Rect(position.x, y, position.width, height);
|
||||
int pathIndex;
|
||||
if (ExpressionEditorHelper.StringPopup(rect, property.FindPropertyRelative(nameof(NodeTransformBinding.RelativePath)), scene.NodeTransformPathList, out pathIndex))
|
||||
{
|
||||
changed = true;
|
||||
}
|
||||
|
||||
// T`
|
||||
y += height;
|
||||
rect = new Rect(position.x, y, position.width, height);
|
||||
if (ExpressionEditorHelper.Vec3Prop(rect, property.FindPropertyRelative(nameof(NodeTransformBinding.OffsetTranslation))))
|
||||
{
|
||||
changed = true;
|
||||
}
|
||||
|
||||
// R
|
||||
y += height;
|
||||
rect = new Rect(position.x, y, position.width, height);
|
||||
if (EditorGUI.PropertyField(rect, property.FindPropertyRelative(nameof(NodeTransformBinding.OffsetRotation))))
|
||||
{
|
||||
changed = true;
|
||||
}
|
||||
|
||||
// S
|
||||
y += height;
|
||||
rect = new Rect(position.x, y, position.width, height);
|
||||
if (ExpressionEditorHelper.Vec3Prop(rect, property.FindPropertyRelative(nameof(NodeTransformBinding.TargetScale))))
|
||||
{
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
public void SetValues(NodeTransformBinding[] bindings)
|
||||
{
|
||||
m_valuesProp.ClearArray();
|
||||
m_valuesProp.arraySize = bindings.Length;
|
||||
for (int i = 0; i < bindings.Length; ++i)
|
||||
{
|
||||
var item = m_valuesProp.GetArrayElementAtIndex(i);
|
||||
|
||||
var endProperty = item.GetEndProperty();
|
||||
while (item.NextVisible(true))
|
||||
{
|
||||
if (SerializedProperty.EqualContents(item, endProperty))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
switch (item.name)
|
||||
{
|
||||
case nameof(NodeTransformBinding.RelativePath):
|
||||
item.stringValue = bindings[i].RelativePath;
|
||||
break;
|
||||
|
||||
case nameof(NodeTransformBinding.OffsetTranslation):
|
||||
item.vector3Value = bindings[i].OffsetTranslation;
|
||||
break;
|
||||
|
||||
case nameof(NodeTransformBinding.OffsetRotation):
|
||||
item.quaternionValue = bindings[i].OffsetRotation;
|
||||
break;
|
||||
|
||||
case nameof(NodeTransformBinding.TargetScale):
|
||||
item.vector3Value = bindings[i].TargetScale;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new Exception();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public bool Draw(string label)
|
||||
{
|
||||
m_changed = false;
|
||||
m_ValuesList.DoLayoutList();
|
||||
if (GUILayout.Button($"Clear {label}"))
|
||||
{
|
||||
m_changed = true;
|
||||
m_valuesProp.arraySize = 0;
|
||||
}
|
||||
return m_changed;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1520687d88c34af4eb8c16bb37ee0391
|
||||
guid: 186e6dd105c86904497f3ac0dfd61212
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
@@ -1,3 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEditor;
|
||||
@@ -28,21 +29,24 @@ namespace UniVRM10
|
||||
ReorderableMorphTargetBindingList m_morphTargetBindings;
|
||||
ReorderableMaterialColorBindingList m_materialColorBindings;
|
||||
ReorderableMaterialUVBindingList m_materialUVBindings;
|
||||
|
||||
ReorderableNodeTransformBindingList m_nodeTransformBindings;
|
||||
#region Editor values
|
||||
|
||||
bool m_changed;
|
||||
|
||||
static int s_Mode;
|
||||
static bool s_MorphTargetFoldout = true;
|
||||
static bool s_OptionFoldout;
|
||||
static bool s_ListFoldout;
|
||||
|
||||
static string[] MODES = new[]{
|
||||
"MorphTarget",
|
||||
"Material Color",
|
||||
"Texture Transform"
|
||||
};
|
||||
enum ListMode
|
||||
{
|
||||
MorphTarget,
|
||||
MaterialColor,
|
||||
TextureTransform,
|
||||
NodeTransform,
|
||||
}
|
||||
static ListMode s_Mode;
|
||||
static string[] MODES = ((ListMode[])Enum.GetValues(typeof(ListMode))).Select(x => x.ToString()).ToArray();
|
||||
|
||||
PreviewMeshItem[] m_items;
|
||||
#endregion
|
||||
@@ -71,6 +75,7 @@ namespace UniVRM10
|
||||
m_morphTargetBindings = new ReorderableMorphTargetBindingList(serializedObject, previewSceneManager, 20);
|
||||
m_materialColorBindings = new ReorderableMaterialColorBindingList(serializedObject, previewSceneManager?.MaterialNames, 20);
|
||||
m_materialUVBindings = new ReorderableMaterialUVBindingList(serializedObject, previewSceneManager?.MaterialNames, 20);
|
||||
m_nodeTransformBindings = new ReorderableNodeTransformBindingList(serializedObject, previewSceneManager, 20);
|
||||
|
||||
m_items = previewSceneManager.EnumRenderItems
|
||||
.Where(x => x.SkinnedMeshRenderer != null)
|
||||
@@ -109,33 +114,39 @@ namespace UniVRM10
|
||||
if (s_ListFoldout)
|
||||
{
|
||||
EditorGUI.indentLevel++;
|
||||
s_Mode = GUILayout.Toolbar(s_Mode, MODES);
|
||||
s_Mode = (ListMode)GUILayout.Toolbar((int)s_Mode, MODES);
|
||||
switch (s_Mode)
|
||||
{
|
||||
case 0:
|
||||
// MorphTarget
|
||||
case ListMode.MorphTarget:
|
||||
{
|
||||
if (m_morphTargetBindings.Draw("MorphTarget"))
|
||||
if (m_morphTargetBindings.Draw(s_Mode.ToString()))
|
||||
{
|
||||
m_changed = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 1:
|
||||
// Material
|
||||
case ListMode.MaterialColor:
|
||||
{
|
||||
if (m_materialColorBindings.Draw("MaterialColor"))
|
||||
if (m_materialColorBindings.Draw(s_Mode.ToString()))
|
||||
{
|
||||
m_changed = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 2:
|
||||
// TextureTransform
|
||||
case ListMode.TextureTransform:
|
||||
{
|
||||
if (m_materialUVBindings.Draw("TextureTransform"))
|
||||
if (m_materialUVBindings.Draw(s_Mode.ToString()))
|
||||
{
|
||||
m_changed = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case ListMode.NodeTransform:
|
||||
{
|
||||
if (m_nodeTransformBindings.Draw(s_Mode.ToString()))
|
||||
{
|
||||
m_changed = true;
|
||||
}
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using UniGLTF;
|
||||
using UniGLTF.Utils;
|
||||
using UnityEngine;
|
||||
|
||||
|
||||
namespace UniVRM10
|
||||
{
|
||||
internal sealed class BoneTransformBindingMerger
|
||||
{
|
||||
Dictionary<ExpressionKey, float> _acum = new();
|
||||
// Vrm10BoneTransformExpression[] _expressions;
|
||||
Transform _root;
|
||||
|
||||
public BoneTransformBindingMerger(Transform root)
|
||||
{
|
||||
// _expressions = root.GetComponentsInChildren<Vrm10BoneTransformExpression>();
|
||||
_root = root;
|
||||
}
|
||||
|
||||
public void AccumulateValue(ExpressionKey key, float value)
|
||||
{
|
||||
_acum[key] = value;
|
||||
}
|
||||
|
||||
public void Apply(IReadOnlyDictionary<Transform, TransformState> initPose)
|
||||
{
|
||||
foreach (var expression in _root.GetComponentsInChildren<Vrm10BoneTransformExpression>())
|
||||
{
|
||||
if (initPose.TryGetValue(expression.transform, out var init))
|
||||
{
|
||||
var weight = _acum.GetValueOrDefault(expression.Expression.ExpressionKey, 0);
|
||||
expression.transform.SetLocalPositionAndRotation(
|
||||
init.LocalPosition + expression.Expression.Translation * weight,
|
||||
Quaternion.Slerp(init.LocalRotation, init.LocalRotation * expression.Expression.Rotation, weight)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -24,10 +24,13 @@ namespace UniVRM10
|
||||
|
||||
MorphTargetBindingMerger m_morphTargetBindingMerger;
|
||||
MaterialValueBindingMerger m_materialValueBindingMerger;
|
||||
BoneTransformBindingMerger m_boneTransformBindingMerger;
|
||||
NodeTransformBindingMerger m_boneTransformBindingMerger;
|
||||
|
||||
|
||||
public ExpressionMerger(VRM10ObjectExpression expressions, Transform root, bool isPrefabInstance)
|
||||
public ExpressionMerger(VRM10ObjectExpression expressions,
|
||||
Transform root,
|
||||
bool isPrefabInstance,
|
||||
IReadOnlyDictionary<Transform, TransformState> initPose)
|
||||
{
|
||||
m_clipMap = expressions.Clips.ToDictionary(
|
||||
x => expressions.CreateKey(x.Clip),
|
||||
@@ -37,14 +40,14 @@ namespace UniVRM10
|
||||
m_valueMap = new Dictionary<ExpressionKey, float>(ExpressionKey.Comparer);
|
||||
m_morphTargetBindingMerger = new MorphTargetBindingMerger(m_clipMap, root);
|
||||
m_materialValueBindingMerger = new MaterialValueBindingMerger(m_clipMap, root, isPrefabInstance);
|
||||
m_boneTransformBindingMerger = new BoneTransformBindingMerger(root);
|
||||
m_boneTransformBindingMerger = new NodeTransformBindingMerger(m_clipMap, root, initPose);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// まとめて反映する。1フレームに1回呼び出されることを想定
|
||||
/// </summary>
|
||||
/// <param name="expressionWeights"></param>
|
||||
public void SetValues(Dictionary<ExpressionKey, float> expressionWeights, IReadOnlyDictionary<Transform, TransformState> initPose)
|
||||
public void SetValues(Dictionary<ExpressionKey, float> expressionWeights)
|
||||
{
|
||||
foreach (var (key, weight) in expressionWeights)
|
||||
{
|
||||
@@ -53,7 +56,7 @@ namespace UniVRM10
|
||||
|
||||
m_morphTargetBindingMerger.Apply();
|
||||
m_materialValueBindingMerger.Apply();
|
||||
m_boneTransformBindingMerger.Apply(initPose);
|
||||
m_boneTransformBindingMerger.Apply();
|
||||
}
|
||||
|
||||
private void AccumulateValue(ExpressionKey key, float value)
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
using System.Collections.Generic;
|
||||
using UniGLTF.Utils;
|
||||
using UnityEngine;
|
||||
|
||||
|
||||
namespace UniVRM10
|
||||
{
|
||||
internal sealed class NodeTransformBindingMerger
|
||||
{
|
||||
IReadOnlyDictionary<ExpressionKey, VRM10Expression> _clipMap;
|
||||
Transform _root;
|
||||
IReadOnlyDictionary<Transform, TransformState> _initPose;
|
||||
Dictionary<ExpressionKey, float> _weightMap = new();
|
||||
|
||||
public NodeTransformBindingMerger(
|
||||
IReadOnlyDictionary<ExpressionKey, VRM10Expression> clipMap,
|
||||
Transform root,
|
||||
IReadOnlyDictionary<Transform, TransformState> initPose)
|
||||
{
|
||||
_clipMap = clipMap;
|
||||
_root = root;
|
||||
_initPose = initPose;
|
||||
}
|
||||
|
||||
public void AccumulateValue(ExpressionKey key, float value)
|
||||
{
|
||||
_weightMap[key] = value;
|
||||
}
|
||||
|
||||
public void Apply()
|
||||
{
|
||||
foreach (var (k, weight) in _weightMap)
|
||||
{
|
||||
if (_clipMap.TryGetValue(k, out var clip))
|
||||
{
|
||||
foreach (var b in clip.NodeTransformBindings)
|
||||
{
|
||||
var node = _root.GetFromPath(b.RelativePath);
|
||||
if (node != null)
|
||||
{
|
||||
if (_initPose.TryGetValue(node, out var init))
|
||||
{
|
||||
b.Apply(node, init, weight);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
using System;
|
||||
using UniGLTF.Utils;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UniVRM10
|
||||
{
|
||||
[Serializable]
|
||||
public struct NodeTransformBinding
|
||||
{
|
||||
public string RelativePath;
|
||||
|
||||
/// <summary>
|
||||
/// t = init_t + offset_t * weight
|
||||
/// disable if offset_t = (0, 0, 0)
|
||||
/// </summary>
|
||||
public Vector3 OffsetTranslation;
|
||||
|
||||
/// <summary>
|
||||
/// r = slerp(init_t, init_t * offset r, weight)
|
||||
/// disable if rotation_t = (0, 0, 0, 1)
|
||||
/// </summary>
|
||||
public Quaternion OffsetRotation;
|
||||
|
||||
/// <summary>
|
||||
/// s = lerp(init_s, blend_s, weight)
|
||||
/// disalbe if blend_s = init_s. maybe(1, 1, 1)
|
||||
/// </summary>
|
||||
public Vector3 TargetScale;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="path"></param>
|
||||
/// <param name="index"></param>
|
||||
/// <param name="weight">0 to 1.0</param>
|
||||
public NodeTransformBinding(string path, in Vector3 t, in Quaternion r, in Vector3 s)
|
||||
{
|
||||
RelativePath = path;
|
||||
OffsetTranslation = t;
|
||||
OffsetRotation = r;
|
||||
TargetScale = s;
|
||||
}
|
||||
|
||||
public void Apply(Transform node, in TransformState init, float weight)
|
||||
{
|
||||
node.SetLocalPositionAndRotation(
|
||||
init.LocalPosition + this.OffsetTranslation * weight,
|
||||
Quaternion.Slerp(init.LocalRotation, init.LocalRotation * this.OffsetRotation, weight)
|
||||
);
|
||||
node.localScale = Vector3.Lerp(init.LocalScale, this.TargetScale, weight);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: dd660f7a77373234c85064f97150eef6
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -3,6 +3,7 @@ using System.Linq;
|
||||
using UnityEngine;
|
||||
using System;
|
||||
using UniGLTF;
|
||||
using UniGLTF.Utils;
|
||||
|
||||
|
||||
namespace UniVRM10
|
||||
@@ -16,6 +17,8 @@ namespace UniVRM10
|
||||
|
||||
public bool hasError;
|
||||
|
||||
private IReadOnlyDictionary<Transform, TransformState> m_defaultTransformStates;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
public static PreviewSceneManager GetOrCreate(GameObject prefab)
|
||||
{
|
||||
@@ -85,7 +88,7 @@ namespace UniVRM10
|
||||
private void Initialize(GameObject prefab)
|
||||
{
|
||||
hasError = false;
|
||||
|
||||
|
||||
Prefab = prefab;
|
||||
|
||||
var materialNames = new List<string>();
|
||||
@@ -104,14 +107,14 @@ namespace UniVRM10
|
||||
{
|
||||
dst = new Material(src);
|
||||
map.Add(src, dst);
|
||||
|
||||
|
||||
if (!PreviewMaterialUtil.TryCreateForPreview(dst, out var previewMaterialItem))
|
||||
{
|
||||
hasError = true;
|
||||
// Return cloned material for preview
|
||||
return dst;
|
||||
}
|
||||
|
||||
|
||||
m_materialMap.Add(src.name, previewMaterialItem);
|
||||
|
||||
materialNames.Add(src.name);
|
||||
@@ -119,6 +122,10 @@ namespace UniVRM10
|
||||
return dst;
|
||||
};
|
||||
|
||||
// initPose for nodeTransform
|
||||
m_defaultTransformStates = transform.GetComponentsInChildren<Transform>()
|
||||
.ToDictionary(tf => tf, tf => new TransformState(tf));
|
||||
|
||||
m_meshes = transform.Traverse()
|
||||
.Select(x => PreviewMeshItem.Create(x, transform, getOrCreateMaterial))
|
||||
.Where(x => x != null)
|
||||
@@ -136,8 +143,13 @@ namespace UniVRM10
|
||||
.Where(x => x.SkinnedMeshRenderer != null)
|
||||
.Select(x => x.Path)
|
||||
.ToArray();
|
||||
m_nodeTransformPathList = transform.GetComponentsInChildren<Transform>()
|
||||
.Select(x => x.RelativePathFrom(transform))
|
||||
.Where(x => x != null)
|
||||
.ToArray()
|
||||
;
|
||||
|
||||
if(TryGetComponent<Animator>(out var animator))
|
||||
if (TryGetComponent<Animator>(out var animator))
|
||||
{
|
||||
var head = animator.GetBoneTransform(HumanBodyBones.Head);
|
||||
if (head != null)
|
||||
@@ -184,6 +196,12 @@ namespace UniVRM10
|
||||
get { return m_skinnedMeshRendererPathList; }
|
||||
}
|
||||
|
||||
string[] m_nodeTransformPathList;
|
||||
public string[] NodeTransformPathList
|
||||
{
|
||||
get { return m_nodeTransformPathList; }
|
||||
}
|
||||
|
||||
public string[] GetBlendShapeNames(int blendShapeMeshIndex)
|
||||
{
|
||||
if (blendShapeMeshIndex >= 0 && blendShapeMeshIndex < m_blendShapeMeshes.Length)
|
||||
@@ -228,19 +246,28 @@ namespace UniVRM10
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// bake NodeTransform
|
||||
//
|
||||
foreach (var nodeTransform in bake.NodeTransformBindings)
|
||||
{
|
||||
var node = transform.GetFromPath(nodeTransform.RelativePath);
|
||||
if (m_defaultTransformStates.TryGetValue(node, out var init))
|
||||
{
|
||||
nodeTransform.Apply(node, init, weight);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Bake Expression
|
||||
//
|
||||
m_bounds = default(Bounds);
|
||||
if (m_meshes != null)
|
||||
{
|
||||
if (bake != null)
|
||||
foreach (var x in m_meshes)
|
||||
{
|
||||
foreach (var x in m_meshes)
|
||||
{
|
||||
x.Bake(bake.MorphTargetBindings, weight);
|
||||
m_bounds.Expand(x.Mesh.bounds.size);
|
||||
}
|
||||
x.Bake(bake.MorphTargetBindings, weight);
|
||||
m_bounds.Expand(x.Mesh.bounds.size);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -46,5 +46,11 @@ namespace UniVRM10
|
||||
/// </summary>
|
||||
[SerializeField]
|
||||
public UniGLTF.Extensions.VRMC_vrm.ExpressionOverrideType OverrideMouth;
|
||||
|
||||
/// <summary>
|
||||
/// from UniVRM-132.0. experimental
|
||||
/// </summary>
|
||||
[SerializeField]
|
||||
public NodeTransformBinding[] NodeTransformBindings = new NodeTransformBinding[] { };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
using System;
|
||||
using UniGLTF.Utils;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UniVRM10
|
||||
{
|
||||
[DisallowMultipleComponent]
|
||||
public class Vrm10BoneTransformExpression : MonoBehaviour
|
||||
{
|
||||
[Serializable]
|
||||
public class BoneTransformExpression
|
||||
{
|
||||
public ExpressionPreset Preset = ExpressionPreset.custom;
|
||||
public string Name = "custom";
|
||||
public ExpressionKey ExpressionKey => new(Preset, Name);
|
||||
public Quaternion Rotation = Quaternion.identity;
|
||||
public Vector3 Translation = Vector3.zero;
|
||||
}
|
||||
|
||||
public BoneTransformExpression Expression;
|
||||
}
|
||||
}
|
||||
@@ -77,7 +77,7 @@ namespace UniVRM10
|
||||
}
|
||||
Constraints = instance.GetComponentsInChildren<IVrm10Constraint>();
|
||||
LookAt = new Vrm10RuntimeLookAt(instance, instance.Humanoid, ControlRig);
|
||||
Expression = new Vrm10RuntimeExpression(instance, LookAt.EyeDirectionApplicable, isPrefabInstance);
|
||||
Expression = new Vrm10RuntimeExpression(instance, LookAt.EyeDirectionApplicable, isPrefabInstance, initPose);
|
||||
SpringBone = springBoneRuntime;
|
||||
}
|
||||
|
||||
@@ -153,7 +153,7 @@ namespace UniVRM10
|
||||
|
||||
// 5. Apply Expression
|
||||
// LookAt の角度制限などはこちらで処理されます。
|
||||
Expression.Process(eyeDirection, _initPose);
|
||||
Expression.Process(eyeDirection);
|
||||
|
||||
// 6. SpringBone
|
||||
SpringBone.Process(Time.deltaTime);
|
||||
|
||||
@@ -25,9 +25,13 @@ namespace UniVRM10
|
||||
public float LookAtOverrideRate { get; private set; }
|
||||
public float MouthOverrideRate { get; private set; }
|
||||
|
||||
internal Vrm10RuntimeExpression(Vrm10Instance target, ILookAtEyeDirectionApplicable eyeDirectionApplicable, bool isPrefabInstance)
|
||||
internal Vrm10RuntimeExpression(Vrm10Instance target,
|
||||
ILookAtEyeDirectionApplicable eyeDirectionApplicable,
|
||||
bool isPrefabInstance,
|
||||
IReadOnlyDictionary<Transform, TransformState> initPose
|
||||
)
|
||||
{
|
||||
_merger = new ExpressionMerger(target.Vrm.Expression, target.transform, isPrefabInstance);
|
||||
_merger = new ExpressionMerger(target.Vrm.Expression, target.transform, isPrefabInstance, initPose);
|
||||
_keys = target.Vrm.Expression.Clips
|
||||
.Select(x => target.Vrm.Expression.CreateKey(x.Clip))
|
||||
.ToList();
|
||||
@@ -60,9 +64,9 @@ namespace UniVRM10
|
||||
_eyeDirectionApplicable = null;
|
||||
}
|
||||
|
||||
internal void Process(LookAtEyeDirection inputEyeDirection, IReadOnlyDictionary<Transform, TransformState> initPose = null)
|
||||
internal void Process(LookAtEyeDirection inputEyeDirection)
|
||||
{
|
||||
Apply(inputEyeDirection, initPose);
|
||||
Apply(inputEyeDirection);
|
||||
}
|
||||
|
||||
public IDictionary<ExpressionKey, float> GetWeights()
|
||||
@@ -114,7 +118,7 @@ namespace UniVRM10
|
||||
/// 入力 Weight を基に、Validation を行い実際にモデルに適用される Weights を計算し、Merger を介して適用する。
|
||||
/// この際、LookAt の情報を pull してそれも適用する。
|
||||
/// </summary>
|
||||
private void Apply(LookAtEyeDirection inputEyeDirection, IReadOnlyDictionary<Transform, TransformState> initPose)
|
||||
private void Apply(LookAtEyeDirection inputEyeDirection)
|
||||
{
|
||||
// 1. Validate user input, and Output as actual weights.
|
||||
_validator.Validate(_inputWeights, _actualWeights,
|
||||
@@ -125,7 +129,7 @@ namespace UniVRM10
|
||||
_eyeDirectionApplicable?.Apply(_actualEyeDirection, _actualWeights);
|
||||
|
||||
// 3. Set actual weights to raw blendshapes.
|
||||
_merger.SetValues(_actualWeights, initPose);
|
||||
_merger.SetValues(_actualWeights);
|
||||
|
||||
BlinkOverrideRate = blink;
|
||||
LookAtOverrideRate = lookAt;
|
||||
|
||||
@@ -2,6 +2,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using UniGLTF;
|
||||
using UniGLTF.Extensions.VRMC_vrm;
|
||||
using UniGLTF.Extensions.VRMC_vrm_expressions_node_transform;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UniVRM10
|
||||
@@ -86,5 +87,29 @@ namespace UniVRM10
|
||||
}
|
||||
return binding;
|
||||
}
|
||||
|
||||
public static NodeTransformBinding? Build10(this NodeTransformBind bind, GameObject root, Vrm10Importer importer)
|
||||
{
|
||||
if (bind.Node.TryGetValidIndex(importer.Nodes.Count, out var nodeIndex))
|
||||
{
|
||||
var node = importer.Nodes[nodeIndex];
|
||||
var relativePath = node.RelativePathFrom(root.transform);
|
||||
|
||||
var t = bind.Translation != null && bind.Translation.Length >= 3
|
||||
? new Vector3(bind.Translation[0], bind.Translation[1], bind.Translation[2])
|
||||
: Vector3.zero;
|
||||
var r = bind.Rotation != null && bind.Rotation.Length >= 4
|
||||
? new Quaternion(bind.Rotation[0], bind.Rotation[1], bind.Rotation[2], bind.Rotation[3])
|
||||
: Quaternion.identity;
|
||||
var s = bind.Scale != null && bind.Scale.Length >= 3
|
||||
? new Vector3(bind.Scale[0], bind.Scale[1], bind.Scale[2])
|
||||
: Vector3.zero;
|
||||
return new NodeTransformBinding(relativePath, t, r, s);
|
||||
}
|
||||
else
|
||||
{
|
||||
return default;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -779,6 +779,17 @@ namespace UniVRM10
|
||||
};
|
||||
}
|
||||
|
||||
static UniGLTF.Extensions.VRMC_vrm_expressions_node_transform.NodeTransformBind ExportNodeTransformBinding(NodeTransformBinding binding, Func<string, int> getIndex)
|
||||
{
|
||||
return new UniGLTF.Extensions.VRMC_vrm_expressions_node_transform.NodeTransformBind
|
||||
{
|
||||
Node = getIndex(binding.RelativePath),
|
||||
Translation = new float[] { binding.OffsetTranslation.x, binding.OffsetRotation.y, binding.OffsetTranslation.z },
|
||||
Rotation = new float[] { binding.OffsetRotation.x, binding.OffsetRotation.y, binding.OffsetRotation.z, binding.OffsetRotation.w },
|
||||
Scale = new float[] { binding.TargetScale.x, binding.TargetScale.y, binding.TargetScale.z },
|
||||
};
|
||||
}
|
||||
|
||||
static UniGLTF.Extensions.VRMC_vrm.Expression ExportExpression(VRM10Expression e, Vrm10Instance vrmController, Model model, ModelExporter converter)
|
||||
{
|
||||
if (e == null)
|
||||
@@ -786,7 +797,7 @@ namespace UniVRM10
|
||||
return null;
|
||||
}
|
||||
|
||||
Func<string, int> getIndexFromRelativePath = relativePath =>
|
||||
Func<string, int> getRendererNodeIndexFromRelativePath = relativePath =>
|
||||
{
|
||||
var rendererNode = vrmController.transform.GetFromPath(relativePath);
|
||||
var renderer = rendererNode.GetComponent<Renderer>();
|
||||
@@ -831,7 +842,7 @@ namespace UniVRM10
|
||||
{
|
||||
try
|
||||
{
|
||||
var binding = ExportMorphTargetBinding(b, getIndexFromRelativePath);
|
||||
var binding = ExportMorphTargetBinding(b, getRendererNodeIndexFromRelativePath);
|
||||
if (binding.Node < 0)
|
||||
{
|
||||
// node もしくは renderer が存在しない
|
||||
@@ -867,6 +878,43 @@ namespace UniVRM10
|
||||
UniGLTFLogger.Warning($"{ex}");
|
||||
}
|
||||
}
|
||||
|
||||
if (e.NodeTransformBindings != null && e.NodeTransformBindings.Length > 0)
|
||||
{
|
||||
Func<string, int> getNodeIndexFromRelativePath = relativePath =>
|
||||
{
|
||||
var n = vrmController.transform.GetFromPath(relativePath);
|
||||
var node = converter.Nodes[n.gameObject];
|
||||
return model.Nodes.IndexOf(node);
|
||||
};
|
||||
|
||||
var nodeTransform = new UniGLTF.Extensions.VRMC_vrm_expressions_node_transform.VRMC_vrm_expressions_node_transform
|
||||
{
|
||||
NodeTransformBinds = new(),
|
||||
};
|
||||
foreach (var b in e.NodeTransformBindings)
|
||||
{
|
||||
try
|
||||
{
|
||||
var binding = ExportNodeTransformBinding(b, getNodeIndexFromRelativePath);
|
||||
if (binding.Node < 0)
|
||||
{
|
||||
// node もしくは renderer が存在しない
|
||||
continue;
|
||||
}
|
||||
|
||||
nodeTransform.NodeTransformBinds.Add(binding);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
UniGLTFLogger.Warning($"{ex}");
|
||||
}
|
||||
}
|
||||
glTFExtension extensions = default;
|
||||
UniGLTF.Extensions.VRMC_vrm_expressions_node_transform.GltfSerializer.SerializeTo(ref extensions, nodeTransform);
|
||||
vrmExpression.Extensions = extensions;
|
||||
}
|
||||
|
||||
return vrmExpression;
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ using System.Threading.Tasks;
|
||||
using UniGLTF;
|
||||
using UniGLTF.Extensions.VRMC_springBone_limit;
|
||||
using UniGLTF.Utils;
|
||||
using UnityEditor.Experimental.GraphView;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UniVRM10
|
||||
@@ -286,6 +287,25 @@ namespace UniVRM10
|
||||
clip.MaterialUVBindings = new MaterialUVBinding[] { };
|
||||
}
|
||||
|
||||
if (UniGLTF.Extensions.VRMC_vrm_expressions_node_transform.GltfDeserializer.TryGet(
|
||||
expression.Extensions as glTFExtension,
|
||||
out UniGLTF.Extensions.VRMC_vrm_expressions_node_transform.VRMC_vrm_expressions_node_transform nodeTransform))
|
||||
{
|
||||
if (nodeTransform.NodeTransformBinds != null)
|
||||
{
|
||||
clip.NodeTransformBindings = nodeTransform.NodeTransformBinds?
|
||||
.Select(x => x.Build10(Root, this))
|
||||
.Where(x => x.HasValue)
|
||||
.Select(x => x.Value)
|
||||
.ToArray();
|
||||
}
|
||||
else
|
||||
{
|
||||
clip.NodeTransformBindings = new NodeTransformBinding[] { };
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
m_expressions.Add((preset, clip));
|
||||
}
|
||||
return clip;
|
||||
|
||||
Reference in New Issue
Block a user