Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

UnityObjectDestoyer 改め RuntimeGltfInstance #1021

Merged
merged 12 commits into from
Jun 11, 2021
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public static void OnGUIAnimation(ScriptedImporter importer, GltfParser parser)
}
}

importer.DrawRemapGUI<AnimationClip>(parser.GLTF.animations.Select(x => new SubAssetKey(typeof(AnimationClip), x.name)));
importer.DrawRemapGUI<AnimationClip>(AnimationImporterUtil.EnumerateSubAssetKeys(parser.GLTF));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yosasou


if (GUILayout.Button("Clear"))
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
using System.Collections.Generic;
using System.Linq;
using UnityEditor;
using UnityEngine;
using VRMShaders;
#if UNITY_2020_2_OR_NEWER
Expand Down Expand Up @@ -50,20 +48,16 @@ public static void Import(ScriptedImporter scriptedImporter, AssetImportContext
}

loader.InvertAxis = reverseAxis;
loader.Load();
loader.ShowMeshes();
var loaded = loader.Load();
loaded.ShowMeshes();

loader.TransferOwnership(o =>
loaded.TransferOwnership((k, o) =>
{
context.AddObjectToAsset(o.name, o);
if (o is GameObject)
{
// Root GameObject is main object
context.SetMainObject(loader.Root);
}

return true;
context.AddObjectToAsset(k.Name, o);
});

context.AddObjectToAsset(loaded.name, loaded.gameObject);
context.SetMainObject(loaded.gameObject);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,13 +107,4 @@ public static void ExtractTextures(GltfParser parser, UnityPath textureDirectory
};
}
}

public static class KeyValuePariExtensions
{
public static void Deconstruct<T, U>(this KeyValuePair<T, U> pair, out T key, out U value)
{
key = pair.Key;
value = pair.Value;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -312,5 +312,13 @@ public static AnimationClip ConvertAnimationClip(glTF gltf, glTFAnimation animat
}
return clip;
}

public static IEnumerable<VRMShaders.SubAssetKey> EnumerateSubAssetKeys(glTF gltf)
{
foreach (var gltfAnimation in gltf.animations)
{
yield return new VRMShaders.SubAssetKey(typeof(AnimationClip), gltfAnimation.name);
}
}
}
}
134 changes: 21 additions & 113 deletions Assets/UniGLTF/Runtime/UniGLTF/IO/ImporterContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ namespace UniGLTF
/// <summary>
/// GLTF importer
/// </summary>
public class ImporterContext : IDisposable
public class ImporterContext : IResponsibilityForDestroyObjects
{
public ITextureDescriptorGenerator TextureDescriptorGenerator { get; protected set; }
public IMaterialDescriptorGenerator MaterialDescriptorGenerator { get; protected set; }
Expand Down Expand Up @@ -61,7 +61,7 @@ public ImporterContext(
};

#region Load. Build unity objects
public virtual async Task LoadAsync(IAwaitCaller awaitCaller = null, Func<string, IDisposable> MeasureTime = null)
public virtual async Task<UnityObjectManager> LoadAsync(IAwaitCaller awaitCaller = null, Func<string, IDisposable> MeasureTime = null)
{
if (awaitCaller == null)
{
Expand Down Expand Up @@ -108,6 +108,8 @@ public virtual async Task LoadAsync(IAwaitCaller awaitCaller = null, Func<string
}

await OnLoadHierarchy(awaitCaller, MeasureTime);

return UnityObjectManager.AttachTo(Root, this);
}

/// <summary>
Expand All @@ -119,18 +121,17 @@ protected virtual async Task LoadAnimationAsync(IAwaitCaller awaitCaller)
{
if (GLTF.animations != null && GLTF.animations.Any())
{
for (int i = 0; i < GLTF.animations.Count; ++i)
foreach (var (key, gltfAnimation) in Enumerable.Zip(AnimationImporterUtil.EnumerateSubAssetKeys(GLTF), GLTF.animations, (x, y) => (x, y)))
{
var gltfAnimation = GLTF.animations[i];
AnimationClip clip = default;
if (_externalObjectMap.TryGetValue(new SubAssetKey(typeof(AnimationClip), gltfAnimation.name), out UnityEngine.Object value))
if (_externalObjectMap.TryGetValue(key, out UnityEngine.Object value))
{
clip = value as AnimationClip;
}
else
{
clip = AnimationImporterUtil.ConvertAnimationClip(GLTF, GLTF.animations[i], InvertAxis.Create());
AnimationClips.Add(clip);
clip = AnimationImporterUtil.ConvertAnimationClip(GLTF, gltfAnimation, InvertAxis.Create());
AnimationClips.Add((key, clip));
}
}

Expand All @@ -150,7 +151,7 @@ protected virtual async Task SetupAnimationsAsync(IAwaitCaller awaitCaller)
var animation = Root.AddComponent<Animation>();
for (int i = 0; i < AnimationClips.Count; ++i)
{
var clip = AnimationClips[i];
var (_, clip) = AnimationClips[i];
animation.AddClip(clip, clip.name);
if (i == 0)
{
Expand Down Expand Up @@ -275,148 +276,55 @@ async Task<MeshWithMaterials> BuildMeshAsync(IAwaitCaller awaitCaller, Func<stri
#endregion

#region Imported
public GameObject Root;
bool m_ownRoot = true;
protected GameObject Root;
public List<Transform> Nodes = new List<Transform>();

public List<MeshWithMaterials> Meshes = new List<MeshWithMaterials>();
public void ShowMeshes()
{
foreach (var x in Meshes)
{
foreach (var y in x.Renderers)
{
y.enabled = true;
}
}
}
void RemoveMesh(Mesh mesh)
{
var index = Meshes.FindIndex(x => x.Mesh == mesh);
if (index >= 0)
{
Meshes.RemoveAt(index);
}
}

public void EnableUpdateWhenOffscreen()
{
foreach (var x in Meshes)
{
foreach (var r in x.Renderers)
{
var skinnedMeshRenderer = r as SkinnedMeshRenderer;
if (skinnedMeshRenderer != null)
{
skinnedMeshRenderer.updateWhenOffscreen = true;
}
}
}
}

public List<AnimationClip> AnimationClips = new List<AnimationClip>();
public List<(SubAssetKey, AnimationClip)> AnimationClips = new List<(SubAssetKey, AnimationClip)>();
#endregion

/// <summary>
/// ImporterContextが所有する UnityEngine.Object を破棄する
/// </summary>
public virtual void Dispose()
{
Action<UnityEngine.Object> destroy = UnityResourceDestroyer.DestroyResource();

foreach (var x in AnimationClips)
foreach (var (k, x) in AnimationClips)
{
#if VRM_DEVELOP
// Debug.Log($"Destroy {x}");
#endif
destroy(x);
UnityObjectDestoyer.DestroyRuntimeOrEditor(x);
}
AnimationClips.Clear();

foreach (var x in Meshes)
{
#if VRM_DEVELOP
// Debug.Log($"Destroy {x.Mesh}");
#endif
destroy(x.Mesh);
UnityObjectDestoyer.DestroyRuntimeOrEditor(x.Mesh);
}
Meshes.Clear();

MaterialFactory?.Dispose();
TextureFactory?.Dispose();

if (m_ownRoot && Root != null)
{
#if VRM_DEVELOP
// Debug.Log($"Destroy {Root}");
#endif
destroy(Root);
}
}

/// <summary>
/// Root ヒエラルキーで使っているリソース
/// </summary>
/// <returns></returns>
public virtual void TransferOwnership(Func<UnityEngine.Object, bool> take)
public virtual void TransferOwnership(TakeResponsibilityForDestroyObjectFunc take)
{
var list = new List<UnityEngine.Object>();
foreach (var mesh in Meshes)
{
if (take(mesh.Mesh))
{
list.Add(mesh.Mesh);
}
}
foreach (var x in list)
foreach (var mesh in Meshes.ToArray())
{
RemoveMesh(x as Mesh);
take(SubAssetKey.Create(mesh.Mesh), mesh.Mesh);
Meshes.Remove(mesh);
}

TextureFactory.TransferOwnership(take);
MaterialFactory.TransferOwnership(take);

list.Clear();
foreach (var animation in AnimationClips)
{
if (take(animation))
{
list.Add(animation);
}
}
foreach (var x in list)
foreach (var (key, animation) in AnimationClips.ToArray())
{
AnimationClips.Remove(x as AnimationClip);
take(key, animation);
AnimationClips.Remove((key, animation));
}

if (m_ownRoot && Root != null)
{
if (take(Root))
{
// 所有権(Dispose権)
m_ownRoot = false;
}
}
}

/// <summary>
/// RootにUnityResourceDestroyerをアタッチして、
/// RootをUnityEngine.Object.Destroyしたときに、
/// 関連するUnityEngine.Objectを破棄するようにする。
/// Mesh, Material, Texture, AnimationClip, GameObject の所有者が
/// ImporterContext から UnityResourceDestroyer に移動する。
/// ImporterContext.Dispose の対象から外れる。
/// </summary>
/// <returns></returns>
public UnityResourceDestroyer DisposeOnGameObjectDestroyed()
{
var destroyer = Root.AddComponent<UnityResourceDestroyer>();
TransferOwnership(o =>
{
destroyer.Resources.Add(o);
return true;
});
return destroyer;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ public static class ImporterContextExtensions
/// <summary>
/// Build unity objects from parsed gltf
/// </summary>
public static void Load(this ImporterContext self)
public static UnityObjectManager Load(this ImporterContext self)
{
var meassureTime = new ImporterContextSpeedLog();
var task = self.LoadAsync(default(ImmediateCaller), meassureTime.MeasureTime);
Expand All @@ -24,6 +24,8 @@ public static void Load(this ImporterContext self)
#if VRM_DEVELOP
Debug.Log($"{self.Parser.TargetPath}: {meassureTime.GetSpeedLog()}");
#endif

return task.Result;
}
}
}
64 changes: 64 additions & 0 deletions Assets/UniGLTF/Runtime/UniGLTF/UnityObjectManager.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
using System;
using System.Collections.Generic;
using UnityEngine;
using VRMShaders;

namespace UniGLTF
{
/// <summary>
/// Mesh, Material, Texture などを抱えておいて確実に破棄できるようにする
/// </summary>
public class UnityObjectManager : MonoBehaviour, IResponsibilityForDestroyObjects
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

存在はいい!が名前が…う~ん…

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ユーザの期待としては Load API の返り値は「ロードした glTF/VRM モデルそのもの」だと思うので、そういう名称にしてしまっていいと思う。
ModelInstance とか glTFModel とか

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

インスタンスの変数名も loaded じゃなくて loadedModel とか model でよさそう

{
List<(SubAssetKey, UnityEngine.Object)> m_resources = new List<(SubAssetKey, UnityEngine.Object)>();

public static UnityObjectManager AttachTo(GameObject go, ImporterContext context)
{
var loaded = go.AddComponent<UnityObjectManager>();
context.TransferOwnership((k, o) =>
{
loaded.m_resources.Add((k, o));
});
return loaded;
}

public void ShowMeshes()
{
foreach (var r in GetComponentsInChildren<Renderer>())
{
r.enabled = true;
}
}

public void EnableUpdateWhenOffscreen()
{
foreach (var smr in GetComponentsInChildren<SkinnedMeshRenderer>())
{
smr.updateWhenOffscreen = true;
}
}

void OnDestroy()
{
Debug.Log("UnityResourceDestroyer.OnDestroy");
foreach (var (key, x) in m_resources)
{
UnityObjectDestoyer.DestroyRuntimeOrEditor(x);
}
}

public void TransferOwnership(TakeResponsibilityForDestroyObjectFunc take)
{
foreach (var (key, x) in m_resources.ToArray())
{
take(key, x);
m_resources.Remove((key, x));
}
}

public void Dispose()
{
UnityObjectDestoyer.DestroyRuntimeOrEditor(this);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this.gameObject を Destroy すべきかも

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

たしかに!

}
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading