mirror of
https://github.com/bdunderscore/modular-avatar.git
synced 2024-12-29 18:55:06 +08:00
chore: update for new preview system API (#877)
This commit is contained in:
parent
a0f27ba70f
commit
d725ade36d
2
.github/ProjectRoot/vpm-manifest-2022.json
vendored
2
.github/ProjectRoot/vpm-manifest-2022.json
vendored
@ -19,7 +19,7 @@
|
|||||||
"dependencies": {}
|
"dependencies": {}
|
||||||
},
|
},
|
||||||
"nadena.dev.ndmf": {
|
"nadena.dev.ndmf": {
|
||||||
"version": "1.5.0-alpha.0"
|
"version": "1.5.0-alpha.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -4,6 +4,7 @@ using System.Collections.Generic;
|
|||||||
using UnityEditor;
|
using UnityEditor;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEngine.SceneManagement;
|
using UnityEngine.SceneManagement;
|
||||||
|
using Object = UnityEngine.Object;
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
@ -12,6 +13,7 @@ namespace nadena.dev.modular_avatar.core.editor.ScaleAdjuster
|
|||||||
internal class ScaleAdjustedBones
|
internal class ScaleAdjustedBones
|
||||||
{
|
{
|
||||||
private static int editorFrameCount = 0;
|
private static int editorFrameCount = 0;
|
||||||
|
private static int lastUpdateFrame = 0;
|
||||||
private static int lastMutatingUpdate = 0;
|
private static int lastMutatingUpdate = 0;
|
||||||
private static int mutatingUpdateCount = 0;
|
private static int mutatingUpdateCount = 0;
|
||||||
|
|
||||||
@ -32,6 +34,16 @@ namespace nadena.dev.modular_avatar.core.editor.ScaleAdjuster
|
|||||||
private Dictionary<Component, BoneState> _bones = new(new ObjectIdentityComparer<Component>());
|
private Dictionary<Component, BoneState> _bones = new(new ObjectIdentityComparer<Component>());
|
||||||
//private List<BoneState> _states = new List<BoneState>();
|
//private List<BoneState> _states = new List<BoneState>();
|
||||||
|
|
||||||
|
public void Clear()
|
||||||
|
{
|
||||||
|
foreach (var state in _bones.Values)
|
||||||
|
{
|
||||||
|
if (state.proxy != null) Object.DestroyImmediate(state.proxy.gameObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
_bones.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
public BoneState GetBone(Component src, bool force = true)
|
public BoneState GetBone(Component src, bool force = true)
|
||||||
{
|
{
|
||||||
if (src == null) return null;
|
if (src == null) return null;
|
||||||
@ -70,6 +82,13 @@ namespace nadena.dev.modular_avatar.core.editor.ScaleAdjuster
|
|||||||
|
|
||||||
public void Update()
|
public void Update()
|
||||||
{
|
{
|
||||||
|
if (lastUpdateFrame == editorFrameCount)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
lastUpdateFrame = editorFrameCount;
|
||||||
|
|
||||||
if (lastMutatingUpdate != editorFrameCount)
|
if (lastMutatingUpdate != editorFrameCount)
|
||||||
{
|
{
|
||||||
mutatingUpdateCount++;
|
mutatingUpdateCount++;
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.Immutable;
|
using System.Collections.Immutable;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using nadena.dev.modular_avatar.core.editor.ScaleAdjuster;
|
using nadena.dev.modular_avatar.core.editor.ScaleAdjuster;
|
||||||
using nadena.dev.ndmf.preview;
|
using nadena.dev.ndmf.preview;
|
||||||
using nadena.dev.ndmf.rq;
|
using nadena.dev.ndmf.rq;
|
||||||
@ -16,7 +17,6 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
{
|
{
|
||||||
internal class ScaleAdjusterPreview : IRenderFilter
|
internal class ScaleAdjusterPreview : IRenderFilter
|
||||||
{
|
{
|
||||||
private ScaleAdjustedBones _bones = new ScaleAdjustedBones();
|
|
||||||
|
|
||||||
[InitializeOnLoadMethod]
|
[InitializeOnLoadMethod]
|
||||||
private static void StaticInit()
|
private static void StaticInit()
|
||||||
@ -64,6 +64,23 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
return targets.Select(r => (IImmutableList<Renderer>)ImmutableList.Create(r)).ToImmutableList();
|
return targets.Select(r => (IImmutableList<Renderer>)ImmutableList.Create(r)).ToImmutableList();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
public Task<IRenderFilterNode> Instantiate(IEnumerable<(Renderer, Renderer)> proxyPairs, ComputeContext context)
|
||||||
|
{
|
||||||
|
return Task.FromResult((IRenderFilterNode)new ScaleAdjusterPreviewNode());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class ScaleAdjusterPreviewNode : IRenderFilterNode
|
||||||
|
{
|
||||||
|
private static ScaleAdjustedBones _bones = new ScaleAdjustedBones();
|
||||||
|
|
||||||
|
public ScaleAdjusterPreviewNode()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public ulong Reads => IRenderFilterNode.Shapes;
|
||||||
|
public ulong WhatChanged => IRenderFilterNode.Shapes;
|
||||||
|
|
||||||
public void OnFrame(Renderer original, Renderer proxy)
|
public void OnFrame(Renderer original, Renderer proxy)
|
||||||
{
|
{
|
||||||
if (proxy is SkinnedMeshRenderer p_smr && original is SkinnedMeshRenderer o_smr)
|
if (proxy is SkinnedMeshRenderer p_smr && original is SkinnedMeshRenderer o_smr)
|
||||||
@ -78,6 +95,10 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
|
|
||||||
_bones.Update();
|
_bones.Update();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
_bones.Clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
@ -1,5 +1,6 @@
|
|||||||
#region
|
#region
|
||||||
|
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.Immutable;
|
using System.Collections.Immutable;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@ -8,6 +9,7 @@ using nadena.dev.ndmf.preview;
|
|||||||
using nadena.dev.ndmf.rq;
|
using nadena.dev.ndmf.rq;
|
||||||
using nadena.dev.ndmf.rq.unity.editor;
|
using nadena.dev.ndmf.rq.unity.editor;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
using Object = UnityEngine.Object;
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
@ -31,6 +33,8 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
{
|
{
|
||||||
// TODO: observe avatar root
|
// TODO: observe avatar root
|
||||||
ctx.Observe(changer);
|
ctx.Observe(changer);
|
||||||
|
if (!ctx.ActiveAndEnabled(changer)) continue;
|
||||||
|
|
||||||
var target = ctx.Observe(changer.targetRenderer.Get(changer));
|
var target = ctx.Observe(changer.targetRenderer.Get(changer));
|
||||||
var renderer = ctx.GetComponent<SkinnedMeshRenderer>(target);
|
var renderer = ctx.GetComponent<SkinnedMeshRenderer>(target);
|
||||||
|
|
||||||
@ -59,138 +63,171 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
.ToImmutableList();
|
.ToImmutableList();
|
||||||
});
|
});
|
||||||
|
|
||||||
private bool IsChangerActive(ModularAvatarShapeChanger changer, ComputeContext context)
|
|
||||||
{
|
|
||||||
if (context != null)
|
|
||||||
{
|
|
||||||
if (!context.ActiveAndEnabled(changer)) return false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (!changer.isActiveAndEnabled) return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
var changerRenderer = context != null
|
|
||||||
? context.GetComponent<Renderer>(changer.gameObject)
|
|
||||||
: changer.GetComponent<Renderer>();
|
|
||||||
context?.Observe(changerRenderer);
|
|
||||||
|
|
||||||
if (changerRenderer == null) return false;
|
public async Task<IRenderFilterNode> Instantiate(IEnumerable<(Renderer, Renderer)> proxyPairs,
|
||||||
return changerRenderer.enabled && (context?.ActiveAndEnabled(changer) ?? changer.isActiveAndEnabled);
|
ComputeContext context)
|
||||||
|
{
|
||||||
|
var node = new Node();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await node.Init(proxyPairs, context);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
// dispose
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
|
||||||
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class Node : IRenderFilterNode
|
||||||
public async Task MutateMeshData(IList<MeshState> states, ComputeContext context)
|
|
||||||
{
|
{
|
||||||
var targetGroups = await context.Observe(InternalTargetGroups);
|
private Mesh _generatedMesh = null;
|
||||||
|
private ImmutableList<ModularAvatarShapeChanger> _changers;
|
||||||
|
|
||||||
var state = states[0];
|
private bool IsChangerActive(ModularAvatarShapeChanger changer, ComputeContext context)
|
||||||
var renderer = state.Original;
|
|
||||||
if (renderer == null) return;
|
|
||||||
if (!targetGroups.TryGetValue(renderer, out var changers)) return;
|
|
||||||
if (!(renderer is SkinnedMeshRenderer smr)) return;
|
|
||||||
|
|
||||||
HashSet<int> toDelete = new HashSet<int>();
|
|
||||||
|
|
||||||
foreach (var changer in changers)
|
|
||||||
{
|
{
|
||||||
if (!IsChangerActive(changer, context)) continue;
|
if (changer == null) return false;
|
||||||
|
|
||||||
foreach (var shape in changer.Shapes)
|
if (context != null)
|
||||||
{
|
{
|
||||||
if (shape.ChangeType == ShapeChangeType.Delete)
|
return context.ActiveAndEnabled(changer);
|
||||||
{
|
}
|
||||||
var index = state.Mesh.GetBlendShapeIndex(shape.ShapeName);
|
else
|
||||||
if (index < 0) continue;
|
{
|
||||||
toDelete.Add(index);
|
return changer.isActiveAndEnabled;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (toDelete.Count > 0)
|
public async Task Init(IEnumerable<(Renderer, Renderer)> renderers, ComputeContext context)
|
||||||
{
|
{
|
||||||
var mesh = Object.Instantiate(state.Mesh);
|
var targetGroups = await context.Observe(InternalTargetGroups);
|
||||||
|
|
||||||
var bsPos = new Vector3[mesh.vertexCount];
|
var (original, proxy) = renderers.First();
|
||||||
bool[] targetVertex = new bool[mesh.vertexCount];
|
|
||||||
foreach (var bs in toDelete)
|
if (original == null || proxy == null) return;
|
||||||
|
if (!targetGroups.TryGetValue(original, out _changers)) return;
|
||||||
|
if (!(proxy is SkinnedMeshRenderer smr)) return;
|
||||||
|
|
||||||
|
HashSet<int> toDelete = new HashSet<int>();
|
||||||
|
var mesh = smr.sharedMesh;
|
||||||
|
|
||||||
|
foreach (var changer in _changers)
|
||||||
{
|
{
|
||||||
int frames = mesh.GetBlendShapeFrameCount(bs);
|
if (!IsChangerActive(changer, context)) continue;
|
||||||
for (int f = 0; f < frames; f++)
|
|
||||||
{
|
|
||||||
mesh.GetBlendShapeFrameVertices(bs, f, bsPos, null, null);
|
|
||||||
|
|
||||||
for (int i = 0; i < bsPos.Length; i++)
|
foreach (var shape in changer.Shapes)
|
||||||
|
{
|
||||||
|
if (shape.ChangeType == ShapeChangeType.Delete)
|
||||||
{
|
{
|
||||||
if (bsPos[i].sqrMagnitude > 0.0001f)
|
var index = mesh.GetBlendShapeIndex(shape.ShapeName);
|
||||||
|
if (index < 0) continue;
|
||||||
|
toDelete.Add(index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (toDelete.Count > 0)
|
||||||
|
{
|
||||||
|
mesh = Object.Instantiate(mesh);
|
||||||
|
|
||||||
|
var bsPos = new Vector3[mesh.vertexCount];
|
||||||
|
bool[] targetVertex = new bool[mesh.vertexCount];
|
||||||
|
foreach (var bs in toDelete)
|
||||||
|
{
|
||||||
|
int frames = mesh.GetBlendShapeFrameCount(bs);
|
||||||
|
for (int f = 0; f < frames; f++)
|
||||||
|
{
|
||||||
|
mesh.GetBlendShapeFrameVertices(bs, f, bsPos, null, null);
|
||||||
|
|
||||||
|
for (int i = 0; i < bsPos.Length; i++)
|
||||||
{
|
{
|
||||||
targetVertex[i] = true;
|
if (bsPos[i].sqrMagnitude > 0.0001f)
|
||||||
|
{
|
||||||
|
targetVertex[i] = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
List<int> tris = new List<int>();
|
List<int> tris = new List<int>();
|
||||||
for (int subMesh = 0; subMesh < mesh.subMeshCount; subMesh++)
|
for (int subMesh = 0; subMesh < mesh.subMeshCount; subMesh++)
|
||||||
{
|
|
||||||
tris.Clear();
|
|
||||||
|
|
||||||
var baseVertex = (int)mesh.GetBaseVertex(subMesh);
|
|
||||||
mesh.GetTriangles(tris, subMesh, false);
|
|
||||||
|
|
||||||
for (int i = 0; i < tris.Count; i += 3)
|
|
||||||
{
|
{
|
||||||
if (targetVertex[tris[i] + baseVertex] || targetVertex[tris[i + 1] + baseVertex] ||
|
tris.Clear();
|
||||||
targetVertex[tris[i + 2] + baseVertex])
|
|
||||||
|
var baseVertex = (int)mesh.GetBaseVertex(subMesh);
|
||||||
|
mesh.GetTriangles(tris, subMesh, false);
|
||||||
|
|
||||||
|
for (int i = 0; i < tris.Count; i += 3)
|
||||||
{
|
{
|
||||||
tris.RemoveRange(i, 3);
|
if (targetVertex[tris[i] + baseVertex] || targetVertex[tris[i + 1] + baseVertex] ||
|
||||||
i -= 3;
|
targetVertex[tris[i + 2] + baseVertex])
|
||||||
|
{
|
||||||
|
tris.RemoveRange(i, 3);
|
||||||
|
i -= 3;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mesh.SetTriangles(tris, subMesh, false, baseVertex: baseVertex);
|
||||||
}
|
}
|
||||||
|
|
||||||
mesh.SetTriangles(tris, subMesh, false, baseVertex: baseVertex);
|
smr.sharedMesh = mesh;
|
||||||
|
_generatedMesh = mesh;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public ulong Reads => IRenderFilterNode.Shapes | IRenderFilterNode.Mesh;
|
||||||
|
public ulong WhatChanged => IRenderFilterNode.Shapes | IRenderFilterNode.Mesh;
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
if (_generatedMesh != null) Object.DestroyImmediate(_generatedMesh);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnFrame(Renderer original, Renderer proxy)
|
||||||
|
{
|
||||||
|
if (_changers == null) return; // can happen transiently as we disable the last component
|
||||||
|
if (!(proxy is SkinnedMeshRenderer smr)) return;
|
||||||
|
|
||||||
|
Mesh mesh;
|
||||||
|
if (_generatedMesh != null)
|
||||||
|
{
|
||||||
|
smr.sharedMesh = _generatedMesh;
|
||||||
|
mesh = _generatedMesh;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mesh = smr.sharedMesh;
|
||||||
}
|
}
|
||||||
|
|
||||||
state.Mesh = mesh;
|
if (mesh == null) return;
|
||||||
state.OnDispose += () =>
|
|
||||||
|
foreach (var changer in _changers)
|
||||||
{
|
{
|
||||||
if (mesh != null) Object.Destroy(mesh);
|
if (!IsChangerActive(changer, null)) continue;
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
foreach (var shape in changer.Shapes)
|
||||||
public void OnFrame(Renderer original, Renderer proxy)
|
|
||||||
{
|
|
||||||
if (!InternalTargetGroups.TryGetValue(out var targetGroups)) return;
|
|
||||||
if (!targetGroups.TryGetValue(original, out var changers)) return;
|
|
||||||
if (!(proxy is SkinnedMeshRenderer smr)) return;
|
|
||||||
|
|
||||||
var mesh = smr.sharedMesh;
|
|
||||||
if (mesh == null) return;
|
|
||||||
|
|
||||||
foreach (var changer in changers)
|
|
||||||
{
|
|
||||||
if (!IsChangerActive(changer, null)) continue;
|
|
||||||
|
|
||||||
foreach (var shape in changer.Shapes)
|
|
||||||
{
|
|
||||||
var index = mesh.GetBlendShapeIndex(shape.ShapeName);
|
|
||||||
if (index < 0) continue;
|
|
||||||
|
|
||||||
float setToValue = -1;
|
|
||||||
|
|
||||||
switch (shape.ChangeType)
|
|
||||||
{
|
{
|
||||||
case ShapeChangeType.Delete:
|
var index = mesh.GetBlendShapeIndex(shape.ShapeName);
|
||||||
setToValue = 100;
|
if (index < 0) continue;
|
||||||
break;
|
|
||||||
case ShapeChangeType.Set:
|
|
||||||
setToValue = shape.Value;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
smr.SetBlendShapeWeight(index, setToValue);
|
float setToValue = -1;
|
||||||
|
|
||||||
|
switch (shape.ChangeType)
|
||||||
|
{
|
||||||
|
case ShapeChangeType.Delete:
|
||||||
|
setToValue = 100;
|
||||||
|
break;
|
||||||
|
case ShapeChangeType.Set:
|
||||||
|
setToValue = shape.Value;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
smr.SetBlendShapeWeight(index, setToValue);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,6 @@
|
|||||||
},
|
},
|
||||||
"vpmDependencies": {
|
"vpmDependencies": {
|
||||||
"com.vrchat.avatars": ">=3.4.0",
|
"com.vrchat.avatars": ">=3.4.0",
|
||||||
"nadena.dev.ndmf": ">=1.5.0-alpha.0 <2.0.0-a"
|
"nadena.dev.ndmf": ">=1.5.0-alpha.1 <2.0.0-a"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user