Merge pull request #2685 from notargs/use_materials

MaterialValueBindingMergerについて、sharedMaterialsではなくmaterialsを使用するように変更
This commit is contained in:
ousttrue 2025-06-26 21:51:22 +09:00 committed by GitHub
commit cff9aa75b7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 74 additions and 18 deletions

View File

@ -61,7 +61,7 @@ namespace UniGLTF
context.AddObjectToAsset(k.Name, o);
});
var root = loaded.Root;
GameObject.DestroyImmediate(loaded);
DestroyImmediate(loaded);
context.AddObjectToAsset(root.name, root);
context.SetMainObject(root);

View File

@ -9,6 +9,10 @@ namespace UniGLTF
/// ImporterContext の Load 結果の GltfModel
///
/// Runtime でモデルを Destory したときに関連リソース(Texture, Material...などの UnityEngine.Object)を自動的に Destroy する。
///
/// TODO: Editor Importの場合でも一瞬だけこのクラスのインスタンスが生じるが、すぐDestroyImmediateされるため、それらを区別する用途に使うことができる
/// Editorでも利用されている以上、名前・責務が良くないので見直したい。
///
/// </summary>
public class RuntimeGltfInstance : MonoBehaviour, IResponsibilityForDestroyObjects
{

View File

@ -1,4 +1,5 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
@ -8,7 +9,7 @@ namespace UniVRM10
/// <summary>
/// ブレンドシェイプを蓄えてまとめて適用するクラス
/// </summary>
internal sealed class ExpressionMerger
internal sealed class ExpressionMerger : IDisposable
{
/// <summary>
/// Key から Expression を得る
@ -24,7 +25,7 @@ namespace UniVRM10
MaterialValueBindingMerger m_materialValueBindingMerger;
public ExpressionMerger(VRM10ObjectExpression expressions, Transform root)
public ExpressionMerger(VRM10ObjectExpression expressions, Transform root, bool isPrefabInstance)
{
m_clipMap = expressions.Clips.ToDictionary(
x => expressions.CreateKey(x.Clip),
@ -33,7 +34,7 @@ namespace UniVRM10
);
m_valueMap = new Dictionary<ExpressionKey, float>(ExpressionKey.Comparer);
m_morphTargetBindingMerger = new MorphTargetBindingMerger(m_clipMap, root);
m_materialValueBindingMerger = new MaterialValueBindingMerger(m_clipMap, root);
m_materialValueBindingMerger = new MaterialValueBindingMerger(m_clipMap, root, isPrefabInstance);
}
/// <summary>
@ -74,5 +75,10 @@ namespace UniVRM10
{
m_materialValueBindingMerger.RestoreMaterialInitialValues();
}
public void Dispose()
{
m_materialValueBindingMerger.Dispose();
}
}
}

View File

@ -3,13 +3,14 @@ using System.Collections.Generic;
using UniGLTF.Extensions.VRMC_vrm;
using UnityEngine;
using VRM10.MToon10;
using Object = UnityEngine.Object;
namespace UniVRM10
{
///
/// Base + (A.Target - Base) * A.Weight + (B.Target - Base) * B.Weight ...
///
internal sealed class MaterialValueBindingMerger
internal sealed class MaterialValueBindingMerger : IDisposable
{
private static readonly string COLOR_PROPERTY = MToon10Prop.BaseColorFactor.ToUnityShaderLabName();
private static readonly string EMISSION_COLOR_PROPERTY = MToon10Prop.EmissiveFactor.ToUnityShaderLabName();
@ -18,6 +19,8 @@ namespace UniVRM10
private static readonly string SHADE_COLOR_PROPERTY = MToon10Prop.ShadeColorFactor.ToUnityShaderLabName();
private static readonly string MATCAP_COLOR_PROPERTY = MToon10Prop.MatcapColorFactor.ToUnityShaderLabName();
private readonly HashSet<Material> _clonedMaterials = new();
public static string GetProperty(MaterialColorType bindType)
{
switch (bindType)
@ -50,16 +53,44 @@ namespace UniVRM10
/// </summary>
Dictionary<string, PreviewMaterialItem> m_materialMap = new Dictionary<string, PreviewMaterialItem>();
void InitializeMaterialMap(Dictionary<ExpressionKey, VRM10Expression> clipMap, Transform root)
void InitializeMaterialMap(Dictionary<ExpressionKey, VRM10Expression> clipMap, Transform root, bool isPrefabInstance)
{
Dictionary<string, Material> materialNameMap = new Dictionary<string, Material>();
var materialNameMap = new Dictionary<string, Material>();
foreach (var renderer in root.GetComponentsInChildren<Renderer>())
{
foreach (var material in renderer.sharedMaterials)
// VFXRendererなど、Materialが設定できないRendererが存在する
if (renderer is not SkinnedMeshRenderer && renderer is not MeshRenderer) continue;
if (isPrefabInstance)
{
if (material != null && !materialNameMap.ContainsKey(material.name))
// EditorImportされたPrefabのInstanceとして生成されている場合、Materialを複製する
var sharedMaterials = renderer.sharedMaterials;
var materials = renderer.materials;
for (var i = 0; i < materials.Length; i++)
{
materialNameMap.Add(material.name, material);
var sharedMaterial = sharedMaterials[i];
var material = materials[i];
if (!sharedMaterial || !material) continue;
// 複製されたマテリアルはこのクラス内で破棄
if (sharedMaterial != material) _clonedMaterials.Add(material);
// 複製前の名前に揃え、それを記録しておく
// なお、Vrm10Runtimeのインスタンスが作られるより先にユーザーによってMaterialが複製されるパターンは想定しない
material.name = sharedMaterial.name;
materialNameMap.TryAdd(sharedMaterial.name, material);
}
}
else
{
// PrefabのInstanceでないRuntimeImportされているならMaterialは複製しない
foreach (var material in renderer.sharedMaterials)
{
if (material)
{
materialNameMap.TryAdd(material.name, material);
}
}
}
}
@ -284,9 +315,18 @@ namespace UniVRM10
}
#endregion
public MaterialValueBindingMerger(Dictionary<ExpressionKey, VRM10Expression> clipMap, Transform root)
public MaterialValueBindingMerger(Dictionary<ExpressionKey, VRM10Expression> clipMap, Transform root, bool isPrefabInstance)
{
InitializeMaterialMap(clipMap, root);
InitializeMaterialMap(clipMap, root, isPrefabInstance);
}
public void Dispose()
{
foreach (var clonedMaterial in _clonedMaterials)
{
Object.Destroy(clonedMaterial);
}
_clonedMaterials.Clear();
}
}
}

View File

@ -141,8 +141,11 @@ namespace UniVRM10
}
var initPose = RuntimeGltfInstance.SafeGetInitialPose(transform);
// NOTE: RuntimeGltfInstanceがないかどうかでPrefabのインスタンスであるかEditorImportされているかが判別できる
var isPrefabInstance = !GetComponent<RuntimeGltfInstance>();
return new Vrm10Runtime(this, useControlRig, m_springBoneRuntime, initPose);
return new Vrm10Runtime(this, useControlRig, m_springBoneRuntime, initPose, isPrefabInstance);
}
public Vrm10Runtime Runtime

View File

@ -52,7 +52,7 @@ namespace UniVRM10
IReadOnlyDictionary<Transform, TransformState> _initPose;
public Vrm10Runtime(Vrm10Instance instance, bool useControlRig, IVrm10SpringBoneRuntime springBoneRuntime,
IReadOnlyDictionary<Transform, TransformState> initPose)
IReadOnlyDictionary<Transform, TransformState> initPose, bool isPrefabInstance)
{
if (!Application.isPlaying)
{
@ -77,7 +77,7 @@ namespace UniVRM10
}
Constraints = instance.GetComponentsInChildren<IVrm10Constraint>();
LookAt = new Vrm10RuntimeLookAt(instance, instance.Humanoid, ControlRig);
Expression = new Vrm10RuntimeExpression(instance, LookAt.EyeDirectionApplicable);
Expression = new Vrm10RuntimeExpression(instance, LookAt.EyeDirectionApplicable, isPrefabInstance);
SpringBone = springBoneRuntime;
}

View File

@ -23,9 +23,9 @@ namespace UniVRM10
public float LookAtOverrideRate { get; private set; }
public float MouthOverrideRate { get; private set; }
internal Vrm10RuntimeExpression(Vrm10Instance target, ILookAtEyeDirectionApplicable eyeDirectionApplicable)
internal Vrm10RuntimeExpression(Vrm10Instance target, ILookAtEyeDirectionApplicable eyeDirectionApplicable, bool isPrefabInstance)
{
_merger = new ExpressionMerger(target.Vrm.Expression, target.transform);
_merger = new ExpressionMerger(target.Vrm.Expression, target.transform, isPrefabInstance);
_keys = target.Vrm.Expression.Clips
.Select(x => target.Vrm.Expression.CreateKey(x.Clip))
.ToList();
@ -56,6 +56,9 @@ namespace UniVRM10
_eyeDirectionApplicable?.Restore();
_eyeDirectionApplicable = null;
_merger?.Dispose();
_merger = null;
}
internal void Process(LookAtEyeDirection inputEyeDirection)