diff --git a/Packages/dev.hackebein.object-tracking/Assets.meta b/Packages/dev.hackebein.object-tracking/Assets.meta new file mode 100644 index 0000000..d169384 --- /dev/null +++ b/Packages/dev.hackebein.object-tracking/Assets.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 4ff4625f4f83cf344af6909b8a7ab6d4 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/dev.hackebein.object-tracking/Assets/World.prefab b/Packages/dev.hackebein.object-tracking/Assets/World.prefab new file mode 100644 index 0000000..e4ab1e8 --- /dev/null +++ b/Packages/dev.hackebein.object-tracking/Assets/World.prefab @@ -0,0 +1,32 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &4508875353715765265 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1720321125886419532} + m_Layer: 0 + m_Name: GameObject + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 4294967295 + m_IsActive: 1 +--- !u!4 &1720321125886419532 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4508875353715765265} + 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: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} diff --git a/Packages/dev.hackebein.object-tracking/Assets/World.prefab.meta b/Packages/dev.hackebein.object-tracking/Assets/World.prefab.meta new file mode 100644 index 0000000..45032d8 --- /dev/null +++ b/Packages/dev.hackebein.object-tracking/Assets/World.prefab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 453612a48b1f5d144aa17679ece31e2e +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/dev.hackebein.object-tracking/Editor/Editor.cs b/Packages/dev.hackebein.object-tracking/Editor/Editor.cs index 2caed3f..4e467ca 100644 --- a/Packages/dev.hackebein.object-tracking/Editor/Editor.cs +++ b/Packages/dev.hackebein.object-tracking/Editor/Editor.cs @@ -49,14 +49,14 @@ private void LabelAccuracy(int range, int bits, string suffix, GUILayoutOption[] // ;) GUILayout.Label("^,....^ remember i love you", guiLayoutOption); } - else if (suffix == "m" && accuracy < 0.01) + else if (suffix == "m" && accuracy < 0.002) { - GUILayout.Label("<0.01" + suffix, guiLayoutOption); - GUILayout.Label("<0.4in", guiLayoutOption); + GUILayout.Label("<0.002" + suffix, guiLayoutOption); + GUILayout.Label("<0.8in", guiLayoutOption); } - else if (suffix == "°" && accuracy < 0.1) + else if (suffix == "°" && accuracy < 0.5) { - GUILayout.Label("<0.1" + suffix, guiLayoutOption); + GUILayout.Label("<0.5" + suffix, guiLayoutOption); } else if (bits > 0 && suffix == "m") { @@ -139,8 +139,7 @@ public override void OnInspectorGUI() { path = EditorUtility.OpenFolderPanel("Select asset folder", path, "").Replace(Application.dataPath, "Assets"); } - - if (!path.StartsWith("Assets/")) + if (GUILayout.Button("Reset") || !path.StartsWith("Assets/")) { path = "Assets/Hackebein/ObjectTracking/Generated"; } @@ -161,6 +160,17 @@ public override void OnInspectorGUI() } } } + + using (new GUILayout.HorizontalScope()) + { + GUILayout.Label("Oriantation Mode:"); + EditorGUILayout.Popup(1, new string[] + { + "Animation (coming soon)", + "Constraint", + }, RelativeWidth(3 / 5f)); + } + } else { @@ -253,6 +263,8 @@ public override void OnInspectorGUI() } } + // TODO: support GoGoLoco and similar systems + // TODO: Multi configuration support foreach (SetupTracker tracker in setup.trackers) { using (new GUILayout.VerticalScope("box")) @@ -278,7 +290,6 @@ public override void OnInspectorGUI() "None", "Hackebein - X-Pole Pole Silkii mount (coming soon)", "Hackebein - X-Pole Aerial Hoop mount (coming soon)", - "Jangxx - Bottle Mount (coming soon)", // https://www.thingiverse.com/thing:4732305 }, RelativeWidth(3 / 5f)); // TODO: show extra information about the prefab (License, Author, URL, etc.) @@ -297,6 +308,21 @@ public override void OnInspectorGUI() }, RelativeWidth(3 / 5f)); } } + if (setup.mode == Utility.Modes.Expert) + { + using (new GUILayout.HorizontalScope()) + { + GUILayout.Label("Smoothing:"); + // TODO: Implement Smoothing Types + EditorGUILayout.Popup(0, new string[] + { + "Exponential (VRC Phys Bone, PC only)", + "Exponential (Animator) (coming soon)", // https://notes.sleightly.dev/Smoothing-Exponential-019e9e69f617451dabd8d64554e09671 + "Damped (Animator) (coming soon)", // https://notes.sleightly.dev/Smoothed-Float-Half-21fe757e52da4e589e2b30997f459f44 + "Linear (Animator) (coming soon)", // Assets/JelleScripts/Linear/Timing + }, RelativeWidth(3 / 5f)); + } + } if (setup.mode >= Utility.Modes.Advanced) { @@ -368,6 +394,7 @@ public override void OnInspectorGUI() using (new GUILayout.VerticalScope()) { + // TODO: add support for >32 bits tracker.bitsRPX = RangeNumberInputField(tracker.bitsRPX, 0, 32, RelativeWidth((float)1 / 5)); tracker.bitsRPX = SliderNumberInputField(tracker.bitsRPX, 0, 32, RelativeWidth((float)1 / 5)); } @@ -452,6 +479,7 @@ public override void OnInspectorGUI() using (new GUILayout.VerticalScope()) { + // TODO: add support for >32 bits tracker.bitsRPY = RangeNumberInputField(tracker.bitsRPY, 0, 32, RelativeWidth((float)1 / 5)); tracker.bitsRPY = SliderNumberInputField(tracker.bitsRPY, 0, 32, RelativeWidth((float)1 / 5)); } @@ -536,6 +564,7 @@ public override void OnInspectorGUI() using (new GUILayout.VerticalScope()) { + // TODO: add support for >32 bits tracker.bitsRPZ = RangeNumberInputField(tracker.bitsRPZ, 0, 32, RelativeWidth((float)1 / 5)); tracker.bitsRPZ = SliderNumberInputField(tracker.bitsRPZ, 0, 32, RelativeWidth((float)1 / 5)); } @@ -940,6 +969,7 @@ public override void OnInspectorGUI() using (new GUILayout.VerticalScope()) { + // TODO: add support for >32 bits positionBits = RangeNumberInputField(positionBits, 0, 32, RelativeWidth((float)1 / 4)); positionBits = SliderNumberInputField(positionBits, 0, 32, RelativeWidth((float)1 / 4)); } @@ -1026,10 +1056,11 @@ public override void OnInspectorGUI() bool isTrackersValid = setup.trackers.Count != 0; string[] trackerNames = new string[setup.trackers.Count]; + string[] protectedNames = new string[]{"device", "index", "value", "global"}; foreach (SetupTracker tracker in setup.trackers) { string name = tracker.name; - if (name.Length == 0 || Array.Exists(trackerNames, trackerName => trackerName == name)) + if (name.Length == 0 || Array.Exists(trackerNames, trackerName => trackerName == name) || Array.Exists(protectedNames, protectedName => protectedName == name)) { isTrackersValid = false; break; diff --git a/Packages/dev.hackebein.object-tracking/Prefab/Tundra Labs Tundra Tracker strap.fbx b/Packages/dev.hackebein.object-tracking/Prefab/Tundra Labs Tundra Tracker strap.fbx new file mode 100644 index 0000000..783a21c Binary files /dev/null and b/Packages/dev.hackebein.object-tracking/Prefab/Tundra Labs Tundra Tracker strap.fbx differ diff --git a/Packages/dev.hackebein.object-tracking/Prefab/Tundra Labs Tundra Tracker strap.fbx.meta b/Packages/dev.hackebein.object-tracking/Prefab/Tundra Labs Tundra Tracker strap.fbx.meta new file mode 100644 index 0000000..a755378 --- /dev/null +++ b/Packages/dev.hackebein.object-tracking/Prefab/Tundra Labs Tundra Tracker strap.fbx.meta @@ -0,0 +1,109 @@ +fileFormatVersion: 2 +guid: 845b044e978ab7e43b62ff38a653b75e +ModelImporter: + serializedVersion: 22200 + internalIDToNameTable: [] + externalObjects: {} + materials: + materialImportMode: 2 + materialName: 0 + materialSearch: 1 + materialLocation: 1 + animations: + legacyGenerateAnimations: 4 + bakeSimulation: 0 + resampleCurves: 1 + optimizeGameObjects: 0 + removeConstantScaleCurves: 0 + motionNodeName: + rigImportErrors: + rigImportWarnings: + animationImportErrors: + animationImportWarnings: + animationRetargetingWarnings: + animationDoRetargetingWarnings: 0 + importAnimatedCustomProperties: 0 + importConstraints: 0 + animationCompression: 1 + animationRotationError: 0.5 + animationPositionError: 0.5 + animationScaleError: 0.5 + animationWrapMode: 0 + extraExposedTransformPaths: [] + extraUserProperties: [] + clipAnimations: [] + isReadable: 0 + meshes: + lODScreenPercentages: [] + globalScale: 1 + meshCompression: 0 + addColliders: 0 + useSRGBMaterialColor: 1 + sortHierarchyByName: 1 + importPhysicalCameras: 1 + importVisibility: 1 + importBlendShapes: 1 + importCameras: 1 + importLights: 1 + nodeNameCollisionStrategy: 1 + fileIdsGeneration: 2 + swapUVChannels: 0 + generateSecondaryUV: 0 + useFileUnits: 1 + keepQuads: 0 + weldVertices: 1 + bakeAxisConversion: 0 + preserveHierarchy: 0 + skinWeightsMode: 0 + maxBonesPerVertex: 4 + minBoneWeight: 0.001 + optimizeBones: 1 + meshOptimizationFlags: -1 + indexFormat: 0 + secondaryUVAngleDistortion: 8 + secondaryUVAreaDistortion: 15.000001 + secondaryUVHardAngle: 88 + secondaryUVMarginMethod: 1 + secondaryUVMinLightmapResolution: 40 + secondaryUVMinObjectScale: 1 + secondaryUVPackMargin: 4 + useFileScale: 1 + strictVertexDataChecks: 0 + tangentSpace: + normalSmoothAngle: 60 + normalImportMode: 0 + tangentImportMode: 3 + normalCalculationMode: 4 + legacyComputeAllNormalsFromSmoothingGroupsWhenMeshHasBlendShapes: 0 + blendShapeNormalImportMode: 1 + normalSmoothingSource: 0 + referencedClips: [] + importAnimation: 1 + humanDescription: + serializedVersion: 3 + human: [] + skeleton: [] + armTwist: 0.5 + foreArmTwist: 0.5 + upperLegTwist: 0.5 + legTwist: 0.5 + armStretch: 0.05 + legStretch: 0.05 + feetSpacing: 0 + globalScale: 1 + rootMotionBoneName: + hasTranslationDoF: 0 + hasExtraRoot: 0 + skeletonHasParents: 1 + lastHumanDescriptionAvatarSource: {instanceID: 0} + autoGenerateAvatarMappingIfUnspecified: 1 + animationType: 2 + humanoidOversampling: 1 + avatarSetup: 0 + addHumanoidExtraRootOnlyWhenUsingAvatar: 1 + importBlendShapeDeformPercent: 1 + remapMaterialsIfMaterialImportModeIsNone: 0 + additionalBone: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/dev.hackebein.object-tracking/Runtime/Setup.cs b/Packages/dev.hackebein.object-tracking/Runtime/Setup.cs index 9117c0a..d1d090f 100644 --- a/Packages/dev.hackebein.object-tracking/Runtime/Setup.cs +++ b/Packages/dev.hackebein.object-tracking/Runtime/Setup.cs @@ -52,8 +52,15 @@ public static int CountMaxExpressionParameters() public int CountExpectedExpressionParameters() { int costs = 0; + costs++; // config/global + costs++; // config/index + costs++; // config/value + costs++; // isRemotePreview + costs++; // goStabilized + costs++; // isStabilized foreach (SetupTracker tracker in trackers) { + costs++; // config/ costs += tracker.GetExpressionParameters(); } @@ -130,33 +137,37 @@ public void Create() Remove(); // ignore animation - ignoreClip = Utility.CreateClip("ignore", "_ignore", "IsActive", 0, 0, assetFolder); + ignoreClip = Utility.CreateClip("ignore", "_ignore", "m_IsActive", 0, 0, assetFolder); // Parameters controller = Utility.CreateBoolParameterAndAddToAnimator(controller, "IsLocal"); - controller = Utility.CreateBoolParameterAndAddToAnimator(controller, "ObjectTracking/IsRemotePreview"); + controller = Utility.CreateBoolParameterAndAddToAnimator(controller, "ObjectTracking/isRemotePreview"); + controller = Utility.CreateBoolParameterAndAddToAnimator(controller, "ObjectTracking/goStabilized"); + controller = Utility.CreateBoolParameterAndAddToAnimator(controller, "ObjectTracking/isStabilized"); controller = Utility.CreateBoolParameterAndAddToAnimator(controller, "ObjectTracking/config/global"); + controller = Utility.CreateIntParameterAndAddToAnimator(controller, "ObjectTracking/config/index"); + controller = Utility.CreateIntParameterAndAddToAnimator(controller, "ObjectTracking/config/value"); - expressionParameters = Utility.CreateBoolParameterAndAddToExpressionParameters(expressionParameters, "ObjectTracking/IsRemotePreview", false, false, false); + expressionParameters = Utility.CreateBoolParameterAndAddToExpressionParameters(expressionParameters, "ObjectTracking/isRemotePreview", false, false, false); + expressionParameters = Utility.CreateBoolParameterAndAddToExpressionParameters(expressionParameters, "ObjectTracking/goStabilized", false, false, false); + expressionParameters = Utility.CreateBoolParameterAndAddToExpressionParameters(expressionParameters, "ObjectTracking/isStabilized", false, false, false); expressionParameters = Utility.CreateBoolParameterAndAddToExpressionParameters(expressionParameters, "ObjectTracking/config/global", false, false, false); + expressionParameters = Utility.CreateIntParameterAndAddToExpressionParameters(expressionParameters, "ObjectTracking/config/index", 0, false, false); + expressionParameters = Utility.CreateIntParameterAndAddToExpressionParameters(expressionParameters, "ObjectTracking/config/value", 0, false, false); foreach (SetupTracker tracker in trackers) { controller = Utility.CreateBoolParameterAndAddToAnimator(controller, "ObjectTracking/config/" + tracker.name); expressionParameters = Utility.CreateBoolParameterAndAddToExpressionParameters(expressionParameters, "ObjectTracking/config/" + tracker.name, false, false, false); } - for (int i = 0; i < 30; i++) - { - controller = Utility.CreateIntParameterAndAddToAnimator(controller, "ObjectTracking/config/value" + i); - expressionParameters = Utility.CreateIntParameterAndAddToExpressionParameters(expressionParameters, "ObjectTracking/config/value" + i, 0, false, false); - } foreach (SetupTracker tracker in trackers) { tracker.AppendAnimatorControllerParameters(controller); } - // Object for scaling + // Object for scaling and z-offset GameObject scaleGameObject = Utility.FindOrCreateEmptyGameObject("ObjectTracking", rootGameObject); Utility.ResetGameObject(scaleGameObject); + // TODO: get z-offset from AvatarDescriptor // Objects for tracking foreach (SetupTracker tracker in trackers) @@ -169,6 +180,7 @@ public void Create() // Animation Controller CreateProcessingLayer(); + CreateStabilizationLayer(); foreach (SetupTracker tracker in trackers) { tracker.AppendTransitionLayers(controller, assetFolder + "/" + uuid); @@ -215,10 +227,10 @@ private void CreateProcessingLayer() Dictionary propsInit = new Dictionary { - { new[] { "ObjectTracking", "IsActive" }, new[] { 1f, 1f } }, + { new[] { "ObjectTracking", "m_IsActive" }, new[] { 1f, 1f } }, { new[] { "ObjectTracking", "m_LocalPosition.x" }, new[] { 0f, 0f } }, { new[] { "ObjectTracking", "m_LocalPosition.y" }, new[] { 0f, 0f } }, - { new[] { "ObjectTracking", "m_LocalPosition.z" }, new[] { 0f, 0f } }, + { new[] { "ObjectTracking", "m_LocalPosition.z" }, new[] { 0f, 0f } }, // TODO: get from AvatarDescriptor { new[] { "ObjectTracking", "m_LocalRotation.x" }, new[] { 0f, 0f } }, { new[] { "ObjectTracking", "m_LocalRotation.y" }, new[] { 0f, 0f } }, { new[] { "ObjectTracking", "m_LocalRotation.z" }, new[] { 0f, 0f } }, @@ -252,11 +264,82 @@ private void CreateProcessingLayer() List parameterDriverParametersLocal = new List { + Utility.ParameterDriverParameterSet("ObjectTracking/config/index", 0), + Utility.ParameterDriverParameterSet("ObjectTracking/config/value", 0), + Utility.ParameterDriverParameterSet("ObjectTracking/config/global", true), + Utility.ParameterDriverParameterSet("ObjectTracking/config/value", 1), // version number + Utility.ParameterDriverParameterSet("ObjectTracking/config/index", 1), Utility.ParameterDriverParameterSet("ObjectTracking/config/global", false), + Utility.ParameterDriverParameterSet("ObjectTracking/config/index", 0), + Utility.ParameterDriverParameterSet("ObjectTracking/config/value", 0), }; - foreach (SetupTracker tracker in trackers) + for (int i = 0; i < trackers.Count; i++) { + SetupTracker tracker = trackers[i]; + parameterDriverParametersLocal.Add(Utility.ParameterDriverParameterSet("ObjectTracking/config/" + tracker.name, true)); + parameterDriverParametersLocal.Add(Utility.ParameterDriverParameterSet("ObjectTracking/config/value", tracker.bitsRPX)); + parameterDriverParametersLocal.Add(Utility.ParameterDriverParameterSet("ObjectTracking/config/index", 1)); + parameterDriverParametersLocal.Add(Utility.ParameterDriverParameterSet("ObjectTracking/config/value", tracker.bitsRPY)); + parameterDriverParametersLocal.Add(Utility.ParameterDriverParameterSet("ObjectTracking/config/index", 2)); + parameterDriverParametersLocal.Add(Utility.ParameterDriverParameterSet("ObjectTracking/config/value", tracker.bitsRPZ)); + parameterDriverParametersLocal.Add(Utility.ParameterDriverParameterSet("ObjectTracking/config/index", 3)); + parameterDriverParametersLocal.Add(Utility.ParameterDriverParameterSet("ObjectTracking/config/value", tracker.bitsRRX)); + parameterDriverParametersLocal.Add(Utility.ParameterDriverParameterSet("ObjectTracking/config/index", 4)); + parameterDriverParametersLocal.Add(Utility.ParameterDriverParameterSet("ObjectTracking/config/value", tracker.bitsRRY)); + parameterDriverParametersLocal.Add(Utility.ParameterDriverParameterSet("ObjectTracking/config/index", 5)); + parameterDriverParametersLocal.Add(Utility.ParameterDriverParameterSet("ObjectTracking/config/value", tracker.bitsRRZ)); + parameterDriverParametersLocal.Add(Utility.ParameterDriverParameterSet("ObjectTracking/config/index", 6)); + parameterDriverParametersLocal.Add(Utility.ParameterDriverParameterSet("ObjectTracking/config/value", tracker.minLPX)); + parameterDriverParametersLocal.Add(Utility.ParameterDriverParameterSet("ObjectTracking/config/index", 7)); + parameterDriverParametersLocal.Add(Utility.ParameterDriverParameterSet("ObjectTracking/config/value", tracker.minLPY)); + parameterDriverParametersLocal.Add(Utility.ParameterDriverParameterSet("ObjectTracking/config/index", 8)); + parameterDriverParametersLocal.Add(Utility.ParameterDriverParameterSet("ObjectTracking/config/value", tracker.minLPZ)); + parameterDriverParametersLocal.Add(Utility.ParameterDriverParameterSet("ObjectTracking/config/index", 9)); + parameterDriverParametersLocal.Add(Utility.ParameterDriverParameterSet("ObjectTracking/config/value", tracker.minLRX)); + parameterDriverParametersLocal.Add(Utility.ParameterDriverParameterSet("ObjectTracking/config/index", 10)); + parameterDriverParametersLocal.Add(Utility.ParameterDriverParameterSet("ObjectTracking/config/value", tracker.minLRY)); + parameterDriverParametersLocal.Add(Utility.ParameterDriverParameterSet("ObjectTracking/config/index", 11)); + parameterDriverParametersLocal.Add(Utility.ParameterDriverParameterSet("ObjectTracking/config/value", tracker.minLRZ)); + parameterDriverParametersLocal.Add(Utility.ParameterDriverParameterSet("ObjectTracking/config/index", 12)); + parameterDriverParametersLocal.Add(Utility.ParameterDriverParameterSet("ObjectTracking/config/value", tracker.minRPX)); + parameterDriverParametersLocal.Add(Utility.ParameterDriverParameterSet("ObjectTracking/config/index", 13)); + parameterDriverParametersLocal.Add(Utility.ParameterDriverParameterSet("ObjectTracking/config/value", tracker.minRPY)); + parameterDriverParametersLocal.Add(Utility.ParameterDriverParameterSet("ObjectTracking/config/index", 14)); + parameterDriverParametersLocal.Add(Utility.ParameterDriverParameterSet("ObjectTracking/config/value", tracker.minRPZ)); + parameterDriverParametersLocal.Add(Utility.ParameterDriverParameterSet("ObjectTracking/config/index", 15)); + parameterDriverParametersLocal.Add(Utility.ParameterDriverParameterSet("ObjectTracking/config/value", tracker.minRRX)); + parameterDriverParametersLocal.Add(Utility.ParameterDriverParameterSet("ObjectTracking/config/index", 16)); + parameterDriverParametersLocal.Add(Utility.ParameterDriverParameterSet("ObjectTracking/config/value", tracker.minRRY)); + parameterDriverParametersLocal.Add(Utility.ParameterDriverParameterSet("ObjectTracking/config/index", 17)); + parameterDriverParametersLocal.Add(Utility.ParameterDriverParameterSet("ObjectTracking/config/value", tracker.minRRZ)); + parameterDriverParametersLocal.Add(Utility.ParameterDriverParameterSet("ObjectTracking/config/index", 18)); + parameterDriverParametersLocal.Add(Utility.ParameterDriverParameterSet("ObjectTracking/config/value", tracker.maxLPX)); + parameterDriverParametersLocal.Add(Utility.ParameterDriverParameterSet("ObjectTracking/config/index", 19)); + parameterDriverParametersLocal.Add(Utility.ParameterDriverParameterSet("ObjectTracking/config/value", tracker.maxLPY)); + parameterDriverParametersLocal.Add(Utility.ParameterDriverParameterSet("ObjectTracking/config/index", 20)); + parameterDriverParametersLocal.Add(Utility.ParameterDriverParameterSet("ObjectTracking/config/value", tracker.maxLPZ)); + parameterDriverParametersLocal.Add(Utility.ParameterDriverParameterSet("ObjectTracking/config/index", 21)); + parameterDriverParametersLocal.Add(Utility.ParameterDriverParameterSet("ObjectTracking/config/value", tracker.maxLRX)); + parameterDriverParametersLocal.Add(Utility.ParameterDriverParameterSet("ObjectTracking/config/index", 22)); + parameterDriverParametersLocal.Add(Utility.ParameterDriverParameterSet("ObjectTracking/config/value", tracker.maxLRY)); + parameterDriverParametersLocal.Add(Utility.ParameterDriverParameterSet("ObjectTracking/config/index", 23)); + parameterDriverParametersLocal.Add(Utility.ParameterDriverParameterSet("ObjectTracking/config/value", tracker.maxLRZ)); + parameterDriverParametersLocal.Add(Utility.ParameterDriverParameterSet("ObjectTracking/config/index", 24)); + parameterDriverParametersLocal.Add(Utility.ParameterDriverParameterSet("ObjectTracking/config/value", tracker.maxRPX)); + parameterDriverParametersLocal.Add(Utility.ParameterDriverParameterSet("ObjectTracking/config/index", 25)); + parameterDriverParametersLocal.Add(Utility.ParameterDriverParameterSet("ObjectTracking/config/value", tracker.maxRPY)); + parameterDriverParametersLocal.Add(Utility.ParameterDriverParameterSet("ObjectTracking/config/index", 26)); + parameterDriverParametersLocal.Add(Utility.ParameterDriverParameterSet("ObjectTracking/config/value", tracker.maxRPZ)); + parameterDriverParametersLocal.Add(Utility.ParameterDriverParameterSet("ObjectTracking/config/index", 27)); + parameterDriverParametersLocal.Add(Utility.ParameterDriverParameterSet("ObjectTracking/config/value", tracker.maxRRX)); + parameterDriverParametersLocal.Add(Utility.ParameterDriverParameterSet("ObjectTracking/config/index", 28)); + parameterDriverParametersLocal.Add(Utility.ParameterDriverParameterSet("ObjectTracking/config/value", tracker.maxRRY)); + parameterDriverParametersLocal.Add(Utility.ParameterDriverParameterSet("ObjectTracking/config/index", 29)); + parameterDriverParametersLocal.Add(Utility.ParameterDriverParameterSet("ObjectTracking/config/value", tracker.maxRRZ)); + parameterDriverParametersLocal.Add(Utility.ParameterDriverParameterSet("ObjectTracking/config/index", 30)); parameterDriverParametersLocal.Add(Utility.ParameterDriverParameterSet("ObjectTracking/config/" + tracker.name, false)); + parameterDriverParametersLocal.Add(Utility.ParameterDriverParameterSet("ObjectTracking/config/index", 0)); + parameterDriverParametersLocal.Add(Utility.ParameterDriverParameterSet("ObjectTracking/config/value", 0)); } VRCAvatarParameterDriver parameterDriverLocal = ScriptableObject.CreateInstance(); parameterDriverLocal.parameters = parameterDriverParametersLocal; @@ -286,8 +369,7 @@ private void CreateProcessingLayer() stateRemote.motion = Utility.CreateDirectBlendTree("processing", motionsRemote); - List parameterDriverParametersRemote = - new List(); + List parameterDriverParametersRemote = new List(); foreach (SetupTracker tracker in trackers) { tracker.AppendAvatarParameterDriverParameters(parameterDriverParametersRemote); @@ -308,124 +390,135 @@ private void CreateProcessingLayer() layer.stateMachine.states = layer.stateMachine.states.Append(stateRemoteChild).ToArray(); // Transition Conditions - Dictionary conditionsToLocal = new Dictionary + Tuple[] conditionsToLocal = new Tuple[] + { + Tuple.Create("IsLocal", true), + Tuple.Create("ObjectTracking/isRemotePreview", false), + }; + Tuple[] conditionsToRemote = new Tuple[] { - { "IsLocal", true }, - { "ObjectTracking/IsRemotePreview", false }, + Tuple.Create("IsLocal", false), }; - Dictionary conditionsToRemote = new Dictionary + Tuple[] conditionsToRemotePreview = new Tuple[] { - { "IsLocal", false }, + Tuple.Create("ObjectTracking/isRemotePreview", true), }; - Dictionary conditionsToRemotePreview = new Dictionary + Tuple[] conditionsReload = new Tuple[] { - { "ObjectTracking/IsRemotePreview", true }, + Tuple.Create("ObjectTracking/config/global", true), }; stateInit.transitions = new[] { - Utility.CreateBoolTransition("isRemote", conditionsToRemote, stateRemote), - Utility.CreateBoolTransition("isRemotePreview", conditionsToRemotePreview, stateRemote), - Utility.CreateBoolTransition("isLocal", conditionsToLocal, stateLocal) + Utility.CreateTransition("isRemote", conditionsToRemote, stateRemote), + Utility.CreateTransition("isRemotePreview", conditionsToRemotePreview, stateRemote), + Utility.CreateTransition("isLocal", conditionsToLocal, stateLocal) }; stateLocal.transitions = new[] { - Utility.CreateBoolTransition("isRemote", conditionsToRemote, stateRemote), - Utility.CreateBoolTransition("isRemotePreview", conditionsToRemotePreview, stateRemote), + Utility.CreateTransition("isRemote", conditionsToRemote, stateRemote), + Utility.CreateTransition("isRemotePreview", conditionsToRemotePreview, stateRemote), + Utility.CreateTransition("reload", conditionsReload, stateLocal) }; stateRemote.transitions = new[] { - Utility.CreateBoolTransition("isRemote", conditionsToRemote, stateRemote), - Utility.CreateBoolTransition("isRemotePreview", conditionsToRemotePreview, stateRemote), - Utility.CreateBoolTransition("isLocal", conditionsToLocal, stateLocal), + Utility.CreateTransition("isRemote", conditionsToRemote, stateRemote), + Utility.CreateTransition("isRemotePreview", conditionsToRemotePreview, stateRemote), + Utility.CreateTransition("isLocal", conditionsToLocal, stateLocal), }; + + Utility.AddSubAssetsToDatabase(layer, controller); + } + + public void CreateStabilizationLayer() + { + // Layer + AnimatorControllerLayer layer = Utility.CreateLayer("ObjectTracking/Stabilization"); + controller.layers = controller.layers.Append(layer).ToArray(); - AnimatorState stateGlobal = new AnimatorState + // Animation State Off + AnimatorState stateOff = new AnimatorState { - name = "Global Config", + name = "Off", writeDefaultValues = false, motion = ignoreClip }; - - VRCAvatarParameterDriver parameterDriverGlobal = ScriptableObject.CreateInstance(); - parameterDriverGlobal.parameters = new List + + VRCAnimatorLocomotionControl locomotionControlOff = ScriptableObject.CreateInstance(); + locomotionControlOff.disableLocomotion = false; + + VRCAvatarParameterDriver parameterDriverOff = ScriptableObject.CreateInstance(); + parameterDriverOff.parameters = new List { - Utility.ParameterDriverParameterSet("ObjectTracking/config/value0", 1), // version number + Utility.ParameterDriverParameterSet("ObjectTracking/isStabilized", false) }; - parameterDriverGlobal.localOnly = false; - stateGlobal.behaviours = new StateMachineBehaviour[] { parameterDriverGlobal }; + parameterDriverOff.localOnly = false; + stateOff.behaviours = new StateMachineBehaviour[] { locomotionControlOff, parameterDriverOff }; - ChildAnimatorState stateGlobalChild = new ChildAnimatorState + ChildAnimatorState stateOffChild = new ChildAnimatorState { - state = stateGlobal, - position = new Vector3(30, 270, 0) + state = stateOff, + position = new Vector3(30, 190, 0) }; - stateLocal.AddTransition(Utility.CreateBoolTransition("isGlobal", "ObjectTracking/config/global", true, stateGlobal)); - stateGlobal.AddTransition(Utility.CreateBoolTransition("reset", "ObjectTracking/config/global", false, stateLocal)); - - layer.stateMachine.states = layer.stateMachine.states.Append(stateGlobalChild).ToArray(); + layer.stateMachine.states = layer.stateMachine.states.Append(stateOffChild).ToArray(); - // Animation State Config Groups - for (int i = 0; i < trackers.Count; i++) + // Animation State On + AnimatorState stateOn = new AnimatorState { - SetupTracker tracker = trackers[i]; - AnimatorState stateDevice = new AnimatorState - { - name = "Tracker Config " + tracker.name, - writeDefaultValues = false, - motion = ignoreClip - }; - - VRCAvatarParameterDriver parameterDriverDevice = ScriptableObject.CreateInstance(); - parameterDriverDevice.parameters = new List - { - Utility.ParameterDriverParameterSet("ObjectTracking/config/value0", tracker.bitsRPX), - Utility.ParameterDriverParameterSet("ObjectTracking/config/value1", tracker.bitsRPY), - Utility.ParameterDriverParameterSet("ObjectTracking/config/value2", tracker.bitsRPZ), - Utility.ParameterDriverParameterSet("ObjectTracking/config/value3", tracker.bitsRRX), - Utility.ParameterDriverParameterSet("ObjectTracking/config/value4", tracker.bitsRRY), - Utility.ParameterDriverParameterSet("ObjectTracking/config/value5", tracker.bitsRRZ), - Utility.ParameterDriverParameterSet("ObjectTracking/config/value6", tracker.minLPX), - Utility.ParameterDriverParameterSet("ObjectTracking/config/value7", tracker.minLPY), - Utility.ParameterDriverParameterSet("ObjectTracking/config/value8", tracker.minLPZ), - Utility.ParameterDriverParameterSet("ObjectTracking/config/value9", tracker.minLRX), - Utility.ParameterDriverParameterSet("ObjectTracking/config/value10", tracker.minLRY), - Utility.ParameterDriverParameterSet("ObjectTracking/config/value11", tracker.minLRZ), - Utility.ParameterDriverParameterSet("ObjectTracking/config/value12", tracker.minRPX), - Utility.ParameterDriverParameterSet("ObjectTracking/config/value13", tracker.minRPY), - Utility.ParameterDriverParameterSet("ObjectTracking/config/value14", tracker.minRPZ), - Utility.ParameterDriverParameterSet("ObjectTracking/config/value15", tracker.minRRX), - Utility.ParameterDriverParameterSet("ObjectTracking/config/value16", tracker.minRRY), - Utility.ParameterDriverParameterSet("ObjectTracking/config/value17", tracker.minRRZ), - Utility.ParameterDriverParameterSet("ObjectTracking/config/value18", tracker.maxLPX), - Utility.ParameterDriverParameterSet("ObjectTracking/config/value19", tracker.maxLPY), - Utility.ParameterDriverParameterSet("ObjectTracking/config/value20", tracker.maxLPZ), - Utility.ParameterDriverParameterSet("ObjectTracking/config/value21", tracker.maxLRX), - Utility.ParameterDriverParameterSet("ObjectTracking/config/value22", tracker.maxLRY), - Utility.ParameterDriverParameterSet("ObjectTracking/config/value23", tracker.maxLRZ), - Utility.ParameterDriverParameterSet("ObjectTracking/config/value24", tracker.maxRPX), - Utility.ParameterDriverParameterSet("ObjectTracking/config/value25", tracker.maxRPY), - Utility.ParameterDriverParameterSet("ObjectTracking/config/value26", tracker.maxRPZ), - Utility.ParameterDriverParameterSet("ObjectTracking/config/value27", tracker.maxRRX), - Utility.ParameterDriverParameterSet("ObjectTracking/config/value28", tracker.maxRRY), - Utility.ParameterDriverParameterSet("ObjectTracking/config/value29", tracker.maxRRZ), - //Utility.ParameterDriverParameterSet("ObjectTracking/config/" + tracker.name, false), - }; - parameterDriverDevice.localOnly = false; - stateDevice.behaviours = new StateMachineBehaviour[] { parameterDriverDevice }; - - ChildAnimatorState stateDeviceChild = new ChildAnimatorState - { - state = stateDevice, - position = new Vector3(30, 350 + (i * 80), 0) - }; - stateLocal.AddTransition(Utility.CreateBoolTransition("isDevice " + tracker.name, "ObjectTracking/config/" + tracker.name, true, stateDevice)); - stateDevice.AddTransition(Utility.CreateBoolTransition("reset", "ObjectTracking/config/global", false, stateLocal)); - - layer.stateMachine.states = layer.stateMachine.states.Append(stateDeviceChild).ToArray(); + name = "On", + writeDefaultValues = false, + motion = ignoreClip + }; - } + VRCAnimatorLocomotionControl locomotionControlOn = ScriptableObject.CreateInstance(); + locomotionControlOn.disableLocomotion = true; + + VRCAvatarParameterDriver parameterDriverOn = ScriptableObject.CreateInstance(); + parameterDriverOn.parameters = new List + { + Utility.ParameterDriverParameterSet("ObjectTracking/isStabilized", true) + }; + parameterDriverOn.localOnly = false; + stateOn.behaviours = new StateMachineBehaviour[] { locomotionControlOn, parameterDriverOn }; + + ChildAnimatorState stateOnChild = new ChildAnimatorState + { + state = stateOn, + position = new Vector3(270, 190, 0) + }; + + layer.stateMachine.states = layer.stateMachine.states.Append(stateOnChild).ToArray(); + + // Transition Conditions + Tuple[] conditionsToOnBools = new Tuple[] + { + Tuple.Create("IsLocal", true), + Tuple.Create("ObjectTracking/goStabilized", true), + Tuple.Create("InStation", false), + }; + Tuple[] conditionsToOnFloats = new Tuple[] + { + Tuple.Create("VelocityX", AnimatorConditionMode.Greater, (float)-1 / 127), + Tuple.Create("VelocityX", AnimatorConditionMode.Less, (float)1 / 127), + Tuple.Create("VelocityY", AnimatorConditionMode.Greater, (float)-1 / 127), + Tuple.Create("VelocityY", AnimatorConditionMode.Less, (float)1 / 127), + Tuple.Create("VelocityZ", AnimatorConditionMode.Greater, (float)0), + }; + Tuple[] conditionsToOff = new Tuple[] + { + Tuple.Create("ObjectTracking/goStabilized", false) + }; + + stateOff.transitions = new[] + { + Utility.CreateTransition("isStabilization", conditionsToOnBools, conditionsToOnFloats, stateOn) + }; + + stateOn.transitions = new[] + { + Utility.CreateTransition("isUnstabilization", conditionsToOff, stateOff) + }; Utility.AddSubAssetsToDatabase(layer, controller); } diff --git a/Packages/dev.hackebein.object-tracking/Runtime/SetupTracker.cs b/Packages/dev.hackebein.object-tracking/Runtime/SetupTracker.cs index 06879ff..19eae14 100644 --- a/Packages/dev.hackebein.object-tracking/Runtime/SetupTracker.cs +++ b/Packages/dev.hackebein.object-tracking/Runtime/SetupTracker.cs @@ -23,11 +23,11 @@ public class SetupTracker public int bitsRRX = 6; public int bitsRRY = 6; public int bitsRRZ = 6; - public int minLPX = -42; + public int minLPX = -12; public int minRPX = -5; - public int minLPY = -42; + public int minLPY = -12; public int minRPY = 0; - public int minLPZ = -42; + public int minLPZ = -12; public int minRPZ = -5; public int minLRX = -180; public int minRRX = -180; @@ -35,11 +35,11 @@ public class SetupTracker public int minRRY = -180; public int minLRZ = -180; public int minRRZ = -180; - public int maxLPX = 42; + public int maxLPX = 12; public int maxRPX = 5; - public int maxLPY = 42; + public int maxLPY = 12; public int maxRPY = 3; - public int maxLPZ = 42; + public int maxLPZ = 12; public int maxRPZ = 5; public int maxLRX = 180; public int maxRRX = 180; @@ -116,6 +116,7 @@ private string[] AxePathAndProperty(string name) { string path = ""; string property = ""; + // TODO: add support for multiple properties switch (name) { case "PX": @@ -132,15 +133,15 @@ private string[] AxePathAndProperty(string name) break; case "RX": path = "ObjectTracking/" + this.name + "/" + this.name + "/" + this.name + "/" + this.name; - property = "m_TranslationOffsets.Array.data[0].x"; + property = "m_RotationOffsets.Array.data[0].x"; break; case "RY": path = "ObjectTracking/" + this.name + "/" + this.name + "/" + this.name + "/" + this.name; - property = "m_TranslationOffsets.Array.data[0].y"; + property = "m_RotationOffsets.Array.data[0].y"; break; case "RZ": path = "ObjectTracking/" + this.name + "/" + this.name + "/" + this.name + "/" + this.name; - property = "m_TranslationOffsets.Array.data[0].z"; + property = "m_RotationOffsets.Array.data[0].z"; break; } @@ -214,33 +215,33 @@ private void AppendTransitionLayer(AnimatorController controller, String assetFo controller.layers = controller.layers.Append(layer).ToArray(); // Transition Conditions - Dictionary conditionsToLocal = new Dictionary + Tuple[] conditionsToLocal = new Tuple[] { - { "IsLocal", true }, - { "ObjectTracking/IsRemotePreview", false }, + Tuple.Create("IsLocal", true), + Tuple.Create("ObjectTracking/isRemotePreview", false), }; - Dictionary conditionsToRemote = new Dictionary + Tuple[] conditionsToRemote = new Tuple[] { - { "IsLocal", false }, + Tuple.Create("IsLocal", false), }; - Dictionary conditionsToRemotePreview = new Dictionary + Tuple[] conditionsToRemotePreview = new Tuple[] { - { "ObjectTracking/IsRemotePreview", true } + Tuple.Create("ObjectTracking/isRemotePreview", true), }; layer.stateMachine.entryTransitions = new[] { - Utility.CreateEntryBoolTransition("isRemote", conditionsToRemote, stateRemote), - Utility.CreateEntryBoolTransition("isRemotePreview", conditionsToRemotePreview, stateRemote), + Utility.CreateEntryTransition("isRemote", conditionsToRemote, stateRemote), + Utility.CreateEntryTransition("isRemotePreview", conditionsToRemotePreview, stateRemote), }; stateLocal.transitions = new[] { - Utility.CreateBoolTransition("isRemote", conditionsToRemote, stateRemote), - Utility.CreateBoolTransition("isRemotePreview", conditionsToRemotePreview, stateRemote), + Utility.CreateTransition("isRemote", conditionsToRemote, stateRemote), + Utility.CreateTransition("isRemotePreview", conditionsToRemotePreview, stateRemote), }; stateRemote.transitions = new[] { - Utility.CreateBoolTransition("isLocal", conditionsToLocal, stateLocal), + Utility.CreateTransition("isLocal", conditionsToLocal, stateLocal), }; // Clip @@ -307,7 +308,7 @@ public void AppendResetList(Dictionary reset) { foreach (KeyValuePair axe in Axes()) { - reset.Add(new[] { axe.Key[1], "IsActive" }, new[] { 1f, 1f }); + reset.Add(new[] { axe.Key[1], "m_IsActive" }, new[] { 1f, 1f }); reset.Add(new[] { axe.Key[1], "m_LocalPosition.x" }, new[] { 0f, 0f }); reset.Add(new[] { axe.Key[1], "m_LocalPosition.y" }, new[] { 0f, 0f }); reset.Add(new[] { axe.Key[1], "m_LocalPosition.z" }, new[] { 0f, 0f }); @@ -333,14 +334,12 @@ public void AppendAnimatorControllerParameters(AnimatorController controller) controller = Utility.CreateFloatParameterAndAddToAnimator(controller, "ObjectTracking/" + name + "/R" + pair.Key[0], .5f); for (int i = 0; i < accuracyBits; i++) { - // TODO: set default value to meet the middle of the range controller = Utility.CreateBoolParameterAndAddToAnimator(controller, "ObjectTracking/" + name + "/R" + pair.Key[0] + "-Bit" + i); controller = Utility.CreateFloatParameterAndAddToAnimator(controller, "ObjectTracking/" + name + "/R" + pair.Key[0] + "-Bit" + i + "-Float"); } for (int i = 0; i < accuracyBytes; i++) { - // TODO: set default value to meet the middle of the range controller = Utility.CreateIntParameterAndAddToAnimator(controller, "ObjectTracking/" + name + "/R" + pair.Key[0] + "-Byte" + i); controller = Utility.CreateFloatParameterAndAddToAnimator(controller, "ObjectTracking/" + name + "/R" + pair.Key[0] + "-Byte" + i + "-Float"); } @@ -355,16 +354,14 @@ public void AppendExpressionParameters(VRCExpressionParameters expressionParamet // TODO: simplification if accuracy is 8: skip both for-loops and do a synced parameter like local instead int accuracyBytes = accuracy / 8; int accuracyBits = accuracy - (accuracyBytes * 8); - expressionParameters = Utility.CreateFloatParameterAndAddToExpressionParameters(expressionParameters, "ObjectTracking/" + name + "/L" + pair.Key[0], 0.5f, false, false); + expressionParameters = Utility.CreateFloatParameterAndAddToExpressionParameters(expressionParameters, "ObjectTracking/" + name + "/L" + pair.Key[0], 0f, false, false); for (int i = 0; i < accuracyBits; i++) { - // TODO: set default value to meet the middle of the range expressionParameters = Utility.CreateBoolParameterAndAddToExpressionParameters(expressionParameters, "ObjectTracking/" + name + "/R" + pair.Key[0] + "-Bit" + i, false, false, true); } for (int i = 0; i < accuracyBytes; i++) { - // TODO: set default value to meet the middle of the range expressionParameters = Utility.CreateIntParameterAndAddToExpressionParameters(expressionParameters, "ObjectTracking/" + name + "/R" + pair.Key[0] + "-Byte" + i, 0, false, true); } } @@ -375,8 +372,9 @@ public int GetExpressionParameters() int costs = 0; foreach (KeyValuePair pair in Axes()) { - costs += pair.Value[0] / 8; - costs += pair.Value[0] % 8; + costs += 1; // L + costs += pair.Value[0] / 8; // R-Byte<0-4> + costs += pair.Value[0] % 8; // R-Bit<0-7> } return costs; diff --git a/Packages/dev.hackebein.object-tracking/Runtime/Utilities.cs b/Packages/dev.hackebein.object-tracking/Runtime/Utilities.cs index 78c72a9..d647454 100644 --- a/Packages/dev.hackebein.object-tracking/Runtime/Utilities.cs +++ b/Packages/dev.hackebein.object-tracking/Runtime/Utilities.cs @@ -55,7 +55,7 @@ public enum TrackerType "Manus - SteamVR Pro Tracker (coming soon)", "Tundra Labs - Tundra Tracker (1\u22154\" Screw Mount)", "Tundra Labs - Tundra Tracker (1\u22154\" Screw Mount, rotated)", - "Tundra Labs - Tundra Tracker (Strap Mount) (coming soon)", + "Tundra Labs - Tundra Tracker (Strap Mount)", }; public static readonly String[] TrackerTypeGameObjects = @@ -69,9 +69,37 @@ public enum TrackerType null, // Manus SteamVR Pro Tracker "Packages/dev.hackebein.object-tracking/Prefab/Tundra Labs Tundra Tracker screw.fbx", "Packages/dev.hackebein.object-tracking/Prefab/Tundra Labs Tundra Tracker screw rotated.fbx", - null, // Tundra Labs Tundra Tracker (Strap Mount) + "Packages/dev.hackebein.object-tracking/Prefab/Tundra Labs Tundra Tracker strap.fbx", }; +/* + public static AnimatorControllerParameter CreateAnimatorParameter(string name, T defaultValue) + { + AnimatorControllerParameter parameter = new AnimatorControllerParameter + { + name = name + }; + switch (defaultValue) + { + case bool b: + parameter.type = AnimatorControllerParameterType.Bool; + parameter.defaultBool = b; + break; + case float f: + parameter.type = AnimatorControllerParameterType.Float; + parameter.defaultFloat = f; + break; + case int i: + parameter.type = AnimatorControllerParameterType.Int; + parameter.defaultInt = i; + break; + default: + throw new ArgumentException("Unsupported parameter type"); + } + + return parameter; + } +*/ public static AnimatorControllerParameter CreateBoolAnimatorParameter(string name, bool value = false) { AnimatorControllerParameter parameter = new AnimatorControllerParameter @@ -299,70 +327,129 @@ public static VRCAvatarParameterDriver.Parameter ParameterDriverParameterBoolToF return parameterDriverParameter; } - - public static AnimatorStateTransition CreateBoolTransition(string name, string variable, bool value, AnimatorState target) - { - Dictionary conditions = new Dictionary { { variable, value } }; - return CreateBoolTransition(name, conditions, target); - } - - public static AnimatorStateTransition CreateBoolTransition(string name, Dictionary conditions, AnimatorState target) + + private static AnimatorCondition[] CreateAnimatorCondition(Tuple[] boolConditions, Tuple[] intConditions, Tuple[] floatConditions) { AnimatorCondition[] animatorConditions = Array.Empty(); - foreach (KeyValuePair pair in conditions) + foreach (Tuple pair in boolConditions) + { + AnimatorCondition condition = new AnimatorCondition + { + parameter = pair.Item1, + mode = pair.Item2 ? AnimatorConditionMode.If : AnimatorConditionMode.IfNot + }; + + animatorConditions = animatorConditions.Append(condition).ToArray(); + } + foreach (Tuple pair in intConditions) + { + AnimatorCondition condition = new AnimatorCondition + { + parameter = pair.Item1, + mode = pair.Item2, + threshold = pair.Item3, + }; + + animatorConditions = animatorConditions.Append(condition).ToArray(); + } + foreach (Tuple pair in floatConditions) { AnimatorCondition condition = new AnimatorCondition { - parameter = pair.Key, - mode = pair.Value ? AnimatorConditionMode.If : AnimatorConditionMode.IfNot + parameter = pair.Item1, + mode = pair.Item2, + threshold = pair.Item3, }; animatorConditions = animatorConditions.Append(condition).ToArray(); } - AnimatorStateTransition transition = new AnimatorStateTransition + return animatorConditions; + } + + public static AnimatorStateTransition CreateTransition(string name, Tuple[] boolConditions, Tuple[] intConditions, Tuple[] floatConditions, AnimatorState target) + { + return new AnimatorStateTransition { name = name, - conditions = animatorConditions, + conditions = CreateAnimatorCondition(boolConditions, intConditions, floatConditions), destinationState = target, duration = 0, hasExitTime = false, exitTime = 0 }; + } + + public static AnimatorTransition CreateEntryTransition(string name, Tuple[] boolConditions, Tuple[] intConditions, Tuple[] floatConditions, AnimatorState target) + { + return new AnimatorTransition + { + name = name, + conditions = CreateAnimatorCondition(boolConditions, intConditions, floatConditions), + destinationState = target + }; + } - return transition; + public static AnimatorStateTransition CreateTransition(string name, Tuple[] boolConditions, AnimatorState target) + { + return CreateTransition(name, boolConditions, Array.Empty>(), Array.Empty>(), target); } - public static AnimatorTransition CreateEntryBoolTransition(string name, string variable, bool value, AnimatorState target) + public static AnimatorStateTransition CreateTransition(string name, Tuple[] intConditions, AnimatorState target) { - Dictionary conditions = new Dictionary { { variable, value } }; - return CreateEntryBoolTransition(name, conditions, target); + return CreateTransition(name, Array.Empty>(), intConditions, Array.Empty>(), target); } - public static AnimatorTransition CreateEntryBoolTransition(string name, Dictionary conditions, AnimatorState target) + public static AnimatorStateTransition CreateTransition(string name, Tuple[] floatConditions, AnimatorState target) { - AnimatorCondition[] animatorConditions = Array.Empty(); - foreach (KeyValuePair pair in conditions) - { - AnimatorCondition condition = new AnimatorCondition - { - parameter = pair.Key, - mode = pair.Value ? AnimatorConditionMode.If : AnimatorConditionMode.IfNot - }; + return CreateTransition(name, Array.Empty>(), Array.Empty>(), floatConditions, target); + } - animatorConditions = animatorConditions.Append(condition).ToArray(); - } + public static AnimatorStateTransition CreateTransition(string name, Tuple[] boolConditions, Tuple[] intConditions, AnimatorState target) + { + return CreateTransition(name, boolConditions, intConditions, Array.Empty>(), target); + } - AnimatorTransition transition = new AnimatorTransition - { - name = name, - conditions = animatorConditions, - destinationState = target - }; + public static AnimatorStateTransition CreateTransition(string name, Tuple[] boolConditions, Tuple[] floatConditions, AnimatorState target) + { + return CreateTransition(name, boolConditions, Array.Empty>(), floatConditions, target); + } + + public static AnimatorStateTransition CreateTransition(string name, Tuple[] intConditions, Tuple[] floatConditions, AnimatorState target) + { + return CreateTransition(name, Array.Empty>(), intConditions, floatConditions, target); + } + + public static AnimatorTransition CreateEntryTransition(string name, Tuple[] boolConditions, AnimatorState target) + { + return CreateEntryTransition(name, boolConditions, Array.Empty>(), Array.Empty>(), target); + } + + public static AnimatorTransition CreateEntryTransition(string name, Tuple[] intConditions, AnimatorState target) + { + return CreateEntryTransition(name, Array.Empty>(), intConditions, Array.Empty>(), target); + } - return transition; + public static AnimatorTransition CreateEntryTransition(string name, Tuple[] floatConditions, AnimatorState target) + { + return CreateEntryTransition(name, Array.Empty>(), Array.Empty>(), floatConditions, target); } + public static AnimatorTransition CreateEntryTransition(string name, Tuple[] boolConditions, Tuple[] intConditions, AnimatorState target) + { + return CreateEntryTransition(name, boolConditions, intConditions, Array.Empty>(), target); + } + + public static AnimatorTransition CreateEntryTransition(string name, Tuple[] boolConditions, Tuple[] floatConditions, AnimatorState target) + { + return CreateEntryTransition(name, boolConditions, Array.Empty>(), floatConditions, target); + } + + public static AnimatorTransition CreateEntryTransition(string name, Tuple[] intConditions, Tuple[] floatConditions, AnimatorState target) + { + return CreateEntryTransition(name, Array.Empty>(), intConditions, floatConditions, target); + } + public static AnimationClip CreateClip(string name, string path, string property, float start, float end, string assetFolder) { Dictionary props = new Dictionary { { new[] { path, property }, new[] { start, end } } }; @@ -378,9 +465,10 @@ public static AnimationClip CreateClip(string name, Dictionary prop in props) { Type type = typeof(GameObject); - switch (prop.Key[1].Split(".")[0]) + switch (prop.Key[1].Split('.')[0]) { case "m_TranslationOffsets": + case "m_RotationOffsets": type = typeof(ParentConstraint); break; case "m_LocalPosition": @@ -388,7 +476,7 @@ public static AnimationClip CreateClip(string name, Dictionary