Merge branch 'master' into version/v0_131_1

This commit is contained in:
ousttrue
2026-04-13 14:43:47 +09:00
committed by GitHub
30 changed files with 870 additions and 45 deletions

View File

@@ -1,4 +1,4 @@
using UnityEngine.Rendering;
using UnityEngine.Rendering;
namespace UniGLTF
{
@@ -6,19 +6,19 @@ namespace UniGLTF
{
public static RenderPipelineTypes GetRenderPipelineType()
{
RenderPipeline currentPipeline = RenderPipelineManager.currentPipeline;
RenderPipelineAsset currentRenderPipelineAsset = GraphicsSettings.currentRenderPipeline;
if (currentPipeline == null)
if (currentRenderPipelineAsset == null)
{
return RenderPipelineTypes.BuiltinRenderPipeline;
}
if (currentPipeline.GetType().Name.Contains("HDRenderPipeline"))
if (currentRenderPipelineAsset.GetType().Name.Contains("HDRenderPipeline"))
{
return RenderPipelineTypes.HighDefinitionRenderPipeline;
}
if (currentPipeline.GetType().Name.Contains("UniversalRenderPipeline"))
if (currentRenderPipelineAsset.GetType().Name.Contains("UniversalRenderPipeline"))
{
return RenderPipelineTypes.UniversalRenderPipeline;
}
@@ -26,4 +26,4 @@ namespace UniGLTF
return RenderPipelineTypes.Unknown;
}
}
}
}

View File

@@ -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);

View File

@@ -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);

View File

@@ -0,0 +1,133 @@
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);
EditorGUI.BeginChangeCheck();
EditorGUI.PropertyField(rect, property.FindPropertyRelative(nameof(NodeTransformBinding.OffsetRotation)));
if (EditorGUI.EndChangeCheck())
{
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;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 186e6dd105c86904497f3ac0dfd61212
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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;
}

View File

@@ -36,6 +36,7 @@ namespace UniVRM10
private const string Vrm10SpecDir = "vrm-specification/specification";
private const string Vrm10FormatGeneratedDir = "Packages/VRM10/Runtime/Format";
private const string UniGltfFormatGeneratedDir = "Packages/UniGLTF/Runtime/UniGLTF/Format";
public static void Run(bool debug)
{
@@ -48,7 +49,7 @@ namespace UniVRM10
// VRMC_hdr_emissiveMultiplier
new GenerateInfo(
$"{Vrm10SpecDir}/VRMC_materials_hdr_emissiveMultiplier-1.0/schema/VRMC_materials_hdr_emissiveMultiplier.json",
"Assets/UniGLTF/Runtime/UniGLTF/Format/ExtensionsAndExtras/EmissiveMultiplier"
$"{UniGltfFormatGeneratedDir}/ExtensionsAndExtras/EmissiveMultiplier"
),
// VRMC_vrm
@@ -94,6 +95,14 @@ namespace UniVRM10
$"{Vrm10SpecDir}/VRMC_springBone_limit-1.0/schema/VRMC_springBone_limit.schema.json",
$"{Vrm10FormatGeneratedDir}/SpringBoneLimit"
),
// VRMC_vrm_expressions_node_transform-1.0
// (experimental)
// https://github.com/ousttrue/vrm-specification/tree/VRMC_vrm_expression_joint
new GenerateInfo(
$"{Vrm10SpecDir}/VRMC_vrm_expressions_node_transform-1.0/schema/VRMC_vrm_expressions_node_transform.schema.json",
$"{Vrm10FormatGeneratedDir}/ExpressionsNodeTransform"
),
};
foreach (var arg in args)

View File

@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using UniGLTF.Utils;
using UnityEngine;
namespace UniVRM10
@@ -23,9 +24,13 @@ namespace UniVRM10
MorphTargetBindingMerger m_morphTargetBindingMerger;
MaterialValueBindingMerger m_materialValueBindingMerger;
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),
@@ -35,6 +40,7 @@ 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 NodeTransformBindingMerger(m_clipMap, root, initPose);
}
/// <summary>
@@ -50,6 +56,7 @@ namespace UniVRM10
m_morphTargetBindingMerger.Apply();
m_materialValueBindingMerger.Apply();
m_boneTransformBindingMerger.Apply();
}
private void AccumulateValue(ExpressionKey key, float value)
@@ -69,6 +76,7 @@ namespace UniVRM10
m_morphTargetBindingMerger.AccumulateValue(key, value);
m_materialValueBindingMerger.AccumulateValue(clip, value);
m_boneTransformBindingMerger.AccumulateValue(key, value);
}
public void Dispose()

View File

@@ -0,0 +1,56 @@
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)
);
if (this.TargetScale != Vector3.zero)
{
node.localScale = Vector3.Lerp(init.LocalScale, this.TargetScale, weight);
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: dd660f7a77373234c85064f97150eef6
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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);
}
}
}
}
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: fe2bf5e71647b0f4d93ca6c22bb9fb7f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -123,7 +123,9 @@ namespace UniVRM10
{
return new PreviewMeshItem(t.RelativePathFrom(root), t, skinnedMeshRenderer.sharedMaterials)
{
Mesh = skinnedMeshRenderer.sharedMesh,
SkinnedMeshRenderer = skinnedMeshRenderer,
Mesh = new Mesh(), // for bake
BlendShapeNames = new string[]{},
};
}
}

View File

@@ -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);
}
}

View File

@@ -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[] { };
}
}

View File

@@ -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;
}

View File

@@ -1,6 +1,8 @@
using System;
using System.Collections.Generic;
using System.Linq;
using UniGLTF.Utils;
using UnityEngine;
namespace UniVRM10
{
@@ -23,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();

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: d80842db26fe76645bf195c10b9c6bf7
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,145 @@
// This file is generated from JsonSchema. Don't modify this source code.
using UniJSON;
using System;
using System.Collections.Generic;
using UnityEngine;
namespace UniGLTF.Extensions.VRMC_vrm_expressions_node_transform {
public static class GltfDeserializer
{
public static readonly Utf8String ExtensionNameUtf8 = Utf8String.From(VRMC_vrm_expressions_node_transform.ExtensionName);
public static bool TryGet(UniGLTF.glTFExtension src, out VRMC_vrm_expressions_node_transform extension)
{
if(src is UniGLTF.glTFExtensionImport extensions)
{
foreach(var kv in extensions.ObjectItems())
{
if(kv.Key.GetUtf8String() == ExtensionNameUtf8)
{
extension = Deserialize(kv.Value);
return true;
}
}
}
extension = default;
return false;
}
public static VRMC_vrm_expressions_node_transform Deserialize(JsonNode parsed)
{
var value = new VRMC_vrm_expressions_node_transform();
foreach(var kv in parsed.ObjectItems())
{
var key = kv.Key.GetString();
if(key=="extensions"){
value.Extensions = new glTFExtensionImport(kv.Value);
continue;
}
if(key=="extras"){
value.Extras = new glTFExtensionImport(kv.Value);
continue;
}
if(key=="nodeTransformBinds"){
value.NodeTransformBinds = Deserialize_NodeTransformBinds(kv.Value);
continue;
}
}
return value;
}
public static List<NodeTransformBind> Deserialize_NodeTransformBinds(JsonNode parsed)
{
var value = new List<NodeTransformBind>();
foreach(var x in parsed.ArrayItems())
{
value.Add(Deserialize_NodeTransformBinds_ITEM(x));
}
return value;
}
public static NodeTransformBind Deserialize_NodeTransformBinds_ITEM(JsonNode parsed)
{
var value = new NodeTransformBind();
foreach(var kv in parsed.ObjectItems())
{
var key = kv.Key.GetString();
if(key=="extensions"){
value.Extensions = new glTFExtensionImport(kv.Value);
continue;
}
if(key=="extras"){
value.Extras = new glTFExtensionImport(kv.Value);
continue;
}
if(key=="node"){
value.Node = kv.Value.GetInt32();
continue;
}
if(key=="rotation"){
value.Rotation = __nodeTransformBinds_ITEM_Deserialize_Rotation(kv.Value);
continue;
}
if(key=="scale"){
value.Scale = __nodeTransformBinds_ITEM_Deserialize_Scale(kv.Value);
continue;
}
if(key=="translation"){
value.Translation = __nodeTransformBinds_ITEM_Deserialize_Translation(kv.Value);
continue;
}
}
return value;
}
public static float[] __nodeTransformBinds_ITEM_Deserialize_Rotation(JsonNode parsed)
{
var value = new float[parsed.GetArrayCount()];
int i=0;
foreach(var x in parsed.ArrayItems())
{
value[i++] = x.GetSingle();
}
return value;
}
public static float[] __nodeTransformBinds_ITEM_Deserialize_Scale(JsonNode parsed)
{
var value = new float[parsed.GetArrayCount()];
int i=0;
foreach(var x in parsed.ArrayItems())
{
value[i++] = x.GetSingle();
}
return value;
}
public static float[] __nodeTransformBinds_ITEM_Deserialize_Translation(JsonNode parsed)
{
var value = new float[parsed.GetArrayCount()];
int i=0;
foreach(var x in parsed.ArrayItems())
{
value[i++] = x.GetSingle();
}
return value;
}
} // GltfDeserializer
} // UniGLTF

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 0a0544899292fe54e961d98e2f7d755c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,43 @@
// This file is generated from JsonSchema. Don't modify this source code.
using System;
using System.Collections.Generic;
namespace UniGLTF.Extensions.VRMC_vrm_expressions_node_transform
{
public class NodeTransformBind
{
// Dictionary object with extension-specific objects.
public object Extensions;
// Application-specific data.
public object Extras;
// The node index.
public int? Node;
// The node's unit quaternion rotation in the order (x, y, z, w), where w is the scalar.
public float[] Rotation;
// The node's non-uniform scale, given as the scaling factors along the x, y, and z axes.
public float[] Scale;
// The node's translation along the x, y, and z axes.
public float[] Translation;
}
public class VRMC_vrm_expressions_node_transform
{
public const string ExtensionName = "VRMC_vrm_expressions_node_transform";
// Dictionary object with extension-specific objects.
public object Extensions;
// Application-specific data.
public object Extras;
// Specify a node transform
public List<NodeTransformBind> NodeTransformBinds;
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 3f6d0369358084249b383bea969b16a6
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,141 @@
// This file is generated from JsonSchema. Don't modify this source code.
using System;
using System.Collections.Generic;
using System.Linq;
using UniJSON;
namespace UniGLTF.Extensions.VRMC_vrm_expressions_node_transform {
static public class GltfSerializer
{
public static void SerializeTo(ref UniGLTF.glTFExtension dst, VRMC_vrm_expressions_node_transform extension)
{
if (dst is glTFExtensionImport)
{
throw new NotImplementedException();
}
if (!(dst is glTFExtensionExport extensions))
{
extensions = new glTFExtensionExport();
dst = extensions;
}
var f = new JsonFormatter();
Serialize(f, extension);
extensions.Add(VRMC_vrm_expressions_node_transform.ExtensionName, f.GetStoreBytes());
}
public static void Serialize(JsonFormatter f, VRMC_vrm_expressions_node_transform value)
{
f.BeginMap();
if(value.Extensions!=null){
f.Key("extensions");
(value.Extensions as glTFExtension).Serialize(f);
}
if(value.Extras!=null){
f.Key("extras");
(value.Extras as glTFExtension).Serialize(f);
}
if(value.NodeTransformBinds!=null&&value.NodeTransformBinds.Count()>=1){
f.Key("nodeTransformBinds");
Serialize_NodeTransformBinds(f, value.NodeTransformBinds);
}
f.EndMap();
}
public static void Serialize_NodeTransformBinds(JsonFormatter f, List<NodeTransformBind> value)
{
f.BeginList();
foreach(var item in value)
{
Serialize_NodeTransformBinds_ITEM(f, item);
}
f.EndList();
}
public static void Serialize_NodeTransformBinds_ITEM(JsonFormatter f, NodeTransformBind value)
{
f.BeginMap();
if(value.Extensions!=null){
f.Key("extensions");
(value.Extensions as glTFExtension).Serialize(f);
}
if(value.Extras!=null){
f.Key("extras");
(value.Extras as glTFExtension).Serialize(f);
}
if(value.Node.HasValue){
f.Key("node");
f.Value(value.Node.GetValueOrDefault());
}
if(value.Rotation!=null&&value.Rotation.Count()>=4){
f.Key("rotation");
__nodeTransformBinds_ITEM_Serialize_Rotation(f, value.Rotation);
}
if(value.Scale!=null&&value.Scale.Count()>=3){
f.Key("scale");
__nodeTransformBinds_ITEM_Serialize_Scale(f, value.Scale);
}
if(value.Translation!=null&&value.Translation.Count()>=3){
f.Key("translation");
__nodeTransformBinds_ITEM_Serialize_Translation(f, value.Translation);
}
f.EndMap();
}
public static void __nodeTransformBinds_ITEM_Serialize_Rotation(JsonFormatter f, float[] value)
{
f.BeginList();
foreach(var item in value)
{
f.Value(item);
}
f.EndList();
}
public static void __nodeTransformBinds_ITEM_Serialize_Scale(JsonFormatter f, float[] value)
{
f.BeginList();
foreach(var item in value)
{
f.Value(item);
}
f.EndList();
}
public static void __nodeTransformBinds_ITEM_Serialize_Translation(JsonFormatter f, float[] value)
{
f.BeginList();
foreach(var item in value)
{
f.Value(item);
}
f.EndList();
}
} // class
} // namespace

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 16a49328d069d9f47840c104597af4a4
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -44,10 +44,10 @@ namespace UniGLTF.Extensions.VRMC_springBone_limit
// Application-specific data.
public object Extras;
// The phi angle of the spherical limit in radians. If the phi angle is set to π or greater, the angle will be interpreted as π by the implementation.
// The pitch angle of the spherical limit in radians. If the pitch angle is set to π or greater, the angle will be interpreted as π by the implementation.
public float? Pitch;
// The theta angle of the spherical limit in radians. If the theta angle is set to π/2 or greater, the angle will be interpreted as π/2 by the implementation.
// The yaw angle of the spherical limit in radians. If the yaw angle is set to π/2 or greater, the angle will be interpreted as π/2 by the implementation.
public float? Yaw;
// The rotation from the default orientation of the spherical limit. The rotation is represented as a quaternion (x, y, z, w), where w is the scalar.

View File

@@ -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])
: node.transform.localScale;
return new NodeTransformBinding(relativePath, t, r, s);
}
else
{
return default;
}
}
}
}

View File

@@ -44,7 +44,7 @@ namespace UniVRM10
// use material.name, because material name may renamed in GltfParser.
matDesc = new MaterialDescriptor(
m.name,
Shader.Find(MToon10Meta.UnityShaderName),
Shader,
null,
Vrm10MToonTextureImporter.EnumerateAllTextures(data, m, mtoon).ToDictionary(tuple => tuple.key, tuple => tuple.Item2.Item2),
TryGetAllFloats(m, mtoon).ToDictionary(tuple => tuple.key, tuple => tuple.value),

View File

@@ -39,7 +39,7 @@ namespace UniVRM10
// use material.name, because material name may renamed in GltfParser.
matDesc = new MaterialDescriptor(
m.name,
Shader.Find(MToon10Meta.UnityUrpShaderName),
Shader,
null,
Vrm10MToonTextureImporter.EnumerateAllTextures(data, m, mtoon).ToDictionary(tuple => tuple.key, tuple => tuple.Item2.Item2),
BuiltInVrm10MToonMaterialImporter.TryGetAllFloats(m, mtoon).ToDictionary(tuple => tuple.key, tuple => tuple.value),

View File

@@ -779,6 +779,19 @@ namespace UniVRM10
};
}
static UniGLTF.Extensions.VRMC_vrm_expressions_node_transform.NodeTransformBind ExportNodeTransformBinding(NodeTransformBinding binding, Func<string, int> getIndex)
{
var translation = ReverseX(binding.OffsetTranslation);
var rotation = ReverseX(binding.OffsetRotation);
return new UniGLTF.Extensions.VRMC_vrm_expressions_node_transform.NodeTransformBind
{
Node = getIndex(binding.RelativePath),
Translation = new float[] { translation.x, translation.y, translation.z },
Rotation = new float[] { rotation.x, rotation.y, rotation.z, rotation.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 +799,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 +844,7 @@ namespace UniVRM10
{
try
{
var binding = ExportMorphTargetBinding(b, getIndexFromRelativePath);
var binding = ExportMorphTargetBinding(b, getRendererNodeIndexFromRelativePath);
if (binding.Node < 0)
{
// node もしくは renderer が存在しない
@@ -867,6 +880,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;
}

View File

@@ -286,6 +286,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;