mirror of
https://github.com/bdunderscore/modular-avatar.git
synced 2024-12-29 18:55:06 +08:00
fix: incorrect handling of shape key deletion (#1258)
This change reworks delete handling to be more consistent with other properties, by treating it as a virtual property (`deletedShape.{blendshapeName}`) instead of a weird additional field of blendshape keys. This then fixes a number of issues (e.g. broken preview for delete keys). Fixes: #1253
This commit is contained in:
parent
c379d730ca
commit
30cafb21e4
@ -8,7 +8,6 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
public TargetProp TargetProp { get; }
|
public TargetProp TargetProp { get; }
|
||||||
public string ControlParam { get; set; }
|
public string ControlParam { get; set; }
|
||||||
|
|
||||||
public bool alwaysDeleted;
|
|
||||||
public object currentState;
|
public object currentState;
|
||||||
|
|
||||||
// Objects which trigger deletion of this shape key.
|
// Objects which trigger deletion of this shape key.
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using nadena.dev.modular_avatar.animation;
|
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
namespace nadena.dev.modular_avatar.core.editor
|
namespace nadena.dev.modular_avatar.core.editor
|
||||||
@ -9,8 +8,8 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
{
|
{
|
||||||
public ReactionRule(TargetProp key, float value)
|
public ReactionRule(TargetProp key, float value)
|
||||||
: this(key, (object)value) { }
|
: this(key, (object)value) { }
|
||||||
|
|
||||||
public ReactionRule(TargetProp key, UnityEngine.Object value)
|
public ReactionRule(TargetProp key, Object value)
|
||||||
: this(key, (object)value) { }
|
: this(key, (object)value) { }
|
||||||
|
|
||||||
private ReactionRule(TargetProp key, object value)
|
private ReactionRule(TargetProp key, object value)
|
||||||
@ -31,15 +30,15 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
|
|
||||||
public bool InitiallyActive =>
|
public bool InitiallyActive =>
|
||||||
((ControllingConditions.Count == 0) || ControllingConditions.All(c => c.InitiallyActive)) ^ Inverted;
|
((ControllingConditions.Count == 0) || ControllingConditions.All(c => c.InitiallyActive)) ^ Inverted;
|
||||||
public bool IsDelete;
|
|
||||||
|
|
||||||
public bool Inverted;
|
public bool Inverted;
|
||||||
|
|
||||||
public bool IsConstant => ControllingConditions.Count == 0
|
public bool IsConstant => ControllingConditions.Count == 0
|
||||||
|| ControllingConditions.All(c => c.IsConstant)
|
|| ControllingConditions.All(c => c.IsConstant)
|
||||||
|| ControllingConditions.Any(c => c.IsConstant && !c.InitiallyActive);
|
|| ControllingConditions.Any(c => c.IsConstant && !c.InitiallyActive);
|
||||||
public bool IsConstantOn => IsConstant && InitiallyActive;
|
|
||||||
|
|
||||||
|
public bool IsConstantActive => IsConstant && InitiallyActive ^ Inverted;
|
||||||
|
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
{
|
{
|
||||||
return $"AGK: {TargetProp}={Value}";
|
return $"AGK: {TargetProp}={Value}";
|
||||||
@ -57,7 +56,6 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
}
|
}
|
||||||
else return false;
|
else return false;
|
||||||
if (!ControllingConditions.SequenceEqual(other.ControllingConditions)) return false;
|
if (!ControllingConditions.SequenceEqual(other.ControllingConditions)) return false;
|
||||||
if (IsDelete || other.IsDelete) return false;
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -124,50 +124,55 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
var key = new TargetProp
|
var key = new TargetProp
|
||||||
{
|
{
|
||||||
TargetObject = renderer,
|
TargetObject = renderer,
|
||||||
PropertyName = "blendShape." + shape.ShapeName,
|
PropertyName = BlendshapePrefix + shape.ShapeName
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var currentValue = renderer.GetBlendShapeWeight(shapeId);
|
||||||
var value = shape.ChangeType == ShapeChangeType.Delete ? 100 : shape.Value;
|
var value = shape.ChangeType == ShapeChangeType.Delete ? 100 : shape.Value;
|
||||||
if (!shapeKeys.TryGetValue(key, out var info))
|
|
||||||
|
RegisterAction(key, renderer, currentValue, value, changer, shape);
|
||||||
|
|
||||||
|
key = new TargetProp
|
||||||
{
|
{
|
||||||
info = new AnimatedProperty(key, renderer.GetBlendShapeWeight(shapeId));
|
TargetObject = renderer,
|
||||||
shapeKeys[key] = info;
|
PropertyName = DeletedShapePrefix + shape.ShapeName
|
||||||
|
};
|
||||||
|
|
||||||
// Add initial state
|
value = shape.ChangeType == ShapeChangeType.Delete ? 1 : 0;
|
||||||
var agk = new ReactionRule(key, value);
|
RegisterAction(key, renderer, 0, value, changer, shape);
|
||||||
agk.Value = renderer.GetBlendShapeWeight(shapeId);
|
|
||||||
info.actionGroups.Add(agk);
|
|
||||||
}
|
|
||||||
|
|
||||||
var action = ObjectRule(key, changer, value);
|
|
||||||
action.Inverted = _computeContext.Observe(changer, c => c.Inverted);
|
|
||||||
var isCurrentlyActive = changer.gameObject.activeInHierarchy;
|
|
||||||
|
|
||||||
if (shape.ChangeType == ShapeChangeType.Delete)
|
|
||||||
{
|
|
||||||
action.IsDelete = true;
|
|
||||||
|
|
||||||
if (isCurrentlyActive) info.currentState = 100;
|
|
||||||
|
|
||||||
info.actionGroups.Add(action); // Never merge
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (changer.gameObject.activeInHierarchy) info.currentState = action.Value;
|
|
||||||
|
|
||||||
if (info.actionGroups.Count == 0)
|
|
||||||
{
|
|
||||||
info.actionGroups.Add(action);
|
|
||||||
}
|
|
||||||
else if (!info.actionGroups[^1].TryMerge(action))
|
|
||||||
{
|
|
||||||
info.actionGroups.Add(action);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return shapeKeys;
|
return shapeKeys;
|
||||||
|
|
||||||
|
void RegisterAction(TargetProp key, SkinnedMeshRenderer renderer, float currentValue, float value,
|
||||||
|
ModularAvatarShapeChanger changer, ChangedShape shape)
|
||||||
|
{
|
||||||
|
if (!shapeKeys.TryGetValue(key, out var info))
|
||||||
|
{
|
||||||
|
info = new AnimatedProperty(key, currentValue);
|
||||||
|
shapeKeys[key] = info;
|
||||||
|
|
||||||
|
// Add initial state
|
||||||
|
var agk = new ReactionRule(key, value);
|
||||||
|
agk.Value = currentValue;
|
||||||
|
info.actionGroups.Add(agk);
|
||||||
|
}
|
||||||
|
|
||||||
|
var action = ObjectRule(key, changer, value);
|
||||||
|
action.Inverted = _computeContext.Observe(changer, c => c.Inverted);
|
||||||
|
|
||||||
|
if (changer.gameObject.activeInHierarchy) info.currentState = action.Value;
|
||||||
|
|
||||||
|
if (info.actionGroups.Count == 0)
|
||||||
|
{
|
||||||
|
info.actionGroups.Add(action);
|
||||||
|
}
|
||||||
|
else if (!info.actionGroups[^1].TryMerge(action))
|
||||||
|
{
|
||||||
|
info.actionGroups.Add(action);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void FindMaterialSetters(Dictionary<TargetProp, AnimatedProperty> objectGroups, GameObject root)
|
private void FindMaterialSetters(Dictionary<TargetProp, AnimatedProperty> objectGroups, GameObject root)
|
||||||
|
@ -18,6 +18,9 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
private readonly ndmf.BuildContext _context;
|
private readonly ndmf.BuildContext _context;
|
||||||
private readonly AnimationServicesContext _asc;
|
private readonly AnimationServicesContext _asc;
|
||||||
private Dictionary<string, float> _simulationInitialStates;
|
private Dictionary<string, float> _simulationInitialStates;
|
||||||
|
|
||||||
|
public const string BlendshapePrefix = "blendShape.";
|
||||||
|
public const string DeletedShapePrefix = "deletedShape.";
|
||||||
|
|
||||||
public ImmutableDictionary<string, float> ForcePropertyOverrides { get; set; } = ImmutableDictionary<string, float>.Empty;
|
public ImmutableDictionary<string, float> ForcePropertyOverrides { get; set; } = ImmutableDictionary<string, float>.Empty;
|
||||||
|
|
||||||
@ -58,7 +61,6 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
{
|
{
|
||||||
public Dictionary<TargetProp, AnimatedProperty> Shapes;
|
public Dictionary<TargetProp, AnimatedProperty> Shapes;
|
||||||
public Dictionary<TargetProp, object> InitialStates;
|
public Dictionary<TargetProp, object> InitialStates;
|
||||||
public HashSet<TargetProp> DeletedShapes;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static PropCache<GameObject, AnalysisResult> _analysisCache;
|
private static PropCache<GameObject, AnalysisResult> _analysisCache;
|
||||||
@ -86,7 +88,6 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="root">The avatar root</param>
|
/// <param name="root">The avatar root</param>
|
||||||
/// <param name="initialStates">A dictionary of target property to initial state (float or UnityEngine.Object)</param>
|
/// <param name="initialStates">A dictionary of target property to initial state (float or UnityEngine.Object)</param>
|
||||||
/// <param name="deletedShapes">A hashset of blendshape properties which are always deleted</param>
|
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public AnalysisResult Analyze(
|
public AnalysisResult Analyze(
|
||||||
GameObject root
|
GameObject root
|
||||||
@ -98,7 +99,6 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
{
|
{
|
||||||
result.Shapes = new();
|
result.Shapes = new();
|
||||||
result.InitialStates = new();
|
result.InitialStates = new();
|
||||||
result.DeletedShapes = new();
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -109,7 +109,7 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
ApplyInitialStateOverrides(shapes);
|
ApplyInitialStateOverrides(shapes);
|
||||||
AnalyzeConstants(shapes);
|
AnalyzeConstants(shapes);
|
||||||
ResolveToggleInitialStates(shapes);
|
ResolveToggleInitialStates(shapes);
|
||||||
PreprocessShapes(shapes, out result.InitialStates, out result.DeletedShapes);
|
PreprocessShapes(shapes, out result.InitialStates);
|
||||||
result.Shapes = shapes;
|
result.Shapes = shapes;
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
@ -165,7 +165,7 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
group.actionGroups.RemoveAll(agk => agk.IsConstant && !agk.InitiallyActive);
|
group.actionGroups.RemoveAll(agk => agk.IsConstant && !agk.InitiallyActive);
|
||||||
|
|
||||||
// Remove all action groups up until the last one where we're always on
|
// Remove all action groups up until the last one where we're always on
|
||||||
var lastAlwaysOnGroup = group.actionGroups.FindLastIndex(ag => ag.IsConstantOn);
|
var lastAlwaysOnGroup = group.actionGroups.FindLastIndex(ag => ag.IsConstantActive);
|
||||||
if (lastAlwaysOnGroup > 0)
|
if (lastAlwaysOnGroup > 0)
|
||||||
group.actionGroups.RemoveRange(0, lastAlwaysOnGroup - 1);
|
group.actionGroups.RemoveRange(0, lastAlwaysOnGroup - 1);
|
||||||
}
|
}
|
||||||
@ -264,18 +264,17 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Determine initial state and deleted shapes for all properties
|
/// Determine initial state for all properties
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="shapes"></param>
|
/// <param name="shapes"></param>
|
||||||
/// <param name="initialStates"></param>
|
/// <param name="initialStates"></param>
|
||||||
/// <param name="deletedShapes"></param>
|
private void PreprocessShapes(Dictionary<TargetProp, AnimatedProperty> shapes,
|
||||||
private void PreprocessShapes(Dictionary<TargetProp, AnimatedProperty> shapes, out Dictionary<TargetProp, object> initialStates, out HashSet<TargetProp> deletedShapes)
|
out Dictionary<TargetProp, object> initialStates)
|
||||||
{
|
{
|
||||||
// For each shapekey, determine 1) if we can just set an initial state and skip and 2) if we can delete the
|
// For each shapekey, determine 1) if we can just set an initial state and skip and 2) if we can delete the
|
||||||
// corresponding mesh. If we can't, delete ops are merged into the main list of operations.
|
// corresponding mesh. If we can't, delete ops are merged into the main list of operations.
|
||||||
|
|
||||||
initialStates = new Dictionary<TargetProp, object>();
|
initialStates = new Dictionary<TargetProp, object>();
|
||||||
deletedShapes = new HashSet<TargetProp>();
|
|
||||||
|
|
||||||
foreach (var (key, info) in shapes.ToList())
|
foreach (var (key, info) in shapes.ToList())
|
||||||
{
|
{
|
||||||
@ -285,18 +284,6 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
shapes.Remove(key);
|
shapes.Remove(key);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
var deletions = info.actionGroups.Where(agk => agk.IsDelete).ToList();
|
|
||||||
if (deletions.Any(d => d.InitiallyActive))
|
|
||||||
{
|
|
||||||
// always deleted
|
|
||||||
shapes.Remove(key);
|
|
||||||
deletedShapes.Add(key);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Move deleted shapes to the end of the list, so they override all Set actions
|
|
||||||
info.actionGroups = info.actionGroups.Where(agk => !agk.IsDelete).Concat(deletions).ToList();
|
|
||||||
|
|
||||||
var initialState = info.actionGroups.Where(agk => agk.InitiallyActive)
|
var initialState = info.actionGroups.Where(agk => agk.InitiallyActive)
|
||||||
.Select(agk => agk.Value)
|
.Select(agk => agk.Value)
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.Immutable;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using nadena.dev.modular_avatar.animation;
|
using nadena.dev.modular_avatar.animation;
|
||||||
using UnityEditor;
|
using UnityEditor;
|
||||||
@ -42,10 +41,11 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
|
|
||||||
var shapes = analysis.Shapes;
|
var shapes = analysis.Shapes;
|
||||||
var initialStates = analysis.InitialStates;
|
var initialStates = analysis.InitialStates;
|
||||||
var deletedShapes = analysis.DeletedShapes;
|
|
||||||
|
|
||||||
GenerateActiveSelfProxies(shapes);
|
GenerateActiveSelfProxies(shapes);
|
||||||
|
|
||||||
|
ProcessMeshDeletion(initialStates, shapes);
|
||||||
|
|
||||||
ProcessInitialStates(initialStates, shapes);
|
ProcessInitialStates(initialStates, shapes);
|
||||||
ProcessInitialAnimatorVariables(shapes);
|
ProcessInitialAnimatorVariables(shapes);
|
||||||
|
|
||||||
@ -53,8 +53,6 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
{
|
{
|
||||||
ProcessShapeKey(groups);
|
ProcessShapeKey(groups);
|
||||||
}
|
}
|
||||||
|
|
||||||
ProcessMeshDeletion(deletedShapes);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void GenerateActiveSelfProxies(Dictionary<TargetProp, AnimatedProperty> shapes)
|
private void GenerateActiveSelfProxies(Dictionary<TargetProp, AnimatedProperty> shapes)
|
||||||
@ -225,30 +223,65 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
|
|
||||||
#region Mesh processing
|
#region Mesh processing
|
||||||
|
|
||||||
private void ProcessMeshDeletion(HashSet<TargetProp> deletedKeys)
|
private void ProcessMeshDeletion(Dictionary<TargetProp, object> initialStates,
|
||||||
|
Dictionary<TargetProp, AnimatedProperty> shapes)
|
||||||
{
|
{
|
||||||
ImmutableDictionary<SkinnedMeshRenderer, List<TargetProp>> renderers = deletedKeys
|
var renderers = initialStates
|
||||||
.GroupBy(
|
.Where(kvp => kvp.Key.PropertyName.StartsWith(ReactiveObjectAnalyzer.DeletedShapePrefix))
|
||||||
v => (SkinnedMeshRenderer) v.TargetObject
|
.Where(kvp => kvp.Key.TargetObject is SkinnedMeshRenderer)
|
||||||
).ToImmutableDictionary(
|
.Where(kvp => kvp.Value is float f && f > 0.5f)
|
||||||
g => (SkinnedMeshRenderer) g.Key,
|
// Filter any non-constant keys
|
||||||
g => g.ToList()
|
.Where(kvp =>
|
||||||
);
|
{
|
||||||
|
if (!shapes.ContainsKey(kvp.Key))
|
||||||
|
{
|
||||||
|
// Constant value
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
foreach (var (renderer, infos) in renderers)
|
var lastGroup = shapes[kvp.Key].actionGroups.LastOrDefault();
|
||||||
|
return lastGroup?.IsConstantActive == true && lastGroup.Value is float f && f > 0.5f;
|
||||||
|
})
|
||||||
|
.GroupBy(kvp => kvp.Key.TargetObject as SkinnedMeshRenderer)
|
||||||
|
.Select(grouping => (grouping.Key, grouping.Select(
|
||||||
|
kvp => kvp.Key.PropertyName.Substring(ReactiveObjectAnalyzer.DeletedShapePrefix.Length)
|
||||||
|
).ToList()))
|
||||||
|
.ToList();
|
||||||
|
foreach (var (renderer, shapeNamesToDelete) in renderers)
|
||||||
{
|
{
|
||||||
if (renderer == null) continue;
|
if (renderer == null) continue;
|
||||||
|
|
||||||
var mesh = renderer.sharedMesh;
|
var mesh = renderer.sharedMesh;
|
||||||
if (mesh == null) continue;
|
if (mesh == null) continue;
|
||||||
|
|
||||||
renderer.sharedMesh = RemoveBlendShapeFromMesh.RemoveBlendshapes(
|
var shapesToDelete = shapeNamesToDelete
|
||||||
mesh,
|
.Select(shape => mesh.GetBlendShapeIndex(shape))
|
||||||
infos
|
.Where(k => k >= 0)
|
||||||
.Select(i => mesh.GetBlendShapeIndex(i.PropertyName.Substring("blendShape.".Length)))
|
.ToList();
|
||||||
.Where(k => k >= 0)
|
|
||||||
.ToList()
|
renderer.sharedMesh = RemoveBlendShapeFromMesh.RemoveBlendshapes(mesh, shapesToDelete);
|
||||||
);
|
|
||||||
|
foreach (var name in shapeNamesToDelete)
|
||||||
|
{
|
||||||
|
// Don't need to animate this anymore...!
|
||||||
|
shapes.Remove(new TargetProp
|
||||||
|
{
|
||||||
|
TargetObject = renderer,
|
||||||
|
PropertyName = ReactiveObjectAnalyzer.BlendshapePrefix + name
|
||||||
|
});
|
||||||
|
|
||||||
|
shapes.Remove(new TargetProp
|
||||||
|
{
|
||||||
|
TargetObject = renderer,
|
||||||
|
PropertyName = ReactiveObjectAnalyzer.DeletedShapePrefix + name
|
||||||
|
});
|
||||||
|
|
||||||
|
initialStates.Remove(new TargetProp
|
||||||
|
{
|
||||||
|
TargetObject = renderer,
|
||||||
|
PropertyName = ReactiveObjectAnalyzer.BlendshapePrefix + name
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -257,10 +290,6 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
private void ProcessShapeKey(AnimatedProperty info)
|
private void ProcessShapeKey(AnimatedProperty info)
|
||||||
{
|
{
|
||||||
// TODO: prune non-animated keys
|
// TODO: prune non-animated keys
|
||||||
|
|
||||||
// Check if this is non-animated and skip most processing if so
|
|
||||||
if (info.alwaysDeleted || info.actionGroups[^1].IsConstant) return;
|
|
||||||
|
|
||||||
var asm = GenerateStateMachine(info);
|
var asm = GenerateStateMachine(info);
|
||||||
ApplyController(asm, "MA Responsive: " + info.TargetProp.TargetObject.name);
|
ApplyController(asm, "MA Responsive: " + info.TargetProp.TargetObject.name);
|
||||||
}
|
}
|
||||||
|
@ -72,8 +72,8 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
var analysis = ReactiveObjectAnalyzer.CachedAnalyze(context, avatarRoot);
|
var analysis = ReactiveObjectAnalyzer.CachedAnalyze(context, avatarRoot);
|
||||||
var shapes = analysis.Shapes;
|
var shapes = analysis.Shapes;
|
||||||
|
|
||||||
ImmutableDictionary<SkinnedMeshRenderer, ImmutableList<(int, float)>>.Builder rendererStates =
|
var rendererStates =
|
||||||
ImmutableDictionary.CreateBuilder<SkinnedMeshRenderer, ImmutableList<(int, float)>>(
|
ImmutableDictionary.CreateBuilder<SkinnedMeshRenderer, ImmutableDictionary<int, float>>(
|
||||||
|
|
||||||
);
|
);
|
||||||
var avatarRootTransform = avatarRoot.transform;
|
var avatarRootTransform = avatarRoot.transform;
|
||||||
@ -83,16 +83,29 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
var target = prop.TargetProp;
|
var target = prop.TargetProp;
|
||||||
if (target.TargetObject == null || target.TargetObject is not SkinnedMeshRenderer r) continue;
|
if (target.TargetObject == null || target.TargetObject is not SkinnedMeshRenderer r) continue;
|
||||||
if (!r.transform.IsChildOf(avatarRootTransform)) continue;
|
if (!r.transform.IsChildOf(avatarRootTransform)) continue;
|
||||||
if (!target.PropertyName.StartsWith("blendShape.")) continue;
|
|
||||||
|
|
||||||
|
var isDelete = false;
|
||||||
|
string shapeName = null;
|
||||||
|
if (target.PropertyName.StartsWith(ReactiveObjectAnalyzer.DeletedShapePrefix))
|
||||||
|
{
|
||||||
|
isDelete = true;
|
||||||
|
shapeName = target.PropertyName.Substring(ReactiveObjectAnalyzer.DeletedShapePrefix.Length);
|
||||||
|
}
|
||||||
|
else if (target.PropertyName.StartsWith(ReactiveObjectAnalyzer.BlendshapePrefix))
|
||||||
|
{
|
||||||
|
shapeName = target.PropertyName.Substring(ReactiveObjectAnalyzer.BlendshapePrefix.Length);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
var mesh = r.sharedMesh;
|
var mesh = r.sharedMesh;
|
||||||
if (mesh == null) continue;
|
if (mesh == null) continue;
|
||||||
|
|
||||||
var shapeName = target.PropertyName.Substring("blendShape.".Length);
|
|
||||||
|
|
||||||
if (!rendererStates.TryGetValue(r, out var states))
|
if (!rendererStates.TryGetValue(r, out var states))
|
||||||
{
|
{
|
||||||
states = ImmutableList<(int, float)>.Empty;
|
states = ImmutableDictionary<int, float>.Empty;
|
||||||
rendererStates[r] = states;
|
rendererStates[r] = states;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -103,15 +116,30 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
if (activeRule == null || activeRule.Value is not float value) continue;
|
if (activeRule == null || activeRule.Value is not float value) continue;
|
||||||
if (activeRule.ControllingObject == null) continue; // default value is being inherited
|
if (activeRule.ControllingObject == null) continue; // default value is being inherited
|
||||||
|
|
||||||
value = Math.Clamp(value, 0, 100);
|
if (isDelete)
|
||||||
|
{
|
||||||
if (activeRule.IsDelete) value = -1;
|
if (value < 0.5f) continue;
|
||||||
|
value = -1;
|
||||||
states = states.Add((index, value));
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (states.ContainsKey(index))
|
||||||
|
{
|
||||||
|
// Delete takes precedence over set in preview
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
value = Math.Clamp(value, 0, 100);
|
||||||
|
}
|
||||||
|
|
||||||
|
states = states.SetItem(index, value);
|
||||||
rendererStates[r] = states;
|
rendererStates[r] = states;
|
||||||
}
|
}
|
||||||
|
|
||||||
return rendererStates.ToImmutableDictionary();
|
return rendererStates.ToImmutableDictionary(
|
||||||
|
kvp => kvp.Key,
|
||||||
|
kvp => kvp.Value.Select(shapePair => (shapePair.Key, shapePair.Value)
|
||||||
|
).ToImmutableList());
|
||||||
}
|
}
|
||||||
|
|
||||||
private IEnumerable<RenderGroup> ShapesToGroups(GameObject avatarRoot, ImmutableDictionary<SkinnedMeshRenderer, ImmutableList<(int, float)>> shapes)
|
private IEnumerable<RenderGroup> ShapesToGroups(GameObject avatarRoot, ImmutableDictionary<SkinnedMeshRenderer, ImmutableList<(int, float)>> shapes)
|
||||||
|
@ -471,7 +471,7 @@ namespace nadena.dev.modular_avatar.core.editor.Simulator
|
|||||||
var f_set_inactive = effectGroup.Q<VisualElement>("effect__set-inactive");
|
var f_set_inactive = effectGroup.Q<VisualElement>("effect__set-inactive");
|
||||||
var f_value = effectGroup.Q<FloatField>("effect__value");
|
var f_value = effectGroup.Q<FloatField>("effect__value");
|
||||||
var f_material = effectGroup.Q<ObjectField>("effect__material");
|
var f_material = effectGroup.Q<ObjectField>("effect__material");
|
||||||
var f_delete = effectGroup.Q("effect__deleted");
|
var f_delete = effectGroup.Q<TextField>("effect__deleted");
|
||||||
|
|
||||||
f_target_component.style.display = DisplayStyle.None;
|
f_target_component.style.display = DisplayStyle.None;
|
||||||
f_target_component.SetEnabled(false);
|
f_target_component.SetEnabled(false);
|
||||||
@ -504,9 +504,10 @@ namespace nadena.dev.modular_avatar.core.editor.Simulator
|
|||||||
f_property.value = targetProp.PropertyName;
|
f_property.value = targetProp.PropertyName;
|
||||||
f_property.style.display = DisplayStyle.Flex;
|
f_property.style.display = DisplayStyle.Flex;
|
||||||
|
|
||||||
if (reactionRule.IsDelete)
|
if (reactionRule.TargetProp.PropertyName.StartsWith(ReactiveObjectAnalyzer.DeletedShapePrefix))
|
||||||
{
|
{
|
||||||
f_delete.style.display = DisplayStyle.Flex;
|
f_delete.style.display = DisplayStyle.Flex;
|
||||||
|
f_delete.value = reactionRule.Value is > 0.5f ? "DELETE" : "RETAIN";
|
||||||
} else if (reactionRule.Value is float f)
|
} else if (reactionRule.Value is float f)
|
||||||
{
|
{
|
||||||
f_value.SetValueWithoutNotify(f);
|
f_value.SetValueWithoutNotify(f);
|
||||||
|
666
UnitTests~/ReactiveComponent/DeletionTest.prefab
Normal file
666
UnitTests~/ReactiveComponent/DeletionTest.prefab
Normal file
@ -0,0 +1,666 @@
|
|||||||
|
%YAML 1.1
|
||||||
|
%TAG !u! tag:unity3d.com,2011:
|
||||||
|
--- !u!1 &2464504760772767737
|
||||||
|
GameObject:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
serializedVersion: 6
|
||||||
|
m_Component:
|
||||||
|
- component: {fileID: 3251791125987375227}
|
||||||
|
- component: {fileID: 6611954401356246169}
|
||||||
|
- component: {fileID: 4257580493320060063}
|
||||||
|
- component: {fileID: 7095484051158404692}
|
||||||
|
m_Layer: 0
|
||||||
|
m_Name: DeletionTest
|
||||||
|
m_TagString: Untagged
|
||||||
|
m_Icon: {fileID: 0}
|
||||||
|
m_NavMeshLayer: 0
|
||||||
|
m_StaticEditorFlags: 0
|
||||||
|
m_IsActive: 1
|
||||||
|
--- !u!4 &3251791125987375227
|
||||||
|
Transform:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 2464504760772767737}
|
||||||
|
serializedVersion: 2
|
||||||
|
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||||
|
m_LocalPosition: {x: 0.06867766, y: 0.7869835, z: -0.57959247}
|
||||||
|
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||||
|
m_ConstrainProportionsScale: 1
|
||||||
|
m_Children:
|
||||||
|
- {fileID: 8671858138418525756}
|
||||||
|
- {fileID: 3787319563290092876}
|
||||||
|
- {fileID: 2780879708549973278}
|
||||||
|
- {fileID: 6867583134219554799}
|
||||||
|
- {fileID: 3617623734196600728}
|
||||||
|
m_Father: {fileID: 0}
|
||||||
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
|
--- !u!95 &6611954401356246169
|
||||||
|
Animator:
|
||||||
|
serializedVersion: 5
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 2464504760772767737}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_Avatar: {fileID: 0}
|
||||||
|
m_Controller: {fileID: 0}
|
||||||
|
m_CullingMode: 0
|
||||||
|
m_UpdateMode: 0
|
||||||
|
m_ApplyRootMotion: 0
|
||||||
|
m_LinearVelocityBlending: 0
|
||||||
|
m_StabilizeFeet: 0
|
||||||
|
m_WarningMessage:
|
||||||
|
m_HasTransformHierarchy: 1
|
||||||
|
m_AllowConstantClipSamplingOptimization: 1
|
||||||
|
m_KeepAnimatorStateOnDisable: 0
|
||||||
|
m_WriteDefaultValuesOnDisable: 0
|
||||||
|
--- !u!114 &4257580493320060063
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 2464504760772767737}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 542108242, guid: 67cc4cb7839cd3741b63733d5adf0442, type: 3}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier:
|
||||||
|
Name:
|
||||||
|
ViewPosition: {x: 0, y: 1.6, z: 0.2}
|
||||||
|
Animations: 0
|
||||||
|
ScaleIPD: 1
|
||||||
|
lipSync: 0
|
||||||
|
lipSyncJawBone: {fileID: 0}
|
||||||
|
lipSyncJawClosed: {x: 0, y: 0, z: 0, w: 1}
|
||||||
|
lipSyncJawOpen: {x: 0, y: 0, z: 0, w: 1}
|
||||||
|
VisemeSkinnedMesh: {fileID: 0}
|
||||||
|
MouthOpenBlendShapeName: Facial_Blends.Jaw_Down
|
||||||
|
VisemeBlendShapes: []
|
||||||
|
unityVersion:
|
||||||
|
portraitCameraPositionOffset: {x: 0, y: 0, z: 0}
|
||||||
|
portraitCameraRotationOffset: {x: 0, y: 1, z: 0, w: -0.00000004371139}
|
||||||
|
networkIDs: []
|
||||||
|
customExpressions: 0
|
||||||
|
expressionsMenu: {fileID: 0}
|
||||||
|
expressionParameters: {fileID: 0}
|
||||||
|
enableEyeLook: 0
|
||||||
|
customEyeLookSettings:
|
||||||
|
eyeMovement:
|
||||||
|
confidence: 0.5
|
||||||
|
excitement: 0.5
|
||||||
|
leftEye: {fileID: 0}
|
||||||
|
rightEye: {fileID: 0}
|
||||||
|
eyesLookingStraight:
|
||||||
|
linked: 1
|
||||||
|
left: {x: 0, y: 0, z: 0, w: 0}
|
||||||
|
right: {x: 0, y: 0, z: 0, w: 0}
|
||||||
|
eyesLookingUp:
|
||||||
|
linked: 1
|
||||||
|
left: {x: 0, y: 0, z: 0, w: 0}
|
||||||
|
right: {x: 0, y: 0, z: 0, w: 0}
|
||||||
|
eyesLookingDown:
|
||||||
|
linked: 1
|
||||||
|
left: {x: 0, y: 0, z: 0, w: 0}
|
||||||
|
right: {x: 0, y: 0, z: 0, w: 0}
|
||||||
|
eyesLookingLeft:
|
||||||
|
linked: 1
|
||||||
|
left: {x: 0, y: 0, z: 0, w: 0}
|
||||||
|
right: {x: 0, y: 0, z: 0, w: 0}
|
||||||
|
eyesLookingRight:
|
||||||
|
linked: 1
|
||||||
|
left: {x: 0, y: 0, z: 0, w: 0}
|
||||||
|
right: {x: 0, y: 0, z: 0, w: 0}
|
||||||
|
eyelidType: 0
|
||||||
|
upperLeftEyelid: {fileID: 0}
|
||||||
|
upperRightEyelid: {fileID: 0}
|
||||||
|
lowerLeftEyelid: {fileID: 0}
|
||||||
|
lowerRightEyelid: {fileID: 0}
|
||||||
|
eyelidsDefault:
|
||||||
|
upper:
|
||||||
|
linked: 1
|
||||||
|
left: {x: 0, y: 0, z: 0, w: 0}
|
||||||
|
right: {x: 0, y: 0, z: 0, w: 0}
|
||||||
|
lower:
|
||||||
|
linked: 1
|
||||||
|
left: {x: 0, y: 0, z: 0, w: 0}
|
||||||
|
right: {x: 0, y: 0, z: 0, w: 0}
|
||||||
|
eyelidsClosed:
|
||||||
|
upper:
|
||||||
|
linked: 1
|
||||||
|
left: {x: 0, y: 0, z: 0, w: 0}
|
||||||
|
right: {x: 0, y: 0, z: 0, w: 0}
|
||||||
|
lower:
|
||||||
|
linked: 1
|
||||||
|
left: {x: 0, y: 0, z: 0, w: 0}
|
||||||
|
right: {x: 0, y: 0, z: 0, w: 0}
|
||||||
|
eyelidsLookingUp:
|
||||||
|
upper:
|
||||||
|
linked: 1
|
||||||
|
left: {x: 0, y: 0, z: 0, w: 0}
|
||||||
|
right: {x: 0, y: 0, z: 0, w: 0}
|
||||||
|
lower:
|
||||||
|
linked: 1
|
||||||
|
left: {x: 0, y: 0, z: 0, w: 0}
|
||||||
|
right: {x: 0, y: 0, z: 0, w: 0}
|
||||||
|
eyelidsLookingDown:
|
||||||
|
upper:
|
||||||
|
linked: 1
|
||||||
|
left: {x: 0, y: 0, z: 0, w: 0}
|
||||||
|
right: {x: 0, y: 0, z: 0, w: 0}
|
||||||
|
lower:
|
||||||
|
linked: 1
|
||||||
|
left: {x: 0, y: 0, z: 0, w: 0}
|
||||||
|
right: {x: 0, y: 0, z: 0, w: 0}
|
||||||
|
eyelidsSkinnedMesh: {fileID: 0}
|
||||||
|
eyelidsBlendshapes:
|
||||||
|
customizeAnimationLayers: 0
|
||||||
|
baseAnimationLayers:
|
||||||
|
- isEnabled: 0
|
||||||
|
type: 0
|
||||||
|
animatorController: {fileID: 0}
|
||||||
|
mask: {fileID: 0}
|
||||||
|
isDefault: 1
|
||||||
|
- isEnabled: 0
|
||||||
|
type: 4
|
||||||
|
animatorController: {fileID: 0}
|
||||||
|
mask: {fileID: 0}
|
||||||
|
isDefault: 1
|
||||||
|
- isEnabled: 0
|
||||||
|
type: 5
|
||||||
|
animatorController: {fileID: 0}
|
||||||
|
mask: {fileID: 0}
|
||||||
|
isDefault: 1
|
||||||
|
specialAnimationLayers:
|
||||||
|
- isEnabled: 0
|
||||||
|
type: 6
|
||||||
|
animatorController: {fileID: 0}
|
||||||
|
mask: {fileID: 0}
|
||||||
|
isDefault: 1
|
||||||
|
- isEnabled: 0
|
||||||
|
type: 7
|
||||||
|
animatorController: {fileID: 0}
|
||||||
|
mask: {fileID: 0}
|
||||||
|
isDefault: 1
|
||||||
|
- isEnabled: 0
|
||||||
|
type: 8
|
||||||
|
animatorController: {fileID: 0}
|
||||||
|
mask: {fileID: 0}
|
||||||
|
isDefault: 1
|
||||||
|
AnimationPreset: {fileID: 0}
|
||||||
|
animationHashSet: []
|
||||||
|
autoFootsteps: 1
|
||||||
|
autoLocomotion: 1
|
||||||
|
collider_head:
|
||||||
|
isMirrored: 1
|
||||||
|
state: 0
|
||||||
|
transform: {fileID: 0}
|
||||||
|
radius: 0
|
||||||
|
height: 0
|
||||||
|
position: {x: 0, y: 0, z: 0}
|
||||||
|
rotation: {x: 0, y: 0, z: 0, w: 1}
|
||||||
|
collider_torso:
|
||||||
|
isMirrored: 1
|
||||||
|
state: 0
|
||||||
|
transform: {fileID: 0}
|
||||||
|
radius: 0
|
||||||
|
height: 0
|
||||||
|
position: {x: 0, y: 0, z: 0}
|
||||||
|
rotation: {x: 0, y: 0, z: 0, w: 1}
|
||||||
|
collider_footR:
|
||||||
|
isMirrored: 1
|
||||||
|
state: 0
|
||||||
|
transform: {fileID: 0}
|
||||||
|
radius: 0
|
||||||
|
height: 0
|
||||||
|
position: {x: 0, y: 0, z: 0}
|
||||||
|
rotation: {x: 0, y: 0, z: 0, w: 1}
|
||||||
|
collider_footL:
|
||||||
|
isMirrored: 1
|
||||||
|
state: 0
|
||||||
|
transform: {fileID: 0}
|
||||||
|
radius: 0
|
||||||
|
height: 0
|
||||||
|
position: {x: 0, y: 0, z: 0}
|
||||||
|
rotation: {x: 0, y: 0, z: 0, w: 1}
|
||||||
|
collider_handR:
|
||||||
|
isMirrored: 1
|
||||||
|
state: 0
|
||||||
|
transform: {fileID: 0}
|
||||||
|
radius: 0
|
||||||
|
height: 0
|
||||||
|
position: {x: 0, y: 0, z: 0}
|
||||||
|
rotation: {x: 0, y: 0, z: 0, w: 1}
|
||||||
|
collider_handL:
|
||||||
|
isMirrored: 1
|
||||||
|
state: 0
|
||||||
|
transform: {fileID: 0}
|
||||||
|
radius: 0
|
||||||
|
height: 0
|
||||||
|
position: {x: 0, y: 0, z: 0}
|
||||||
|
rotation: {x: 0, y: 0, z: 0, w: 1}
|
||||||
|
collider_fingerIndexL:
|
||||||
|
isMirrored: 1
|
||||||
|
state: 0
|
||||||
|
transform: {fileID: 0}
|
||||||
|
radius: 0
|
||||||
|
height: 0
|
||||||
|
position: {x: 0, y: 0, z: 0}
|
||||||
|
rotation: {x: 0, y: 0, z: 0, w: 1}
|
||||||
|
collider_fingerMiddleL:
|
||||||
|
isMirrored: 1
|
||||||
|
state: 0
|
||||||
|
transform: {fileID: 0}
|
||||||
|
radius: 0
|
||||||
|
height: 0
|
||||||
|
position: {x: 0, y: 0, z: 0}
|
||||||
|
rotation: {x: 0, y: 0, z: 0, w: 1}
|
||||||
|
collider_fingerRingL:
|
||||||
|
isMirrored: 1
|
||||||
|
state: 0
|
||||||
|
transform: {fileID: 0}
|
||||||
|
radius: 0
|
||||||
|
height: 0
|
||||||
|
position: {x: 0, y: 0, z: 0}
|
||||||
|
rotation: {x: 0, y: 0, z: 0, w: 1}
|
||||||
|
collider_fingerLittleL:
|
||||||
|
isMirrored: 1
|
||||||
|
state: 0
|
||||||
|
transform: {fileID: 0}
|
||||||
|
radius: 0
|
||||||
|
height: 0
|
||||||
|
position: {x: 0, y: 0, z: 0}
|
||||||
|
rotation: {x: 0, y: 0, z: 0, w: 1}
|
||||||
|
collider_fingerIndexR:
|
||||||
|
isMirrored: 1
|
||||||
|
state: 0
|
||||||
|
transform: {fileID: 0}
|
||||||
|
radius: 0
|
||||||
|
height: 0
|
||||||
|
position: {x: 0, y: 0, z: 0}
|
||||||
|
rotation: {x: 0, y: 0, z: 0, w: 1}
|
||||||
|
collider_fingerMiddleR:
|
||||||
|
isMirrored: 1
|
||||||
|
state: 0
|
||||||
|
transform: {fileID: 0}
|
||||||
|
radius: 0
|
||||||
|
height: 0
|
||||||
|
position: {x: 0, y: 0, z: 0}
|
||||||
|
rotation: {x: 0, y: 0, z: 0, w: 1}
|
||||||
|
collider_fingerRingR:
|
||||||
|
isMirrored: 1
|
||||||
|
state: 0
|
||||||
|
transform: {fileID: 0}
|
||||||
|
radius: 0
|
||||||
|
height: 0
|
||||||
|
position: {x: 0, y: 0, z: 0}
|
||||||
|
rotation: {x: 0, y: 0, z: 0, w: 1}
|
||||||
|
collider_fingerLittleR:
|
||||||
|
isMirrored: 1
|
||||||
|
state: 0
|
||||||
|
transform: {fileID: 0}
|
||||||
|
radius: 0
|
||||||
|
height: 0
|
||||||
|
position: {x: 0, y: 0, z: 0}
|
||||||
|
rotation: {x: 0, y: 0, z: 0, w: 1}
|
||||||
|
--- !u!114 &7095484051158404692
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 2464504760772767737}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: -1427037861, guid: 4ecd63eff847044b68db9453ce219299, type: 3}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier:
|
||||||
|
launchedFromSDKPipeline: 0
|
||||||
|
completedSDKPipeline: 0
|
||||||
|
blueprintId:
|
||||||
|
contentType: 0
|
||||||
|
assetBundleUnityVersion:
|
||||||
|
fallbackStatus: 0
|
||||||
|
--- !u!1 &3134446681435896768
|
||||||
|
GameObject:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
serializedVersion: 6
|
||||||
|
m_Component:
|
||||||
|
- component: {fileID: 2780879708549973278}
|
||||||
|
- component: {fileID: 2470606632396626262}
|
||||||
|
m_Layer: 0
|
||||||
|
m_Name: Delete
|
||||||
|
m_TagString: Untagged
|
||||||
|
m_Icon: {fileID: 0}
|
||||||
|
m_NavMeshLayer: 0
|
||||||
|
m_StaticEditorFlags: 0
|
||||||
|
m_IsActive: 1
|
||||||
|
--- !u!4 &2780879708549973278
|
||||||
|
Transform:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 3134446681435896768}
|
||||||
|
serializedVersion: 2
|
||||||
|
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||||
|
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||||
|
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||||
|
m_ConstrainProportionsScale: 1
|
||||||
|
m_Children: []
|
||||||
|
m_Father: {fileID: 3251791125987375227}
|
||||||
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
|
--- !u!114 &2470606632396626262
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 3134446681435896768}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: 2db441f589c3407bb6fb5f02ff8ab541, type: 3}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier:
|
||||||
|
m_inverted: 0
|
||||||
|
m_shapes:
|
||||||
|
- Object:
|
||||||
|
referencePath: shape deletion test mesh
|
||||||
|
targetObject: {fileID: 0}
|
||||||
|
ShapeName: bottom
|
||||||
|
ChangeType: 0
|
||||||
|
Value: 50
|
||||||
|
--- !u!1 &7874409458034691206
|
||||||
|
GameObject:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
serializedVersion: 6
|
||||||
|
m_Component:
|
||||||
|
- component: {fileID: 3787319563290092876}
|
||||||
|
- component: {fileID: 8462455628590652122}
|
||||||
|
m_Layer: 0
|
||||||
|
m_Name: PriorSet
|
||||||
|
m_TagString: Untagged
|
||||||
|
m_Icon: {fileID: 0}
|
||||||
|
m_NavMeshLayer: 0
|
||||||
|
m_StaticEditorFlags: 0
|
||||||
|
m_IsActive: 1
|
||||||
|
--- !u!4 &3787319563290092876
|
||||||
|
Transform:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 7874409458034691206}
|
||||||
|
serializedVersion: 2
|
||||||
|
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||||
|
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||||
|
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||||
|
m_ConstrainProportionsScale: 1
|
||||||
|
m_Children: []
|
||||||
|
m_Father: {fileID: 3251791125987375227}
|
||||||
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
|
--- !u!114 &8462455628590652122
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 7874409458034691206}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: 2db441f589c3407bb6fb5f02ff8ab541, type: 3}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier:
|
||||||
|
m_inverted: 0
|
||||||
|
m_shapes:
|
||||||
|
- Object:
|
||||||
|
referencePath: shape deletion test mesh
|
||||||
|
targetObject: {fileID: 0}
|
||||||
|
ShapeName: bottom
|
||||||
|
ChangeType: 1
|
||||||
|
Value: 50
|
||||||
|
--- !u!1 &7956182162252432618
|
||||||
|
GameObject:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
serializedVersion: 6
|
||||||
|
m_Component:
|
||||||
|
- component: {fileID: 3617623734196600728}
|
||||||
|
- component: {fileID: 4167915178638071617}
|
||||||
|
- component: {fileID: 3280847981733507148}
|
||||||
|
m_Layer: 0
|
||||||
|
m_Name: MenuSet
|
||||||
|
m_TagString: Untagged
|
||||||
|
m_Icon: {fileID: 0}
|
||||||
|
m_NavMeshLayer: 0
|
||||||
|
m_StaticEditorFlags: 0
|
||||||
|
m_IsActive: 0
|
||||||
|
--- !u!4 &3617623734196600728
|
||||||
|
Transform:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 7956182162252432618}
|
||||||
|
serializedVersion: 2
|
||||||
|
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||||
|
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||||
|
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||||
|
m_ConstrainProportionsScale: 1
|
||||||
|
m_Children: []
|
||||||
|
m_Father: {fileID: 3251791125987375227}
|
||||||
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
|
--- !u!114 &4167915178638071617
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 7956182162252432618}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: 2db441f589c3407bb6fb5f02ff8ab541, type: 3}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier:
|
||||||
|
m_inverted: 0
|
||||||
|
m_shapes:
|
||||||
|
- Object:
|
||||||
|
referencePath: shape deletion test mesh
|
||||||
|
targetObject: {fileID: 0}
|
||||||
|
ShapeName: bottom
|
||||||
|
ChangeType: 1
|
||||||
|
Value: 0
|
||||||
|
--- !u!114 &3280847981733507148
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 7956182162252432618}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: 3b29d45007c5493d926d2cd45a489529, type: 3}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier:
|
||||||
|
Control:
|
||||||
|
name:
|
||||||
|
icon: {fileID: 0}
|
||||||
|
type: 102
|
||||||
|
parameter:
|
||||||
|
name:
|
||||||
|
value: 1
|
||||||
|
style: 0
|
||||||
|
subMenu: {fileID: 0}
|
||||||
|
subParameters: []
|
||||||
|
labels: []
|
||||||
|
MenuSource: 1
|
||||||
|
menuSource_otherObjectChildren: {fileID: 0}
|
||||||
|
isSynced: 1
|
||||||
|
isSaved: 1
|
||||||
|
isDefault: 0
|
||||||
|
automaticValue: 1
|
||||||
|
--- !u!1 &8389945206789797712
|
||||||
|
GameObject:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
serializedVersion: 6
|
||||||
|
m_Component:
|
||||||
|
- component: {fileID: 6867583134219554799}
|
||||||
|
- component: {fileID: 8099891503683627458}
|
||||||
|
m_Layer: 0
|
||||||
|
m_Name: NullSet
|
||||||
|
m_TagString: Untagged
|
||||||
|
m_Icon: {fileID: 0}
|
||||||
|
m_NavMeshLayer: 0
|
||||||
|
m_StaticEditorFlags: 0
|
||||||
|
m_IsActive: 0
|
||||||
|
--- !u!4 &6867583134219554799
|
||||||
|
Transform:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 8389945206789797712}
|
||||||
|
serializedVersion: 2
|
||||||
|
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||||
|
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||||
|
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||||
|
m_ConstrainProportionsScale: 1
|
||||||
|
m_Children: []
|
||||||
|
m_Father: {fileID: 3251791125987375227}
|
||||||
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
|
--- !u!114 &8099891503683627458
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 8389945206789797712}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: 2db441f589c3407bb6fb5f02ff8ab541, type: 3}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier:
|
||||||
|
m_inverted: 0
|
||||||
|
m_shapes:
|
||||||
|
- Object:
|
||||||
|
referencePath: shape deletion test mesh
|
||||||
|
targetObject: {fileID: 0}
|
||||||
|
ShapeName: bottom
|
||||||
|
ChangeType: 1
|
||||||
|
Value: 0
|
||||||
|
--- !u!1001 &9210451080691405271
|
||||||
|
PrefabInstance:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
serializedVersion: 2
|
||||||
|
m_Modification:
|
||||||
|
serializedVersion: 3
|
||||||
|
m_TransformParent: {fileID: 3251791125987375227}
|
||||||
|
m_Modifications:
|
||||||
|
- target: {fileID: -8679921383154817045, guid: fe5b76dae94c07345b74d51e9a9a8440,
|
||||||
|
type: 3}
|
||||||
|
propertyPath: m_LocalPosition.x
|
||||||
|
value: -0
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: -8679921383154817045, guid: fe5b76dae94c07345b74d51e9a9a8440,
|
||||||
|
type: 3}
|
||||||
|
propertyPath: m_LocalPosition.y
|
||||||
|
value: 0
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: -8679921383154817045, guid: fe5b76dae94c07345b74d51e9a9a8440,
|
||||||
|
type: 3}
|
||||||
|
propertyPath: m_LocalPosition.z
|
||||||
|
value: 0
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: -8679921383154817045, guid: fe5b76dae94c07345b74d51e9a9a8440,
|
||||||
|
type: 3}
|
||||||
|
propertyPath: m_LocalRotation.w
|
||||||
|
value: 0.7071067
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: -8679921383154817045, guid: fe5b76dae94c07345b74d51e9a9a8440,
|
||||||
|
type: 3}
|
||||||
|
propertyPath: m_LocalRotation.x
|
||||||
|
value: -0.7071068
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: -8679921383154817045, guid: fe5b76dae94c07345b74d51e9a9a8440,
|
||||||
|
type: 3}
|
||||||
|
propertyPath: m_LocalRotation.y
|
||||||
|
value: 0
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: -8679921383154817045, guid: fe5b76dae94c07345b74d51e9a9a8440,
|
||||||
|
type: 3}
|
||||||
|
propertyPath: m_LocalRotation.z
|
||||||
|
value: -0
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: -8679921383154817045, guid: fe5b76dae94c07345b74d51e9a9a8440,
|
||||||
|
type: 3}
|
||||||
|
propertyPath: m_LocalEulerAnglesHint.x
|
||||||
|
value: 0
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: -8679921383154817045, guid: fe5b76dae94c07345b74d51e9a9a8440,
|
||||||
|
type: 3}
|
||||||
|
propertyPath: m_LocalEulerAnglesHint.y
|
||||||
|
value: 0
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: -8679921383154817045, guid: fe5b76dae94c07345b74d51e9a9a8440,
|
||||||
|
type: 3}
|
||||||
|
propertyPath: m_LocalEulerAnglesHint.z
|
||||||
|
value: 0
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: -3887185075125053422, guid: fe5b76dae94c07345b74d51e9a9a8440,
|
||||||
|
type: 3}
|
||||||
|
propertyPath: m_DirtyAABB
|
||||||
|
value: 0
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: -3887185075125053422, guid: fe5b76dae94c07345b74d51e9a9a8440,
|
||||||
|
type: 3}
|
||||||
|
propertyPath: m_AABB.m_Extent.x
|
||||||
|
value: 1
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: -3887185075125053422, guid: fe5b76dae94c07345b74d51e9a9a8440,
|
||||||
|
type: 3}
|
||||||
|
propertyPath: m_AABB.m_Extent.y
|
||||||
|
value: 1
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: -3887185075125053422, guid: fe5b76dae94c07345b74d51e9a9a8440,
|
||||||
|
type: 3}
|
||||||
|
propertyPath: m_AABB.m_Extent.z
|
||||||
|
value: 2
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: -3887185075125053422, guid: fe5b76dae94c07345b74d51e9a9a8440,
|
||||||
|
type: 3}
|
||||||
|
propertyPath: m_BlendShapeWeights.Array.data[0]
|
||||||
|
value: 0
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: 919132149155446097, guid: fe5b76dae94c07345b74d51e9a9a8440,
|
||||||
|
type: 3}
|
||||||
|
propertyPath: m_Name
|
||||||
|
value: shape deletion test mesh
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
m_RemovedComponents: []
|
||||||
|
m_RemovedGameObjects: []
|
||||||
|
m_AddedGameObjects: []
|
||||||
|
m_AddedComponents: []
|
||||||
|
m_SourcePrefab: {fileID: 100100000, guid: fe5b76dae94c07345b74d51e9a9a8440, type: 3}
|
||||||
|
--- !u!4 &8671858138418525756 stripped
|
||||||
|
Transform:
|
||||||
|
m_CorrespondingSourceObject: {fileID: -8679921383154817045, guid: fe5b76dae94c07345b74d51e9a9a8440,
|
||||||
|
type: 3}
|
||||||
|
m_PrefabInstance: {fileID: 9210451080691405271}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
7
UnitTests~/ReactiveComponent/DeletionTest.prefab.meta
Normal file
7
UnitTests~/ReactiveComponent/DeletionTest.prefab.meta
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: a82669288fc87d94db320a2494fd76c5
|
||||||
|
PrefabImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
98
UnitTests~/ReactiveComponent/ShapeDeletionAnalysis.cs
Normal file
98
UnitTests~/ReactiveComponent/ShapeDeletionAnalysis.cs
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using modular_avatar_tests;
|
||||||
|
using nadena.dev.modular_avatar.core;
|
||||||
|
using nadena.dev.modular_avatar.core.editor;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
public class ShapeDeletionAnalysis : TestBase
|
||||||
|
{
|
||||||
|
[Test]
|
||||||
|
public void BasicShapeDeletionAnalysis()
|
||||||
|
{
|
||||||
|
var root = CreatePrefab("DeletionTest.prefab");
|
||||||
|
|
||||||
|
var mesh = AssertPreviewDeletion(root);
|
||||||
|
|
||||||
|
AssertBuildDeletion(mesh, root);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void WhenShapeDeletionIsConditionedOnSubsequentChanger_DoesNotDelete()
|
||||||
|
{
|
||||||
|
var root = CreatePrefab("DeletionTest.prefab");
|
||||||
|
root.transform.Find("MenuSet").gameObject.SetActive(true);
|
||||||
|
|
||||||
|
AssertPreviewDeletion(root);
|
||||||
|
AssertNoMeshDeletion(root);
|
||||||
|
|
||||||
|
var mesh = root.GetComponentInChildren<SkinnedMeshRenderer>();
|
||||||
|
Assert.AreEqual(100, mesh.GetBlendShapeWeight(mesh.sharedMesh.GetBlendShapeIndex("bottom")));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void WhenShapeDeletionIsConditionedOnItself_DoesNotDelete()
|
||||||
|
{
|
||||||
|
var root = CreatePrefab("DeletionTest.prefab");
|
||||||
|
root.transform.Find("Delete").gameObject.AddComponent<ModularAvatarMenuItem>().InitSettings();
|
||||||
|
|
||||||
|
AssertNoPreviewDeletion(root);
|
||||||
|
AssertNoMeshDeletion(root);
|
||||||
|
|
||||||
|
var mesh = root.GetComponentInChildren<SkinnedMeshRenderer>();
|
||||||
|
// deletion action is initially off, so we use the shape changer above it, which is set to 50.
|
||||||
|
Assert.AreEqual(50f, mesh.GetBlendShapeWeight(mesh.sharedMesh.GetBlendShapeIndex("bottom")));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void AssertBuildDeletion(SkinnedMeshRenderer mesh, GameObject root)
|
||||||
|
{
|
||||||
|
var originalSharedMesh = mesh.sharedMesh;
|
||||||
|
AvatarProcessor.ProcessAvatar(root);
|
||||||
|
Assert.AreNotEqual(originalSharedMesh, mesh.sharedMesh);
|
||||||
|
|
||||||
|
Assert.IsTrue(mesh.sharedMesh.vertices.All(v => v.z >= 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static SkinnedMeshRenderer AssertPreviewDeletion(GameObject root)
|
||||||
|
{
|
||||||
|
var mesh = root.GetComponentInChildren<SkinnedMeshRenderer>();
|
||||||
|
var analysis = new ReactiveObjectAnalyzer().Analyze(root);
|
||||||
|
var deletedShape = analysis.Shapes.GetValueOrDefault(new TargetProp()
|
||||||
|
{
|
||||||
|
TargetObject = mesh,
|
||||||
|
PropertyName = "deletedShape.bottom"
|
||||||
|
});
|
||||||
|
Assert.IsNotNull(deletedShape);
|
||||||
|
var activeGroup = deletedShape.actionGroups.LastOrDefault(ag => ag.InitiallyActive);
|
||||||
|
Assert.AreEqual(1.0f, activeGroup?.Value);
|
||||||
|
return mesh;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void AssertNoPreviewDeletion(GameObject root)
|
||||||
|
{
|
||||||
|
var mesh = root.GetComponentInChildren<SkinnedMeshRenderer>();
|
||||||
|
var analysis = new ReactiveObjectAnalyzer().Analyze(root);
|
||||||
|
var deletedShape = analysis.Shapes.GetValueOrDefault(new TargetProp()
|
||||||
|
{
|
||||||
|
TargetObject = mesh,
|
||||||
|
PropertyName = "deletedShape.bottom"
|
||||||
|
});
|
||||||
|
if (deletedShape != null)
|
||||||
|
{
|
||||||
|
var activeGroup = deletedShape.actionGroups.LastOrDefault(ag => ag.InitiallyActive);
|
||||||
|
Assert.IsFalse(activeGroup?.Value is float f && f > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void AssertNoMeshDeletion(GameObject root)
|
||||||
|
{
|
||||||
|
var mesh = root.GetComponentInChildren<SkinnedMeshRenderer>();
|
||||||
|
var originalSharedMesh = mesh.sharedMesh;
|
||||||
|
AvatarProcessor.ProcessAvatar(root);
|
||||||
|
Assert.AreEqual(originalSharedMesh, mesh.sharedMesh);
|
||||||
|
}
|
||||||
|
}
|
11
UnitTests~/ReactiveComponent/ShapeDeletionAnalysis.cs.meta
Normal file
11
UnitTests~/ReactiveComponent/ShapeDeletionAnalysis.cs.meta
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 18eb55e1b66a00243a91142456dfd5f5
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
BIN
UnitTests~/ReactiveComponent/shape deletion test mesh.fbx
Normal file
BIN
UnitTests~/ReactiveComponent/shape deletion test mesh.fbx
Normal file
Binary file not shown.
109
UnitTests~/ReactiveComponent/shape deletion test mesh.fbx.meta
Normal file
109
UnitTests~/ReactiveComponent/shape deletion test mesh.fbx.meta
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: fe5b76dae94c07345b74d51e9a9a8440
|
||||||
|
ModelImporter:
|
||||||
|
serializedVersion: 22200
|
||||||
|
internalIDToNameTable: []
|
||||||
|
externalObjects: {}
|
||||||
|
materials:
|
||||||
|
materialImportMode: 2
|
||||||
|
materialName: 0
|
||||||
|
materialSearch: 1
|
||||||
|
materialLocation: 1
|
||||||
|
animations:
|
||||||
|
legacyGenerateAnimations: 4
|
||||||
|
bakeSimulation: 0
|
||||||
|
resampleCurves: 1
|
||||||
|
optimizeGameObjects: 0
|
||||||
|
removeConstantScaleCurves: 0
|
||||||
|
motionNodeName:
|
||||||
|
rigImportErrors:
|
||||||
|
rigImportWarnings:
|
||||||
|
animationImportErrors:
|
||||||
|
animationImportWarnings:
|
||||||
|
animationRetargetingWarnings:
|
||||||
|
animationDoRetargetingWarnings: 0
|
||||||
|
importAnimatedCustomProperties: 0
|
||||||
|
importConstraints: 0
|
||||||
|
animationCompression: 1
|
||||||
|
animationRotationError: 0.5
|
||||||
|
animationPositionError: 0.5
|
||||||
|
animationScaleError: 0.5
|
||||||
|
animationWrapMode: 0
|
||||||
|
extraExposedTransformPaths: []
|
||||||
|
extraUserProperties: []
|
||||||
|
clipAnimations: []
|
||||||
|
isReadable: 0
|
||||||
|
meshes:
|
||||||
|
lODScreenPercentages: []
|
||||||
|
globalScale: 1
|
||||||
|
meshCompression: 0
|
||||||
|
addColliders: 0
|
||||||
|
useSRGBMaterialColor: 1
|
||||||
|
sortHierarchyByName: 1
|
||||||
|
importPhysicalCameras: 1
|
||||||
|
importVisibility: 1
|
||||||
|
importBlendShapes: 1
|
||||||
|
importCameras: 1
|
||||||
|
importLights: 1
|
||||||
|
nodeNameCollisionStrategy: 1
|
||||||
|
fileIdsGeneration: 2
|
||||||
|
swapUVChannels: 0
|
||||||
|
generateSecondaryUV: 0
|
||||||
|
useFileUnits: 1
|
||||||
|
keepQuads: 0
|
||||||
|
weldVertices: 1
|
||||||
|
bakeAxisConversion: 0
|
||||||
|
preserveHierarchy: 0
|
||||||
|
skinWeightsMode: 0
|
||||||
|
maxBonesPerVertex: 4
|
||||||
|
minBoneWeight: 0.001
|
||||||
|
optimizeBones: 1
|
||||||
|
meshOptimizationFlags: -1
|
||||||
|
indexFormat: 0
|
||||||
|
secondaryUVAngleDistortion: 8
|
||||||
|
secondaryUVAreaDistortion: 15.000001
|
||||||
|
secondaryUVHardAngle: 88
|
||||||
|
secondaryUVMarginMethod: 1
|
||||||
|
secondaryUVMinLightmapResolution: 40
|
||||||
|
secondaryUVMinObjectScale: 1
|
||||||
|
secondaryUVPackMargin: 4
|
||||||
|
useFileScale: 1
|
||||||
|
strictVertexDataChecks: 0
|
||||||
|
tangentSpace:
|
||||||
|
normalSmoothAngle: 60
|
||||||
|
normalImportMode: 0
|
||||||
|
tangentImportMode: 3
|
||||||
|
normalCalculationMode: 4
|
||||||
|
legacyComputeAllNormalsFromSmoothingGroupsWhenMeshHasBlendShapes: 0
|
||||||
|
blendShapeNormalImportMode: 1
|
||||||
|
normalSmoothingSource: 0
|
||||||
|
referencedClips: []
|
||||||
|
importAnimation: 1
|
||||||
|
humanDescription:
|
||||||
|
serializedVersion: 3
|
||||||
|
human: []
|
||||||
|
skeleton: []
|
||||||
|
armTwist: 0.5
|
||||||
|
foreArmTwist: 0.5
|
||||||
|
upperLegTwist: 0.5
|
||||||
|
legTwist: 0.5
|
||||||
|
armStretch: 0.05
|
||||||
|
legStretch: 0.05
|
||||||
|
feetSpacing: 0
|
||||||
|
globalScale: 1
|
||||||
|
rootMotionBoneName:
|
||||||
|
hasTranslationDoF: 0
|
||||||
|
hasExtraRoot: 0
|
||||||
|
skeletonHasParents: 1
|
||||||
|
lastHumanDescriptionAvatarSource: {instanceID: 0}
|
||||||
|
autoGenerateAvatarMappingIfUnspecified: 1
|
||||||
|
animationType: 2
|
||||||
|
humanoidOversampling: 1
|
||||||
|
avatarSetup: 0
|
||||||
|
addHumanoidExtraRootOnlyWhenUsingAvatar: 1
|
||||||
|
importBlendShapeDeformPercent: 1
|
||||||
|
remapMaterialsIfMaterialImportModeIsNone: 0
|
||||||
|
additionalBone: 0
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
Loading…
Reference in New Issue
Block a user