chore: update for new preview system API (#877)

This commit is contained in:
bd_ 2024-06-07 12:58:08 +09:00 committed by GitHub
parent a0f27ba70f
commit d725ade36d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 181 additions and 104 deletions

View File

@ -19,7 +19,7 @@
"dependencies": {} "dependencies": {}
}, },
"nadena.dev.ndmf": { "nadena.dev.ndmf": {
"version": "1.5.0-alpha.0" "version": "1.5.0-alpha.1"
} }
} }
} }

View File

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

View File

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

View File

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

View File

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