mirror of
https://github.com/bdunderscore/modular-avatar.git
synced 2024-12-29 18:55:06 +08:00
Merge pull request #324 from bdunderscore/enhancement/mesh-settings
Add the Mesh Settings component
This commit is contained in:
commit
cdb5ede7fe
@ -0,0 +1,72 @@
|
||||
using nadena.dev.modular_avatar.core.editor;
|
||||
using NUnit.Framework;
|
||||
using UnityEngine;
|
||||
using VRC.SDK3.Avatars.Components;
|
||||
|
||||
namespace modular_avatar_tests
|
||||
{
|
||||
internal class MeshSettingsTests : TestBase
|
||||
{
|
||||
private static readonly string PREFAB_NAME = "MeshSettingsTests.prefab";
|
||||
|
||||
[Test]
|
||||
public void TestProbeAnchor()
|
||||
{
|
||||
var prefab = CreatePrefab(PREFAB_NAME);
|
||||
var context = new BuildContext(prefab.GetComponent<VRCAvatarDescriptor>());
|
||||
new MeshSettingsPass(context).OnPreprocessAvatar();
|
||||
|
||||
var root = prefab.transform.Find("RendererRoot");
|
||||
var target = prefab.transform.Find("ProbeTarget");
|
||||
var obj1 = prefab.transform.Find("ProbeTargetRenderers/SkinnedMeshRenderer").GetComponent<Renderer>();
|
||||
var obj2 = prefab.transform.Find("ProbeTargetRenderers/MeshRenderer").GetComponent<Renderer>();
|
||||
var obj3 = prefab.transform.Find("ProbeTargetRenderers/ParticleSystemRenderer").GetComponent<Renderer>();
|
||||
var obj4 = prefab.transform.Find("ProbeTargetRenderers/TrailRenderer").GetComponent<Renderer>();
|
||||
|
||||
Assert.AreEqual(target, obj1.probeAnchor);
|
||||
Assert.AreEqual(target, obj2.probeAnchor);
|
||||
Assert.AreEqual(target, obj3.probeAnchor);
|
||||
Assert.AreEqual(target, obj4.probeAnchor);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestProbeAnchorOverrides()
|
||||
{
|
||||
var prefab = CreatePrefab(PREFAB_NAME);
|
||||
var context = new BuildContext(prefab.GetComponent<VRCAvatarDescriptor>());
|
||||
new MeshSettingsPass(context).OnPreprocessAvatar();
|
||||
|
||||
var noninherit = prefab.transform.Find("ProbeTargetRenderers/NonInherited").GetComponent<MeshRenderer>();
|
||||
var overrideset = prefab.transform.Find("ProbeTargetRenderers/OverrideSet").GetComponent<MeshRenderer>();
|
||||
|
||||
Assert.AreEqual(noninherit.transform.Find("Target"), noninherit.probeAnchor);
|
||||
Assert.AreEqual(overrideset.transform.Find("Target"), overrideset.probeAnchor);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestSetBounds()
|
||||
{
|
||||
var prefab = CreatePrefab(PREFAB_NAME);
|
||||
var context = new BuildContext(prefab.GetComponent<VRCAvatarDescriptor>());
|
||||
new MeshSettingsPass(context).OnPreprocessAvatar();
|
||||
|
||||
var target = prefab.transform.Find("ProbeTarget");
|
||||
|
||||
var inherit = prefab.transform.Find("Bounds/Inherit").GetComponent<SkinnedMeshRenderer>();
|
||||
var overridden = prefab.transform.Find("Bounds/Overridden").GetComponent<SkinnedMeshRenderer>();
|
||||
var notset = prefab.transform.Find("Bounds/NotSet").GetComponent<SkinnedMeshRenderer>();
|
||||
|
||||
Assert.AreEqual(new Vector3(1, 2, 3), inherit.bounds.center);
|
||||
Assert.AreEqual(new Vector3(4, 5, 6), inherit.bounds.extents);
|
||||
Assert.AreEqual(target, inherit.rootBone);
|
||||
|
||||
Assert.AreEqual(new Vector3(8, 8, 8), overridden.bounds.center);
|
||||
Assert.AreEqual(new Vector3(9, 9, 9), overridden.bounds.extents);
|
||||
Assert.AreEqual(overridden.transform.Find("Target"), overridden.rootBone);
|
||||
|
||||
Assert.AreEqual(new Vector3(0, 0, 0), notset.bounds.center);
|
||||
Assert.AreEqual(new Vector3(2, 2, 2), notset.bounds.extents);
|
||||
Assert.AreEqual(notset.transform.Find("Target"), notset.rootBone);
|
||||
}
|
||||
}
|
||||
}
|
@ -9,9 +9,9 @@ GameObject:
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 5397716290800633055}
|
||||
- component: {fileID: 2330010457497982229}
|
||||
- component: {fileID: 335967967441451257}
|
||||
m_Layer: 0
|
||||
m_Name: RendererRoot
|
||||
m_Name: ProbeTargetRenderers
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
@ -32,10 +32,12 @@ Transform:
|
||||
- {fileID: 7708823067105146344}
|
||||
- {fileID: 6857113755099998103}
|
||||
- {fileID: 3582219504831888926}
|
||||
- {fileID: 8922954295583054356}
|
||||
- {fileID: 4234831726961402887}
|
||||
m_Father: {fileID: 2813872215014323517}
|
||||
m_RootOrder: 1
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!114 &2330010457497982229
|
||||
--- !u!114 &335967967441451257
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
@ -44,11 +46,78 @@ MonoBehaviour:
|
||||
m_GameObject: {fileID: 680825651427616331}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: b18784296c2581e498e5127a23e6f019, type: 3}
|
||||
m_Script: {fileID: 11500000, guid: 560fdafd46c74b2db6422fdf0e7f2363, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
probeTarget:
|
||||
InheritProbeAnchor: 1
|
||||
ProbeAnchor:
|
||||
referencePath: ProbeTarget
|
||||
InheritBounds: 0
|
||||
RootBone:
|
||||
referencePath:
|
||||
Bounds:
|
||||
m_Center: {x: 0, y: 0, z: 0}
|
||||
m_Extent: {x: 1, y: 1, z: 1}
|
||||
--- !u!1 &935411094479274245
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 7820260671288448613}
|
||||
m_Layer: 0
|
||||
m_Name: Target
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!4 &7820260671288448613
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 935411094479274245}
|
||||
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_Children: []
|
||||
m_Father: {fileID: 8922954295583054356}
|
||||
m_RootOrder: 0
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!1 &1110437597349189514
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 5019135646683737746}
|
||||
m_Layer: 0
|
||||
m_Name: Target
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!4 &5019135646683737746
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1110437597349189514}
|
||||
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_Children: []
|
||||
m_Father: {fileID: 2306861396738510558}
|
||||
m_RootOrder: 0
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!1 &2395813488222310007
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
@ -119,6 +188,111 @@ MeshRenderer:
|
||||
m_SortingLayerID: 0
|
||||
m_SortingLayer: 0
|
||||
m_SortingOrder: 0
|
||||
--- !u!1 &2871342873229566282
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 2671010323382710830}
|
||||
- component: {fileID: 2589302178758902106}
|
||||
- component: {fileID: 5369087837389602381}
|
||||
m_Layer: 0
|
||||
m_Name: Overridden
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!4 &2671010323382710830
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 2871342873229566282}
|
||||
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_Children:
|
||||
- {fileID: 8008288380682626085}
|
||||
m_Father: {fileID: 9198237797126898215}
|
||||
m_RootOrder: 1
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!114 &2589302178758902106
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 2871342873229566282}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 560fdafd46c74b2db6422fdf0e7f2363, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
InheritProbeAnchor: 0
|
||||
ProbeAnchor:
|
||||
referencePath:
|
||||
InheritBounds: 1
|
||||
RootBone:
|
||||
referencePath: ProbeTarget
|
||||
Bounds:
|
||||
m_Center: {x: 8, y: 8, z: 8}
|
||||
m_Extent: {x: 9, y: 9, z: 9}
|
||||
--- !u!137 &5369087837389602381
|
||||
SkinnedMeshRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 2871342873229566282}
|
||||
m_Enabled: 1
|
||||
m_CastShadows: 1
|
||||
m_ReceiveShadows: 1
|
||||
m_DynamicOccludee: 1
|
||||
m_MotionVectors: 1
|
||||
m_LightProbeUsage: 1
|
||||
m_ReflectionProbeUsage: 1
|
||||
m_RayTracingMode: 0
|
||||
m_RenderingLayerMask: 1
|
||||
m_RendererPriority: 0
|
||||
m_Materials:
|
||||
- {fileID: 0}
|
||||
m_StaticBatchInfo:
|
||||
firstSubMesh: 0
|
||||
subMeshCount: 0
|
||||
m_StaticBatchRoot: {fileID: 0}
|
||||
m_ProbeAnchor: {fileID: 0}
|
||||
m_LightProbeVolumeOverride: {fileID: 0}
|
||||
m_ScaleInLightmap: 1
|
||||
m_ReceiveGI: 1
|
||||
m_PreserveUVs: 0
|
||||
m_IgnoreNormalsForChartDetection: 0
|
||||
m_ImportantGI: 0
|
||||
m_StitchLightmapSeams: 1
|
||||
m_SelectedEditorRenderState: 3
|
||||
m_MinimumChartSize: 4
|
||||
m_AutoUVMaxDistance: 0.5
|
||||
m_AutoUVMaxAngle: 89
|
||||
m_LightmapParameters: {fileID: 0}
|
||||
m_SortingLayerID: 0
|
||||
m_SortingLayer: 0
|
||||
m_SortingOrder: 0
|
||||
serializedVersion: 2
|
||||
m_Quality: 0
|
||||
m_UpdateWhenOffscreen: 0
|
||||
m_SkinnedMotionVectors: 1
|
||||
m_Mesh: {fileID: 0}
|
||||
m_Bones: []
|
||||
m_BlendShapeWeights: []
|
||||
m_RootBone: {fileID: 0}
|
||||
m_AABB:
|
||||
m_Center: {x: 0, y: 0, z: 0}
|
||||
m_Extent: {x: 0, y: 0, z: 0}
|
||||
m_DirtyAABB: 1
|
||||
--- !u!1 &3657214856810207961
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
@ -132,7 +306,7 @@ GameObject:
|
||||
- component: {fileID: 265261251370394767}
|
||||
- component: {fileID: 7103399505028166247}
|
||||
m_Layer: 0
|
||||
m_Name: ProbeAnchorTests
|
||||
m_Name: MeshSettingsTests
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
@ -151,6 +325,7 @@ Transform:
|
||||
m_Children:
|
||||
- {fileID: 1865266364885290703}
|
||||
- {fileID: 5397716290800633055}
|
||||
- {fileID: 9198237797126898215}
|
||||
m_Father: {fileID: 0}
|
||||
m_RootOrder: 0
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
@ -440,6 +615,111 @@ Animator:
|
||||
m_HasTransformHierarchy: 1
|
||||
m_AllowConstantClipSamplingOptimization: 1
|
||||
m_KeepAnimatorControllerStateOnDisable: 0
|
||||
--- !u!1 &3968597137123995335
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 2306861396738510558}
|
||||
- component: {fileID: 9171463375283835425}
|
||||
- component: {fileID: 6233715779515687049}
|
||||
m_Layer: 0
|
||||
m_Name: NotSet
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!4 &2306861396738510558
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 3968597137123995335}
|
||||
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_Children:
|
||||
- {fileID: 5019135646683737746}
|
||||
m_Father: {fileID: 9198237797126898215}
|
||||
m_RootOrder: 2
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!114 &9171463375283835425
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 3968597137123995335}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 560fdafd46c74b2db6422fdf0e7f2363, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
InheritProbeAnchor: 0
|
||||
ProbeAnchor:
|
||||
referencePath:
|
||||
InheritBounds: 2
|
||||
RootBone:
|
||||
referencePath: ProbeTarget
|
||||
Bounds:
|
||||
m_Center: {x: 0, y: 0, z: 0}
|
||||
m_Extent: {x: 1, y: 1, z: 1}
|
||||
--- !u!137 &6233715779515687049
|
||||
SkinnedMeshRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 3968597137123995335}
|
||||
m_Enabled: 1
|
||||
m_CastShadows: 1
|
||||
m_ReceiveShadows: 1
|
||||
m_DynamicOccludee: 1
|
||||
m_MotionVectors: 1
|
||||
m_LightProbeUsage: 1
|
||||
m_ReflectionProbeUsage: 1
|
||||
m_RayTracingMode: 0
|
||||
m_RenderingLayerMask: 1
|
||||
m_RendererPriority: 0
|
||||
m_Materials:
|
||||
- {fileID: 0}
|
||||
m_StaticBatchInfo:
|
||||
firstSubMesh: 0
|
||||
subMeshCount: 0
|
||||
m_StaticBatchRoot: {fileID: 0}
|
||||
m_ProbeAnchor: {fileID: 0}
|
||||
m_LightProbeVolumeOverride: {fileID: 0}
|
||||
m_ScaleInLightmap: 1
|
||||
m_ReceiveGI: 1
|
||||
m_PreserveUVs: 0
|
||||
m_IgnoreNormalsForChartDetection: 0
|
||||
m_ImportantGI: 0
|
||||
m_StitchLightmapSeams: 1
|
||||
m_SelectedEditorRenderState: 3
|
||||
m_MinimumChartSize: 4
|
||||
m_AutoUVMaxDistance: 0.5
|
||||
m_AutoUVMaxAngle: 89
|
||||
m_LightmapParameters: {fileID: 0}
|
||||
m_SortingLayerID: 0
|
||||
m_SortingLayer: 0
|
||||
m_SortingOrder: 0
|
||||
serializedVersion: 2
|
||||
m_Quality: 0
|
||||
m_UpdateWhenOffscreen: 0
|
||||
m_SkinnedMotionVectors: 1
|
||||
m_Mesh: {fileID: 0}
|
||||
m_Bones: []
|
||||
m_BlendShapeWeights: []
|
||||
m_RootBone: {fileID: 5019135646683737746}
|
||||
m_AABB:
|
||||
m_Center: {x: 0, y: 0, z: 0}
|
||||
m_Extent: {x: 2, y: 2, z: 2}
|
||||
m_DirtyAABB: 0
|
||||
--- !u!1 &6236283415756824863
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
@ -470,6 +750,91 @@ Transform:
|
||||
m_Father: {fileID: 2813872215014323517}
|
||||
m_RootOrder: 0
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!1 &6389017230970607628
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 8008288380682626085}
|
||||
m_Layer: 0
|
||||
m_Name: Target
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!4 &8008288380682626085
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 6389017230970607628}
|
||||
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_Children: []
|
||||
m_Father: {fileID: 2671010323382710830}
|
||||
m_RootOrder: 0
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!1 &7015511926769845160
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 9198237797126898215}
|
||||
- component: {fileID: 5213165685920700274}
|
||||
m_Layer: 0
|
||||
m_Name: Bounds
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!4 &9198237797126898215
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 7015511926769845160}
|
||||
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_Children:
|
||||
- {fileID: 4332104211298917797}
|
||||
- {fileID: 2671010323382710830}
|
||||
- {fileID: 2306861396738510558}
|
||||
m_Father: {fileID: 2813872215014323517}
|
||||
m_RootOrder: 2
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!114 &5213165685920700274
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 7015511926769845160}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 560fdafd46c74b2db6422fdf0e7f2363, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
InheritProbeAnchor: 0
|
||||
ProbeAnchor:
|
||||
referencePath:
|
||||
InheritBounds: 1
|
||||
RootBone:
|
||||
referencePath: ProbeTarget
|
||||
Bounds:
|
||||
m_Center: {x: 1, y: 2, z: 3}
|
||||
m_Extent: {x: 4, y: 5, z: 6}
|
||||
--- !u!1 &7136371616812247070
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
@ -598,6 +963,181 @@ TrailRenderer:
|
||||
m_MinVertexDistance: 0.1
|
||||
m_Autodestruct: 0
|
||||
m_Emitting: 1
|
||||
--- !u!1 &7694387925439316296
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 4332104211298917797}
|
||||
- component: {fileID: 3551356292515820315}
|
||||
m_Layer: 0
|
||||
m_Name: Inherit
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!4 &4332104211298917797
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 7694387925439316296}
|
||||
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_Children: []
|
||||
m_Father: {fileID: 9198237797126898215}
|
||||
m_RootOrder: 0
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!137 &3551356292515820315
|
||||
SkinnedMeshRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 7694387925439316296}
|
||||
m_Enabled: 1
|
||||
m_CastShadows: 1
|
||||
m_ReceiveShadows: 1
|
||||
m_DynamicOccludee: 1
|
||||
m_MotionVectors: 1
|
||||
m_LightProbeUsage: 1
|
||||
m_ReflectionProbeUsage: 1
|
||||
m_RayTracingMode: 0
|
||||
m_RenderingLayerMask: 1
|
||||
m_RendererPriority: 0
|
||||
m_Materials:
|
||||
- {fileID: 0}
|
||||
m_StaticBatchInfo:
|
||||
firstSubMesh: 0
|
||||
subMeshCount: 0
|
||||
m_StaticBatchRoot: {fileID: 0}
|
||||
m_ProbeAnchor: {fileID: 0}
|
||||
m_LightProbeVolumeOverride: {fileID: 0}
|
||||
m_ScaleInLightmap: 1
|
||||
m_ReceiveGI: 1
|
||||
m_PreserveUVs: 0
|
||||
m_IgnoreNormalsForChartDetection: 0
|
||||
m_ImportantGI: 0
|
||||
m_StitchLightmapSeams: 1
|
||||
m_SelectedEditorRenderState: 3
|
||||
m_MinimumChartSize: 4
|
||||
m_AutoUVMaxDistance: 0.5
|
||||
m_AutoUVMaxAngle: 89
|
||||
m_LightmapParameters: {fileID: 0}
|
||||
m_SortingLayerID: 0
|
||||
m_SortingLayer: 0
|
||||
m_SortingOrder: 0
|
||||
serializedVersion: 2
|
||||
m_Quality: 0
|
||||
m_UpdateWhenOffscreen: 0
|
||||
m_SkinnedMotionVectors: 1
|
||||
m_Mesh: {fileID: 0}
|
||||
m_Bones: []
|
||||
m_BlendShapeWeights: []
|
||||
m_RootBone: {fileID: 0}
|
||||
m_AABB:
|
||||
m_Center: {x: 0, y: 0, z: 0}
|
||||
m_Extent: {x: 0, y: 0, z: 0}
|
||||
m_DirtyAABB: 1
|
||||
--- !u!1 &8118624344453541351
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 8922954295583054356}
|
||||
- component: {fileID: 5109966626089099389}
|
||||
- component: {fileID: 4914466322604787005}
|
||||
m_Layer: 0
|
||||
m_Name: NonInherited
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!4 &8922954295583054356
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 8118624344453541351}
|
||||
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_Children:
|
||||
- {fileID: 7820260671288448613}
|
||||
m_Father: {fileID: 5397716290800633055}
|
||||
m_RootOrder: 4
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!23 &5109966626089099389
|
||||
MeshRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 8118624344453541351}
|
||||
m_Enabled: 1
|
||||
m_CastShadows: 1
|
||||
m_ReceiveShadows: 1
|
||||
m_DynamicOccludee: 1
|
||||
m_MotionVectors: 1
|
||||
m_LightProbeUsage: 1
|
||||
m_ReflectionProbeUsage: 1
|
||||
m_RayTracingMode: 2
|
||||
m_RenderingLayerMask: 1
|
||||
m_RendererPriority: 0
|
||||
m_Materials:
|
||||
- {fileID: 0}
|
||||
m_StaticBatchInfo:
|
||||
firstSubMesh: 0
|
||||
subMeshCount: 0
|
||||
m_StaticBatchRoot: {fileID: 0}
|
||||
m_ProbeAnchor: {fileID: 7820260671288448613}
|
||||
m_LightProbeVolumeOverride: {fileID: 0}
|
||||
m_ScaleInLightmap: 1
|
||||
m_ReceiveGI: 1
|
||||
m_PreserveUVs: 0
|
||||
m_IgnoreNormalsForChartDetection: 0
|
||||
m_ImportantGI: 0
|
||||
m_StitchLightmapSeams: 1
|
||||
m_SelectedEditorRenderState: 3
|
||||
m_MinimumChartSize: 4
|
||||
m_AutoUVMaxDistance: 0.5
|
||||
m_AutoUVMaxAngle: 89
|
||||
m_LightmapParameters: {fileID: 0}
|
||||
m_SortingLayerID: 0
|
||||
m_SortingLayer: 0
|
||||
m_SortingOrder: 0
|
||||
--- !u!114 &4914466322604787005
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 8118624344453541351}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 560fdafd46c74b2db6422fdf0e7f2363, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
InheritProbeAnchor: 2
|
||||
ProbeAnchor:
|
||||
referencePath:
|
||||
InheritBounds: 0
|
||||
RootBone:
|
||||
referencePath:
|
||||
Bounds:
|
||||
m_Center: {x: 0, y: 0, z: 0}
|
||||
m_Extent: {x: 1, y: 1, z: 1}
|
||||
--- !u!1 &8298941597190323301
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
@ -680,6 +1220,129 @@ SkinnedMeshRenderer:
|
||||
m_Center: {x: 0, y: 0, z: 0}
|
||||
m_Extent: {x: 0, y: 0, z: 0}
|
||||
m_DirtyAABB: 1
|
||||
--- !u!1 &8312581682139214105
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 1691276452827846806}
|
||||
m_Layer: 0
|
||||
m_Name: Target
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!4 &1691276452827846806
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 8312581682139214105}
|
||||
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_Children: []
|
||||
m_Father: {fileID: 4234831726961402887}
|
||||
m_RootOrder: 0
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!1 &8524827212543336267
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 4234831726961402887}
|
||||
- component: {fileID: 5041197310081425676}
|
||||
- component: {fileID: 7885810423339069945}
|
||||
m_Layer: 0
|
||||
m_Name: OverrideSet
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!4 &4234831726961402887
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 8524827212543336267}
|
||||
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_Children:
|
||||
- {fileID: 1691276452827846806}
|
||||
m_Father: {fileID: 5397716290800633055}
|
||||
m_RootOrder: 5
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!23 &5041197310081425676
|
||||
MeshRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 8524827212543336267}
|
||||
m_Enabled: 1
|
||||
m_CastShadows: 1
|
||||
m_ReceiveShadows: 1
|
||||
m_DynamicOccludee: 1
|
||||
m_MotionVectors: 1
|
||||
m_LightProbeUsage: 1
|
||||
m_ReflectionProbeUsage: 1
|
||||
m_RayTracingMode: 2
|
||||
m_RenderingLayerMask: 1
|
||||
m_RendererPriority: 0
|
||||
m_Materials:
|
||||
- {fileID: 0}
|
||||
m_StaticBatchInfo:
|
||||
firstSubMesh: 0
|
||||
subMeshCount: 0
|
||||
m_StaticBatchRoot: {fileID: 0}
|
||||
m_ProbeAnchor: {fileID: 0}
|
||||
m_LightProbeVolumeOverride: {fileID: 0}
|
||||
m_ScaleInLightmap: 1
|
||||
m_ReceiveGI: 1
|
||||
m_PreserveUVs: 0
|
||||
m_IgnoreNormalsForChartDetection: 0
|
||||
m_ImportantGI: 0
|
||||
m_StitchLightmapSeams: 1
|
||||
m_SelectedEditorRenderState: 3
|
||||
m_MinimumChartSize: 4
|
||||
m_AutoUVMaxDistance: 0.5
|
||||
m_AutoUVMaxAngle: 89
|
||||
m_LightmapParameters: {fileID: 0}
|
||||
m_SortingLayerID: 0
|
||||
m_SortingLayer: 0
|
||||
m_SortingOrder: 0
|
||||
--- !u!114 &7885810423339069945
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 8524827212543336267}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 560fdafd46c74b2db6422fdf0e7f2363, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
InheritProbeAnchor: 1
|
||||
ProbeAnchor:
|
||||
referencePath: ProbeTargetRenderers/OverrideSet/Target
|
||||
InheritBounds: 0
|
||||
RootBone:
|
||||
referencePath:
|
||||
Bounds:
|
||||
m_Center: {x: 0, y: 0, z: 0}
|
||||
m_Extent: {x: 1, y: 1, z: 1}
|
||||
--- !u!1 &9152779281672452689
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
@ -1,29 +0,0 @@
|
||||
using nadena.dev.modular_avatar.core.editor;
|
||||
using NUnit.Framework;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace modular_avatar_tests
|
||||
{
|
||||
internal class ProbeAnchorTests : TestBase
|
||||
{
|
||||
[Test]
|
||||
public void TestProbeAnchor()
|
||||
{
|
||||
var prefab = CreatePrefab("ProbeAnchorTests.prefab");
|
||||
AvatarProcessor.ProcessAvatar(prefab);
|
||||
|
||||
var root = prefab.transform.Find("RendererRoot");
|
||||
var target = prefab.transform.Find("ProbeTarget");
|
||||
var obj1 = prefab.transform.Find("RendererRoot/SkinnedMeshRenderer").GetComponent<Renderer>();
|
||||
var obj2 = prefab.transform.Find("RendererRoot/MeshRenderer").GetComponent<Renderer>();
|
||||
var obj3 = prefab.transform.Find("RendererRoot/ParticleSystemRenderer").GetComponent<Renderer>();
|
||||
var obj4 = prefab.transform.Find("RendererRoot/TrailRenderer").GetComponent<Renderer>();
|
||||
|
||||
Assert.AreEqual(target, obj1.probeAnchor);
|
||||
Assert.AreEqual(target, obj2.probeAnchor);
|
||||
Assert.AreEqual(target, obj3.probeAnchor);
|
||||
Assert.AreEqual(target, obj4.probeAnchor);
|
||||
}
|
||||
}
|
||||
}
|
@ -198,8 +198,8 @@ namespace nadena.dev.modular_avatar.core.editor
|
||||
new MenuInstallHook().OnPreprocessAvatar(avatarGameObject, context);
|
||||
new MergeArmatureHook().OnPreprocessAvatar(context, avatarGameObject);
|
||||
new BoneProxyProcessor().OnPreprocessAvatar(avatarGameObject);
|
||||
new ProbeAnchorProcessor().OnPreprocessAvatar(avatarGameObject);
|
||||
new VisibleHeadAccessoryProcessor(vrcAvatarDescriptor).Process(context);
|
||||
new MeshSettingsPass(context).OnPreprocessAvatar();
|
||||
new RemapAnimationPass(vrcAvatarDescriptor).Process(context.AnimationDatabase);
|
||||
new BlendshapeSyncAnimationProcessor().OnPreprocessAvatar(avatarGameObject, context);
|
||||
PhysboneBlockerPass.Process(avatarGameObject);
|
||||
|
@ -17,6 +17,7 @@ namespace nadena.dev.modular_avatar.core.editor
|
||||
out var avatarRoot, out var avatarHips, out var outfitHips)
|
||||
) return;
|
||||
|
||||
var outfitRoot = cmd.context as GameObject;
|
||||
var avatarArmature = avatarHips.transform.parent;
|
||||
var outfitArmature = outfitHips.transform.parent;
|
||||
|
||||
@ -28,6 +29,95 @@ namespace nadena.dev.modular_avatar.core.editor
|
||||
merge.InferPrefixSuffix();
|
||||
HeuristicBoneMapper.RenameBonesByHeuristic(merge);
|
||||
}
|
||||
|
||||
if (outfitRoot != null
|
||||
&& outfitRoot.GetComponent<ModularAvatarMeshSettings>() == null
|
||||
&& outfitRoot.GetComponentInParent<ModularAvatarMeshSettings>() == null)
|
||||
{
|
||||
var meshSettings = Undo.AddComponent<ModularAvatarMeshSettings>(outfitRoot.gameObject);
|
||||
Transform rootBone = null, probeAnchor = null;
|
||||
Bounds bounds = ModularAvatarMeshSettings.DEFAULT_BOUNDS;
|
||||
|
||||
FindConsistentSettings(avatarRoot, ref probeAnchor, ref rootBone, ref bounds);
|
||||
|
||||
if (probeAnchor == null)
|
||||
{
|
||||
probeAnchor = avatarHips.transform;
|
||||
}
|
||||
|
||||
if (rootBone == null)
|
||||
{
|
||||
rootBone = avatarRoot.transform;
|
||||
}
|
||||
|
||||
meshSettings.InheritProbeAnchor = ModularAvatarMeshSettings.InheritMode.Set;
|
||||
meshSettings.InheritBounds = ModularAvatarMeshSettings.InheritMode.Set;
|
||||
|
||||
meshSettings.ProbeAnchor = new AvatarObjectReference();
|
||||
meshSettings.ProbeAnchor.referencePath = RuntimeUtil.RelativePath(avatarRoot, probeAnchor.gameObject);
|
||||
|
||||
meshSettings.RootBone = new AvatarObjectReference();
|
||||
meshSettings.RootBone.referencePath = RuntimeUtil.RelativePath(avatarRoot, rootBone.gameObject);
|
||||
meshSettings.Bounds = bounds;
|
||||
}
|
||||
}
|
||||
|
||||
private static void FindConsistentSettings(
|
||||
GameObject avatarRoot,
|
||||
ref Transform probeAnchor,
|
||||
ref Transform rootBone,
|
||||
ref Bounds bounds
|
||||
)
|
||||
{
|
||||
// We assume the renderers directly under the avatar root came from the original avatar and are _probably_
|
||||
// set consistently. If so, we use this as a basis for the new outfit's settings.
|
||||
|
||||
bool firstRenderer = true;
|
||||
bool firstSkinnedMeshRenderer = true;
|
||||
|
||||
foreach (Transform directChild in avatarRoot.transform)
|
||||
{
|
||||
var renderer = directChild.GetComponent<Renderer>();
|
||||
if (renderer == null) continue;
|
||||
|
||||
if (firstRenderer)
|
||||
{
|
||||
probeAnchor = renderer.probeAnchor;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (renderer.probeAnchor != probeAnchor)
|
||||
{
|
||||
probeAnchor = null; // inconsistent configuration
|
||||
}
|
||||
}
|
||||
|
||||
firstRenderer = false;
|
||||
|
||||
var skinnedMeshRenderer = renderer as SkinnedMeshRenderer;
|
||||
if (skinnedMeshRenderer == null) continue;
|
||||
|
||||
if (firstSkinnedMeshRenderer)
|
||||
{
|
||||
rootBone = skinnedMeshRenderer.rootBone;
|
||||
bounds = skinnedMeshRenderer.localBounds;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (rootBone != skinnedMeshRenderer.rootBone)
|
||||
{
|
||||
rootBone = null; // inconsistent configuration
|
||||
bounds = ModularAvatarMeshSettings.DEFAULT_BOUNDS;
|
||||
}
|
||||
else if (Vector3.Distance(bounds.center, skinnedMeshRenderer.bounds.center) > 0.01f
|
||||
|| Vector3.Distance(bounds.extents, skinnedMeshRenderer.bounds.extents) > 0.01f)
|
||||
{
|
||||
bounds = ModularAvatarMeshSettings.DEFAULT_BOUNDS;
|
||||
}
|
||||
}
|
||||
|
||||
firstSkinnedMeshRenderer = false;
|
||||
}
|
||||
}
|
||||
|
||||
[MenuItem("GameObject/ModularAvatar/Setup Outfit", true, PRIORITY)]
|
||||
|
@ -1,6 +1,7 @@
|
||||
using System.Collections.Generic;
|
||||
using nadena.dev.modular_avatar.core;
|
||||
using nadena.dev.modular_avatar.core.menu;
|
||||
using NUnit.Framework;
|
||||
using UnityEngine;
|
||||
using VRC.SDK3.Avatars.Components;
|
||||
|
||||
@ -21,8 +22,6 @@ namespace nadena.dev.modular_avatar.editor.ErrorReporting
|
||||
return CheckInternal(bs);
|
||||
case ModularAvatarBoneProxy bp:
|
||||
return CheckInternal(bp);
|
||||
case ModularAvatarProbeAnchor pa:
|
||||
return CheckInternal(pa);
|
||||
case ModularAvatarMenuInstaller mi:
|
||||
return CheckInternal(mi);
|
||||
case ModularAvatarMergeAnimator obj:
|
||||
@ -137,19 +136,6 @@ namespace nadena.dev.modular_avatar.editor.ErrorReporting
|
||||
return null;
|
||||
}
|
||||
|
||||
private static List<ErrorLog> CheckInternal(ModularAvatarProbeAnchor pa)
|
||||
{
|
||||
if (pa.probeTarget == null)
|
||||
{
|
||||
return new List<ErrorLog>()
|
||||
{
|
||||
new ErrorLog(ReportLevel.Validation, "validation.probe_anchor.no_target", pa)
|
||||
};
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static List<ErrorLog> CheckInternal(ModularAvatarMenuInstaller mi)
|
||||
{
|
||||
// TODO - check that target menu is in the avatar
|
||||
|
@ -0,0 +1,122 @@
|
||||
using System;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using static nadena.dev.modular_avatar.core.editor.Localization;
|
||||
|
||||
namespace nadena.dev.modular_avatar.core.editor
|
||||
{
|
||||
[CustomPropertyDrawer(typeof(ModularAvatarMeshSettings.InheritMode))]
|
||||
class MeshSettingsInheritMode : EnumDrawer<ModularAvatarMeshSettings.InheritMode>
|
||||
{
|
||||
protected override string localizationPrefix => "mesh_settings.inherit_mode";
|
||||
}
|
||||
|
||||
[CustomEditor(typeof(ModularAvatarMeshSettings))]
|
||||
[CanEditMultipleObjects]
|
||||
internal class MeshSettingsEditor : MAEditorBase
|
||||
{
|
||||
private SerializedProperty _prop_inherit_probe_anchor;
|
||||
private SerializedProperty _prop_probe_anchor;
|
||||
|
||||
private SerializedProperty _prop_inherit_bounds;
|
||||
private SerializedProperty _prop_root_bone;
|
||||
private SerializedProperty _prop_bounds;
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
_prop_inherit_probe_anchor =
|
||||
serializedObject.FindProperty(nameof(ModularAvatarMeshSettings.InheritProbeAnchor));
|
||||
_prop_probe_anchor = serializedObject.FindProperty(nameof(ModularAvatarMeshSettings.ProbeAnchor));
|
||||
|
||||
_prop_inherit_bounds = serializedObject.FindProperty(nameof(ModularAvatarMeshSettings.InheritBounds));
|
||||
_prop_root_bone = serializedObject.FindProperty(nameof(ModularAvatarMeshSettings.RootBone));
|
||||
_prop_bounds = serializedObject.FindProperty(nameof(ModularAvatarMeshSettings.Bounds));
|
||||
}
|
||||
|
||||
protected override void OnInnerInspectorGUI()
|
||||
{
|
||||
MeshSettingsPass.MergedSettings merged = new MeshSettingsPass.MergedSettings();
|
||||
bool haveMerged = false;
|
||||
|
||||
ModularAvatarMeshSettings settings = null;
|
||||
if (targets.Length == 1)
|
||||
{
|
||||
settings = (ModularAvatarMeshSettings) target;
|
||||
var avatar = RuntimeUtil.FindAvatarInParents(settings.transform);
|
||||
if (avatar != null)
|
||||
{
|
||||
Component mesh = (Component) target;
|
||||
merged = MeshSettingsPass.MergeSettings(avatar.transform, mesh.transform);
|
||||
haveMerged = true;
|
||||
}
|
||||
}
|
||||
|
||||
serializedObject.Update();
|
||||
|
||||
EditorGUILayout.LabelField(G("mesh_settings.header_probe_anchor"), EditorStyles.boldLabel);
|
||||
EditorGUILayout.PropertyField(_prop_inherit_probe_anchor, G("mesh_settings.inherit_probe_anchor"));
|
||||
if (_prop_inherit_probe_anchor.enumValueIndex == (int) ModularAvatarMeshSettings.InheritMode.Set)
|
||||
{
|
||||
EditorGUILayout.PropertyField(_prop_probe_anchor, G("mesh_settings.probe_anchor"));
|
||||
}
|
||||
else if (_prop_inherit_probe_anchor.enumValueIndex == (int) ModularAvatarMeshSettings.InheritMode.Inherit &&
|
||||
haveMerged)
|
||||
{
|
||||
using (new EditorGUI.DisabledScope(true))
|
||||
{
|
||||
EditorGUILayout.ObjectField(G("mesh_settings.probe_anchor"), merged.ProbeAnchor, typeof(Transform),
|
||||
true);
|
||||
}
|
||||
}
|
||||
|
||||
EditorGUILayout.Separator();
|
||||
|
||||
EditorGUILayout.LabelField(G("mesh_settings.header_bounds"), EditorStyles.boldLabel);
|
||||
EditorGUILayout.PropertyField(_prop_inherit_bounds, G("mesh_settings.inherit_bounds"));
|
||||
if (_prop_inherit_bounds.enumValueIndex == (int) ModularAvatarMeshSettings.InheritMode.Set)
|
||||
{
|
||||
EditorGUILayout.PropertyField(_prop_root_bone, G("mesh_settings.root_bone"));
|
||||
EditorGUILayout.PropertyField(_prop_bounds, G("mesh_settings.bounds"));
|
||||
}
|
||||
else if (_prop_inherit_bounds.enumValueIndex == (int) ModularAvatarMeshSettings.InheritMode.Inherit &&
|
||||
haveMerged)
|
||||
{
|
||||
using (new EditorGUI.DisabledScope(true))
|
||||
{
|
||||
EditorGUILayout.ObjectField(G("mesh_settings.root_bone"), merged.RootBone, typeof(Transform), true);
|
||||
EditorGUILayout.PropertyField(_prop_bounds, G("mesh_settings.bounds"));
|
||||
}
|
||||
}
|
||||
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
|
||||
ShowLanguageUI();
|
||||
}
|
||||
|
||||
[DrawGizmo(GizmoType.Selected)]
|
||||
private static void DrawGizmo(ModularAvatarMeshSettings component, GizmoType gizmoType)
|
||||
{
|
||||
if (component.InheritBounds != ModularAvatarMeshSettings.InheritMode.Set) return;
|
||||
|
||||
Matrix4x4 oldMatrix = Gizmos.matrix;
|
||||
|
||||
Vector3 center = component.Bounds.center;
|
||||
Vector3 size = component.Bounds.size;
|
||||
|
||||
Transform rootBone = component.RootBone.Get(component)?.transform;
|
||||
try
|
||||
{
|
||||
if (rootBone != null)
|
||||
{
|
||||
Gizmos.matrix *= rootBone.localToWorldMatrix;
|
||||
}
|
||||
|
||||
Gizmos.DrawWireCube(center, size);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Gizmos.matrix = oldMatrix;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 441e32d18e0f4971be8f1853a7ceacae
|
||||
timeCreated: 1685960604
|
@ -1,39 +0,0 @@
|
||||
using UnityEditor;
|
||||
using static nadena.dev.modular_avatar.core.editor.Localization;
|
||||
|
||||
namespace nadena.dev.modular_avatar.core.editor
|
||||
{
|
||||
[CustomEditor(typeof(ModularAvatarProbeAnchor))]
|
||||
[CanEditMultipleObjects]
|
||||
internal class ProbeAnchorEditor : MAEditorBase
|
||||
{
|
||||
private SerializedProperty prop_probeTarget;
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
prop_probeTarget = serializedObject.FindProperty(nameof(ModularAvatarProbeAnchor.probeTarget));
|
||||
}
|
||||
|
||||
private void ShowParametersUI()
|
||||
{
|
||||
serializedObject.Update();
|
||||
|
||||
EditorGUILayout.PropertyField(prop_probeTarget, G("probeanchor.target"));
|
||||
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
|
||||
protected override void OnInnerInspectorGUI()
|
||||
{
|
||||
EditorGUILayout.HelpBox(S("probe_anchor.help"), MessageType.Info);
|
||||
EditorGUI.BeginChangeCheck();
|
||||
ShowParametersUI();
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
|
||||
Localization.ShowLanguageUI();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,3 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1ac49767157d7e142b4b1f277baf00ed
|
||||
timeCreated: 1664757842
|
@ -3,7 +3,6 @@
|
||||
"test0.test_b": "test_b",
|
||||
"boneproxy.foldout.advanced": "Advanced",
|
||||
"boneproxy.target": "Target",
|
||||
"probeanchor.target": "Target",
|
||||
"menuinstall.help.hint_set_menu": "This prefab will be installed to the root menu of your avatar by default. Select a different menu or uncheck the component's enabled checkbox to prevent this.",
|
||||
"menuinstall.help.hint_bad_menu": "Selected menu asset is not part of your avatar.",
|
||||
"menuinstall.installto": "Install To",
|
||||
@ -60,14 +59,25 @@
|
||||
"hint.not_in_avatar": "This component needs to be placed inside your avatar to work properly.",
|
||||
"boneproxy.err.MovingTarget": "You cannot specify a target object that will be moved by other Modular Avatar components",
|
||||
"boneproxy.err.NotInAvatar": "You must specify an object that is in the avatar",
|
||||
"probeanchor.err.NotInAvatar": "You must specify an object that is in the avatar",
|
||||
"boneproxy.attachment": "Attachment mode",
|
||||
"boneproxy.attachment.AsChildAtRoot": "As child; at root",
|
||||
"boneproxy.attachment.AsChildKeepWorldPose": "As child; keep position and rotation",
|
||||
"boneproxy.attachment.AsChildKeepPosition": "As child; keep position",
|
||||
"boneproxy.attachment.AsChildKeepRotation": "As child; keep rotation",
|
||||
"mesh_settings.header_probe_anchor": "Anchor Override Configuration",
|
||||
"mesh_settings.inherit_probe_anchor": "Anchor Override Mode",
|
||||
"mesh_settings.probe_anchor": "Anchor Override",
|
||||
"mesh_settings.probe_anchor.tooltip": "Sets the anchor override used for lighting calculations for renderers inside this object",
|
||||
"mesh_settings.header_bounds": "Bounds Override Configuration",
|
||||
"mesh_settings.inherit_bounds": "Bounds Override Mode",
|
||||
"mesh_settings.root_bone": "Root Bone",
|
||||
"mesh_settings.root_bone.tooltip": "The root bone of the mesh. This is used as a reference point from which to calculate the bounds of the mesh.",
|
||||
"mesh_settings.bounds": "Bounds",
|
||||
"mesh_settings.bounds.tooltip": "The bounds of the mesh. This is used to determine when rendering can be skipped for an offscreen mesh.",
|
||||
"mesh_settings.inherit_mode.Inherit": "Inherit",
|
||||
"mesh_settings.inherit_mode.Set": "Set",
|
||||
"mesh_settings.inherit_mode.DontSet": "Don't Set (use mesh as-is)",
|
||||
"pb_blocker.help": "This object will not be affected by PhysBones attached to parents.",
|
||||
"probe_anchor.help": "Sets the Anchor Override for the inner renderer object.",
|
||||
"hint.bad_vrcsdk": "Incompatible version of VRCSDK detected.\n\nPlease try upgrading your VRCSDK; if this does not work, check for a newer version of Modular Avatar as well.",
|
||||
"error.stack_trace": "Stack trace (provide this when reporting bugs!)",
|
||||
"error.merge_armature.merge_into_self": "Your Merge Armature component is referencing itself, or a child of itself, as the merge target. You should reference the avatar's armature instead. Do not put Merge Armature on the avatar's main armature.",
|
||||
@ -83,7 +93,6 @@
|
||||
"validation.blendshape_sync.missing_target_renderer": "No renderer found on the target object",
|
||||
"validation.blendshape_sync.missing_target_mesh": "No mesh found on the renderer on the target object",
|
||||
"validation.bone_proxy.no_target": "No target object specified (or target object not found)",
|
||||
"validation.probe_anchor.no_target": "No target object specified (or target object not found)",
|
||||
"validation.menu_installer.no_menu": "No menu to install specified",
|
||||
"validation.merge_animator.no_animator": "No animator to merge specified",
|
||||
"validation.merge_armature.no_target": "No merge target specified",
|
||||
|
@ -58,14 +58,25 @@
|
||||
"hint.not_in_avatar": "このコンポーネントが正しく動作するには、アバター内に配置する必要があります。",
|
||||
"boneproxy.err.MovingTarget": "他のモジュラーアバターコンポーネントで移動されるオブジェクトを指定できません。",
|
||||
"boneproxy.err.NotInAvatar": "アバター内のオブジェクトを指定してください。",
|
||||
"probeanchor.err.NotInAvatar": "アバター内のオブジェクトを指定してください。",
|
||||
"boneproxy.attachment": "配置モード",
|
||||
"boneproxy.attachment.AsChildAtRoot": "子として・ルートに配置",
|
||||
"boneproxy.attachment.AsChildKeepWorldPose": "子として・ワールド位置と向きを維持",
|
||||
"boneproxy.attachment.AsChildKeepPosition": "子として・ワールド位置を維持",
|
||||
"boneproxy.attachment.AsChildKeepRotation": "子として・ワールド向きを維持",
|
||||
"mesh_settings.header_probe_anchor": "Anchor Override 設定",
|
||||
"mesh_settings.inherit_probe_anchor": "設定モード",
|
||||
"mesh_settings.probe_anchor": "Anchor Override",
|
||||
"mesh_settings.probe_anchor.tooltip": "このオブジェクトとその子のレンダラーのAnchorOverrideを設定します。",
|
||||
"mesh_settings.header_bounds": "Bounds 設定",
|
||||
"mesh_settings.inherit_bounds": "設定モード",
|
||||
"mesh_settings.root_bone": "Root Bone",
|
||||
"mesh_settings.root_bone.tooltip": "このオブジェクトとその子のメッシュで設定されるルートボーン。メッシュのバウンズを計算するための参照点として使用されます。",
|
||||
"mesh_settings.bounds": "Bounds",
|
||||
"mesh_settings.bounds.tooltip": "このオブジェクトとその子のメッシュで設定されるバウンズ。画面外のメッシュのレンダリングを省略するかどうかを決定するために使用されます。",
|
||||
"mesh_settings.inherit_mode.Inherit": "継承",
|
||||
"mesh_settings.inherit_mode.Set": "設定",
|
||||
"mesh_settings.inherit_mode.DontSet": "設定しない(メッシュ本体の設定のまま)",
|
||||
"pb_blocker.help": "このオブジェクトは親のPhysBoneから影響を受けなくなります。",
|
||||
"probe_anchor.help": "このオブジェクトに含まれるレンダラーのAnchorOverrideを設定します。",
|
||||
"hint.bad_vrcsdk": "使用中のVRCSDKのバージョンとは互換性がありません。\n\nVRCSDKを更新してみてください。それでもだめでしたら、Modular Avatarにも最新版が出てないかチェックしてください。",
|
||||
"error.stack_trace": "スタックトレース(バグを報告する時は必ず添付してください!)",
|
||||
"error.merge_armature.merge_into_self": "Merge Armatureに自分自身のオブジェクト、もしくは自分の子をターゲットにしてしています。かわりにアバターのメインArmatureを指定してください。アバター自体のArmatureに追加しないでください。",
|
||||
@ -81,7 +92,6 @@
|
||||
"validation.blendshape_sync.missing_target_renderer": "同期元のオブジェクトにはSkinnedMeshRendererがありません。",
|
||||
"validation.blendshape_sync.missing_target_mesh": "同期元のオブジェクトにはSkinnedMeshRendererがありますが、メッシュがありません。",
|
||||
"validation.bone_proxy.no_target": "ターゲットオブジェクトが未設定、もしくは存在しません。",
|
||||
"validation.probe_anchor.no_target": "ターゲットオブジェクトが未設定、もしくは存在しません。",
|
||||
"validation.menu_installer.no_menu": "インストールするメニューがありません。",
|
||||
"validation.merge_animator.no_animator": "Animator Controllerがありません。",
|
||||
"validation.merge_armature.no_target": "ターゲットオブジェクトが未設定、もしくは存在しません。",
|
||||
|
@ -1,7 +1,6 @@
|
||||
{
|
||||
"boneproxy.foldout.advanced": "高级设置",
|
||||
"boneproxy.target": "目标",
|
||||
"probeanchor.target": "目标",
|
||||
"menuinstall.help.hint_set_menu": "此预制体的菜单默认会安装Avatar的顶部菜单中. 如果不需要, 可以选择其他菜单或取消勾选启用复选框.",
|
||||
"menuinstall.help.hint_bad_menu": "选择的菜单不属于当前Avatar.",
|
||||
"menuinstall.installto": "安装到",
|
||||
@ -53,11 +52,9 @@
|
||||
"hint.not_in_avatar": "此组件需要放置于你的Avatar中才能工作",
|
||||
"boneproxy.err.MovingTarget": "您不能指定将由其他 Modular Avatar 组件移动的目标对象",
|
||||
"boneproxy.err.NotInAvatar": "你必须指定一个在Avatar中的对象",
|
||||
"probeanchor.err.NotInAvatar": "你必须指定一个在Avatar中的对象",
|
||||
"boneproxy.attachment": "附加模式",
|
||||
"boneproxy.attachment.AsChildAtRoot": "作为子对象, 放置于Root",
|
||||
"boneproxy.attachment.AsChildKeepWorldPosition": "作为子对象, 保持原有位置",
|
||||
"pb_blocker.help": "当前对象不会受到附加的父对象的PhysBones的影响.",
|
||||
"probe_anchor.help": "设置此对象所包含的渲染器的AnchorOverride",
|
||||
"hint.bad_vrcsdk": "检测到不兼容的VRCSDK版本.\n\n请尝试升级VRCSDK; 如果这不起作用, 请尝试新版本的Modular Avatar."
|
||||
}
|
110
Packages/nadena.dev.modular-avatar/Editor/MeshSettingsPass.cs
Normal file
110
Packages/nadena.dev.modular-avatar/Editor/MeshSettingsPass.cs
Normal file
@ -0,0 +1,110 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace nadena.dev.modular_avatar.core.editor
|
||||
{
|
||||
internal static class InheritModeExtension
|
||||
{
|
||||
internal static bool NotFinal(this ModularAvatarMeshSettings.InheritMode mode)
|
||||
{
|
||||
return mode == ModularAvatarMeshSettings.InheritMode.Inherit;
|
||||
}
|
||||
}
|
||||
|
||||
internal class MeshSettingsPass
|
||||
{
|
||||
private readonly BuildContext context;
|
||||
|
||||
public MeshSettingsPass(BuildContext context)
|
||||
{
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
public void OnPreprocessAvatar()
|
||||
{
|
||||
foreach (var mesh in context.AvatarDescriptor.GetComponentsInChildren<Renderer>(true))
|
||||
{
|
||||
ProcessMesh(mesh);
|
||||
}
|
||||
}
|
||||
|
||||
internal struct MergedSettings
|
||||
{
|
||||
public bool SetAnchor, SetBounds;
|
||||
|
||||
public Transform ProbeAnchor;
|
||||
public Transform RootBone;
|
||||
public Bounds Bounds;
|
||||
}
|
||||
|
||||
private static bool Inherit(ref ModularAvatarMeshSettings.InheritMode mode,
|
||||
ModularAvatarMeshSettings.InheritMode srcmode)
|
||||
{
|
||||
if (mode != ModularAvatarMeshSettings.InheritMode.Inherit ||
|
||||
srcmode == ModularAvatarMeshSettings.InheritMode.Inherit)
|
||||
return false;
|
||||
|
||||
mode = srcmode;
|
||||
return true;
|
||||
}
|
||||
|
||||
internal static MergedSettings MergeSettings(Transform avatarRoot, Transform referenceObject)
|
||||
{
|
||||
MergedSettings merged = new MergedSettings();
|
||||
|
||||
Transform current = referenceObject;
|
||||
|
||||
ModularAvatarMeshSettings.InheritMode inheritProbeAnchor = ModularAvatarMeshSettings.InheritMode.Inherit;
|
||||
ModularAvatarMeshSettings.InheritMode inheritBounds = ModularAvatarMeshSettings.InheritMode.Inherit;
|
||||
|
||||
do
|
||||
{
|
||||
var settings = current.GetComponent<ModularAvatarMeshSettings>();
|
||||
if (current == avatarRoot)
|
||||
{
|
||||
current = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
current = current.transform.parent;
|
||||
}
|
||||
|
||||
if (settings == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (Inherit(ref inheritProbeAnchor, settings.InheritProbeAnchor))
|
||||
{
|
||||
merged.ProbeAnchor = settings.ProbeAnchor.Get(settings)?.transform;
|
||||
}
|
||||
|
||||
if (Inherit(ref inheritBounds, settings.InheritBounds))
|
||||
{
|
||||
merged.RootBone = settings.RootBone.Get(settings)?.transform;
|
||||
merged.Bounds = settings.Bounds;
|
||||
}
|
||||
} while (current != null && (inheritProbeAnchor.NotFinal() || inheritBounds.NotFinal()));
|
||||
|
||||
merged.SetAnchor = inheritProbeAnchor == ModularAvatarMeshSettings.InheritMode.Set;
|
||||
merged.SetBounds = inheritBounds == ModularAvatarMeshSettings.InheritMode.Set;
|
||||
|
||||
return merged;
|
||||
}
|
||||
|
||||
private void ProcessMesh(Renderer mesh)
|
||||
{
|
||||
MergedSettings settings = MergeSettings(context.AvatarDescriptor.transform, mesh.transform);
|
||||
|
||||
if (settings.SetAnchor)
|
||||
{
|
||||
mesh.probeAnchor = settings.ProbeAnchor;
|
||||
}
|
||||
|
||||
if (settings.SetBounds && mesh is SkinnedMeshRenderer smr)
|
||||
{
|
||||
smr.rootBone = settings.RootBone;
|
||||
smr.localBounds = settings.Bounds;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 06b7e7286f434327b1d0ef4b60496055
|
||||
timeCreated: 1685960001
|
@ -1,75 +0,0 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2022 bd_
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
using nadena.dev.modular_avatar.editor.ErrorReporting;
|
||||
using UnityEngine;
|
||||
|
||||
namespace nadena.dev.modular_avatar.core.editor
|
||||
{
|
||||
internal class ProbeAnchorProcessor
|
||||
{
|
||||
internal enum ValidationResult
|
||||
{
|
||||
OK,
|
||||
NotInAvatar
|
||||
}
|
||||
|
||||
internal void OnPreprocessAvatar(GameObject avatarGameObject)
|
||||
{
|
||||
var boneProxies = avatarGameObject.GetComponentsInChildren<ModularAvatarProbeAnchor>(true);
|
||||
|
||||
foreach (var proxy in boneProxies)
|
||||
{
|
||||
BuildReport.ReportingObject(proxy, () => ProcessAnchor(avatarGameObject, proxy));
|
||||
}
|
||||
}
|
||||
|
||||
private void ProcessAnchor(GameObject avatarGameObject, ModularAvatarProbeAnchor proxy)
|
||||
{
|
||||
if (proxy.probeTarget.Get(proxy) != null && ValidateTarget(avatarGameObject, proxy.probeTarget.Get(proxy).transform) == ValidationResult.OK)
|
||||
{
|
||||
foreach (Renderer r in proxy.GetComponentsInChildren<Renderer>(true))
|
||||
{
|
||||
r.probeAnchor = proxy.probeTarget.Get(proxy).transform;
|
||||
}
|
||||
}
|
||||
|
||||
Object.DestroyImmediate(proxy);
|
||||
}
|
||||
|
||||
internal static ValidationResult ValidateTarget(GameObject avatarGameObject, Transform proxyTarget)
|
||||
{
|
||||
var avatar = avatarGameObject.transform;
|
||||
var node = proxyTarget;
|
||||
|
||||
while (node != null && node != avatar)
|
||||
{
|
||||
node = node.parent;
|
||||
}
|
||||
|
||||
if (node == null) return ValidationResult.NotInAvatar;
|
||||
else return ValidationResult.OK;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,3 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cdb66cfc3a147a849810baa9315df90f
|
||||
timeCreated: 1661649405
|
@ -125,15 +125,16 @@ namespace nadena.dev.modular_avatar.core.editor
|
||||
return;
|
||||
}
|
||||
|
||||
SetGizmoIconEnabled(typeof(ModularAvatarBoneProxy), false);
|
||||
SetGizmoIconEnabled(typeof(ModularAvatarProbeAnchor), false);
|
||||
SetGizmoIconEnabled(typeof(ModularAvatarBlendshapeSync), false);
|
||||
SetGizmoIconEnabled(typeof(ModularAvatarMenuInstaller), false);
|
||||
SetGizmoIconEnabled(typeof(ModularAvatarMergeAnimator), false);
|
||||
SetGizmoIconEnabled(typeof(ModularAvatarMergeArmature), false);
|
||||
SetGizmoIconEnabled(typeof(ModularAvatarParameters), false);
|
||||
SetGizmoIconEnabled(typeof(ModularAvatarPBBlocker), false);
|
||||
SetGizmoIconEnabled(typeof(ModularAvatarVisibleHeadAccessory), false);
|
||||
foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
|
||||
{
|
||||
foreach (var ty in assembly.GetTypes())
|
||||
{
|
||||
if (typeof(AvatarTagComponent).IsAssignableFrom(ty) && !ty.IsAbstract)
|
||||
{
|
||||
SetGizmoIconEnabled(ty, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EditorApplication.update -= DisableMAGizmoIcons;
|
||||
SessionState.GetBool("MAIconsDisabled", true);
|
||||
|
@ -15,7 +15,7 @@ namespace nadena.dev.modular_avatar.core
|
||||
|
||||
public GameObject Get(Component container)
|
||||
{
|
||||
if (_cacheValid && _cachedPath == referencePath) return _cachedReference;
|
||||
if (_cacheValid && _cachedPath == referencePath && _cachedReference != null) return _cachedReference;
|
||||
|
||||
_cacheValid = true;
|
||||
_cachedPath = referencePath;
|
||||
|
@ -0,0 +1,30 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Serialization;
|
||||
|
||||
namespace nadena.dev.modular_avatar.core
|
||||
{
|
||||
[AddComponentMenu("Modular Avatar/MA Mesh Settings")]
|
||||
[DisallowMultipleComponent]
|
||||
public class ModularAvatarMeshSettings : AvatarTagComponent
|
||||
{
|
||||
internal static readonly Bounds DEFAULT_BOUNDS = new Bounds(Vector3.zero, Vector3.one * 2);
|
||||
|
||||
[Serializable]
|
||||
public enum InheritMode
|
||||
{
|
||||
Inherit,
|
||||
Set,
|
||||
DontSet
|
||||
}
|
||||
|
||||
//[Header("Probe anchor configuration")]
|
||||
public InheritMode InheritProbeAnchor = InheritMode.Inherit;
|
||||
public AvatarObjectReference ProbeAnchor;
|
||||
|
||||
//[Header("Bounds configuration")]
|
||||
public InheritMode InheritBounds = InheritMode.Inherit;
|
||||
public AvatarObjectReference RootBone;
|
||||
public Bounds Bounds = DEFAULT_BOUNDS;
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b18784296c2581e498e5127a23e6f019
|
||||
guid: 560fdafd46c74b2db6422fdf0e7f2363
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
@ -1,38 +0,0 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2022 bd_
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace nadena.dev.modular_avatar.core
|
||||
{
|
||||
[ExecuteInEditMode]
|
||||
[DisallowMultipleComponent]
|
||||
[AddComponentMenu("Modular Avatar/MA Probe Anchor")]
|
||||
public class ModularAvatarProbeAnchor : AvatarTagComponent
|
||||
{
|
||||
public AvatarObjectReference probeTarget;
|
||||
}
|
||||
}
|
33
docs/docs/reference/mesh-settings.md
Normal file
33
docs/docs/reference/mesh-settings.md
Normal file
@ -0,0 +1,33 @@
|
||||
# Mesh Settings
|
||||
|
||||
![Mesh Settings](mesh-settings.png)
|
||||
|
||||
The Mesh Settings component lets you set certain mesh settings (anchor override and bounds) for all meshes
|
||||
under a particular game object.
|
||||
|
||||
## When should I use it?
|
||||
|
||||
You can place this component at the top level of your avatar to ensure that bounds and light probe anchors
|
||||
are consistent for all meshes in your avatar.
|
||||
|
||||
The "Setup Outfit" feature will also automatically configure a Mesh Settings component on newly added outfits.
|
||||
|
||||
Finally, Mesh Settings can be used to _exclude_ meshes from the influence of Mesh Settings higher up on the
|
||||
hierarchy.
|
||||
|
||||
## When shouldn't I use it?
|
||||
|
||||
Setting bounds or light probes on assets for distribution requires some care, as these configurations
|
||||
might be inconsistent with the avatar they are applied to. Generally, these should only be set on assets
|
||||
designed for a specific avatar.
|
||||
|
||||
## Manually configuring Mesh Settings
|
||||
|
||||
When you add Mesh Settings to a game object, initially it is configured to do nothing. By setting either
|
||||
"Anchor Override Mode" or "Bounds Override Mode" to "Set", you can configure the anchor override or bounds
|
||||
for all meshes under that game object. Alternately, by setting the mode to "Don't set", you can exclude
|
||||
these meshes from the influence of Mesh Settings higher up on the hierarchy.
|
||||
|
||||
When configuring bounds, the bounding box will be determined relative to the transform you specify as the
|
||||
"Root Bone". Note that bounds only affects Skinned Mesh Renderers, but Anchor Override also impacts other
|
||||
types of renderers like Mesh Renderers or Line Renderers.
|
BIN
docs/docs/reference/mesh-settings.png
Normal file
BIN
docs/docs/reference/mesh-settings.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 34 KiB |
@ -0,0 +1,30 @@
|
||||
# Mesh Settings
|
||||
|
||||
![Mesh Settings](mesh-settings.png)
|
||||
|
||||
Mesh Settingsコンポーネントを使用すると、特定のゲームオブジェクトの配下にあるすべてのメッシュに対して、特定のメッシュ設定
|
||||
(アンカーオーバーライドとバウンズ)を設定できます。
|
||||
|
||||
## いつ使うべきか
|
||||
|
||||
このコンポーネントをアバターの最上位レベルに配置すると、アバター内のすべてのメッシュに対してバウンズとライトプローブアンカーが
|
||||
一貫して設定されるようになります。
|
||||
|
||||
「Setup Outfit」機能は、新しく追加されたアウトフィットに自動的にMesh Settingsコンポーネントを自動的に設定します。
|
||||
|
||||
最後に、Mesh Settingsは、階層の上位にあるMesh Settingsの影響を受けないように、メッシュを除外するためにも使用できます。
|
||||
|
||||
## いつ使うべきでないか
|
||||
|
||||
配布用のアセットにバウンズやライトプローブを設定する時は注意が必要です。なぜなら、これらの設定がアバターと一致しない可能性が
|
||||
あります。一般的に、特定のアバター用に設計されたアセットの場合のみ設定を推奨します。
|
||||
|
||||
## Mesh Settingsの手動設定
|
||||
|
||||
ゲームオブジェクトにMesh Settingsを追加すると、最初は何も効果がありません。Anchor Overrideの設定モードまたはBounds Override
|
||||
の設定モードを「設定」に設定することで、そのゲームオブジェクトの下にあるすべてのメッシュのアンカーオーバーライドまたはバウンズ
|
||||
を設定できます。また、モードを「設定しない」に設定することで、これらのメッシュを階層の上位にあるMesh Settingsの影響から除外できます。
|
||||
|
||||
バウンズを設定する場合、バウンディングボックスは「Root Bone」として指定したトランスフォームに対して相対的に決定されます。
|
||||
また、バウンズはSkinned Mesh Rendererのみに影響しますが、Anchor OverrideはMesh RendererやLine Rendererなどの他のタイプの
|
||||
Rendererにも設定されます。
|
Binary file not shown.
After Width: | Height: | Size: 32 KiB |
Loading…
Reference in New Issue
Block a user