-
Notifications
You must be signed in to change notification settings - Fork 54
Commit
- Loading branch information
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
{ | ||
"name": "Meta.XR.Movement.Editor", | ||
"rootNamespace": "", | ||
"references": [ | ||
"GUID:f64c9ebcd7899c3448a08dc9f9ddbe30", | ||
"GUID:f4af9e3560e85174f90917cb2bbcda01", | ||
"GUID:8e76fd86d1fdc9243a341ca50624a575" | ||
], | ||
"includePlatforms": [ | ||
"Editor" | ||
], | ||
"excludePlatforms": [], | ||
"allowUnsafeCode": false, | ||
"overrideReferences": false, | ||
"precompiledReferences": [], | ||
"autoReferenced": true, | ||
"defineConstraints": [], | ||
"versionDefines": [], | ||
"noEngineReferences": false | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,176 @@ | ||
// (c) Meta Platforms, Inc. and affiliates. Confidential and proprietary. | ||
|
||
#define ENABLE_NATIVE_PLUGIN_API_TEST | ||
|
||
using System; | ||
using System.Collections.Generic; | ||
using System.IO; | ||
using System.Linq; | ||
using Unity.Collections; | ||
using UnityEditor; | ||
using UnityEditor.SceneManagement; | ||
using UnityEngine; | ||
|
||
namespace Meta.XR.Movement.Editor | ||
{ | ||
public class NativeUtilityEditor | ||
{ | ||
/// <summary> | ||
/// Prefix for movement samples one-click menus. | ||
/// </summary> | ||
private const string _movementMenuPath = | ||
"GameObject/Movement SDK/"; | ||
|
||
private const string _movementAssetsPath = | ||
"Assets/Movement SDK/"; | ||
|
||
[MenuItem(_movementMenuPath + "Create Retargeting Config")] | ||
public static void CreateRetargetingConfig() | ||
{ | ||
CreateRetargetingConfig(Selection.activeGameObject); | ||
} | ||
|
||
[MenuItem(_movementMenuPath + "Create Retargeting Data")] | ||
public static void CreateRetargetingDataAndSave() | ||
{ | ||
if (Selection.activeGameObject == null) | ||
{ | ||
Debug.LogError("The gameObject with the skeleton for retargeting data must be selected!"); | ||
return; | ||
} | ||
|
||
var data = CreateRetargetingData(Selection.activeGameObject); | ||
|
||
var assetPath = EditorUtility.SaveFilePanelInProject( | ||
"Save Retargeting Data", | ||
Selection.activeGameObject.name, | ||
"asset", | ||
"Save Retargeted Data"); | ||
if (string.IsNullOrEmpty(assetPath)) | ||
{ | ||
return; | ||
} | ||
AssetDatabase.CreateAsset(data, assetPath); | ||
AssetDatabase.SaveAssets(); | ||
AssetDatabase.Refresh(); | ||
} | ||
|
||
|
||
public static TextAsset CreateRetargetingConfig(GameObject targetObject) | ||
{ | ||
var target = CreateRetargetingData(targetObject); | ||
if (target == null) | ||
{ | ||
Debug.LogError("Error in creating retargeting data!"); | ||
return null; | ||
} | ||
|
||
var source = GetOVRSkeletonRetargetingData(); | ||
var skinnedMeshRenderers = GetValidSkinnedMeshRenderers(targetObject); | ||
var blendshapeNames = GetBlendshapeNames(skinnedMeshRenderers); | ||
|
||
var output = NativeUtilityHelper.CreateRetargetingConfig( | ||
blendshapeNames, source, target, targetObject.name); | ||
var assetPath = EditorUtility.SaveFilePanelInProject( | ||
"Save Retargeting Config", | ||
targetObject.name, | ||
"json", | ||
"Save Retargeting Config"); | ||
if (string.IsNullOrEmpty(assetPath)) | ||
{ | ||
return null; | ||
} | ||
File.WriteAllText(assetPath, output); | ||
AssetDatabase.SaveAssets(); | ||
AssetDatabase.Refresh(); | ||
return AssetDatabase.LoadAssetAtPath<TextAsset>(assetPath); | ||
} | ||
|
||
public static GameObject FindPrefab(string assetName) | ||
{ | ||
var guids = AssetDatabase.FindAssets(assetName + " t: GameObject", | ||
new[] { "Assets", "Packages" }); | ||
return guids is not { Length: > 0 } | ||
? null | ||
: guids.Select(AssetDatabase.GUIDToAssetPath).Select(AssetDatabase.LoadAssetAtPath<GameObject>) | ||
.FirstOrDefault(loadedAsset => loadedAsset.name == assetName); | ||
} | ||
|
||
private static RetargetingBodyData CreateRetargetingData(GameObject target) | ||
{ | ||
var jointMapping = | ||
NativeUtilityHelper.GetChildParentJointMapping(target); | ||
if (jointMapping == null) | ||
{ | ||
return null; | ||
} | ||
|
||
var data = ScriptableObject.CreateInstance<RetargetingBodyData>(); | ||
var index = 0; | ||
var jointCount = jointMapping.Keys.Count; | ||
data.Initialize(jointCount); | ||
foreach (var jointPair in jointMapping) | ||
{ | ||
var joint = jointPair.Key; | ||
var parentJoint = jointPair.Value; | ||
data.Joints[index] = joint.name; | ||
data.ParentJoints[index] = parentJoint == null ? string.Empty : parentJoint.name; | ||
data.TPose[index] = new Pose(joint.localPosition, joint.localRotation); | ||
index++; | ||
} | ||
// TODO: Replace with min T-Pose information when available from editor. | ||
data.TPoseMin = data.TPose; | ||
// TODO: Replace with max T-Pose information when available from editor. | ||
data.TPoseMax = data.TPose; | ||
|
||
// Check if it's OVRSkeleton - if so, we should sort the array. | ||
if (target.name == "OVRSkeleton") | ||
{ | ||
data.SortData(); | ||
} | ||
return data; | ||
} | ||
|
||
private static RetargetingBodyData GetOVRSkeletonRetargetingData() | ||
{ | ||
var assetName = "OVRSkeletonRetargetingData"; | ||
var guids = AssetDatabase.FindAssets(assetName); | ||
if (guids == null || guids.Length == 0) | ||
{ | ||
Debug.LogError($"Asset {assetName} cannot be found."); | ||
return null; | ||
} | ||
var pathToAsset = AssetDatabase.GUIDToAssetPath(guids[0]); | ||
return AssetDatabase.LoadAssetAtPath<RetargetingBodyData>(pathToAsset); | ||
} | ||
|
||
private static SkinnedMeshRenderer[] GetValidSkinnedMeshRenderers(GameObject gameObject) | ||
{ | ||
var allSkinnedMeshes = gameObject.GetComponentsInChildren<SkinnedMeshRenderer>(); | ||
List<SkinnedMeshRenderer> skinnedMeshesWithBlendshapes = new List<SkinnedMeshRenderer>(); | ||
foreach (var skinnedMesh in allSkinnedMeshes) | ||
{ | ||
if (skinnedMesh.sharedMesh.blendShapeCount > 0) | ||
{ | ||
skinnedMeshesWithBlendshapes.Add(skinnedMesh); | ||
} | ||
} | ||
return skinnedMeshesWithBlendshapes.ToArray(); | ||
} | ||
|
||
private static string[] GetBlendshapeNames(SkinnedMeshRenderer[] skinnedMeshes) | ||
{ | ||
List<string> blendshapeNames = new List<string>(); | ||
foreach (var skinnedMesh in skinnedMeshes) | ||
{ | ||
int numCurrentBlendshapes = skinnedMesh.sharedMesh.blendShapeCount; | ||
for (int blendIndex = 0; blendIndex < numCurrentBlendshapes; blendIndex++) | ||
{ | ||
blendshapeNames.Add(skinnedMesh.sharedMesh.GetBlendShapeName(blendIndex)); | ||
} | ||
} | ||
return blendshapeNames.ToArray(); | ||
} | ||
|
||
} | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
%YAML 1.1 | ||
%TAG !u! tag:unity3d.com,2011: | ||
--- !u!114 &11400000 | ||
MonoBehaviour: | ||
m_ObjectHideFlags: 0 | ||
m_CorrespondingSourceObject: {fileID: 0} | ||
m_PrefabInstance: {fileID: 0} | ||
m_PrefabAsset: {fileID: 0} | ||
m_GameObject: {fileID: 0} | ||
m_Enabled: 1 | ||
m_EditorHideFlags: 0 | ||
m_Script: {fileID: 11500000, guid: 81d5758cfb47823489080981979f33be, type: 3} | ||
m_Name: INetworkPoseRetargeter | ||
m_EditorClassIdentifier: | ||
id: 6b4a8085-3c71-410b-baec-ff2c5a44ad31 | ||
version: 1 | ||
blockName: Networked Retargeted Character | ||
description: Showing Retargeted Characters for all connected players. | ||
tags: | ||
array: | ||
- name: Multiplayer | ||
thumbnail: {fileID: 2800000, guid: 0bff7535bc7b21f4382b01f5178a1dcb, type: 3} | ||
order: 0 | ||
prefab: {fileID: 0} | ||
externalBlockDependencies: [] | ||
dependencies: | ||
- 1d8db162-54f6-43df-b4ef-b499df1f6769 | ||
- e47682b9-c270-40b1-b16d-90b627a5ce1b | ||
packageDependencies: [] | ||
isSingleton: 0 | ||
usageInstructions: A valid character that contains a pose retargeter config must | ||
be set. | ||
featureDocumentationName: | ||
featureDocumentationUrl: |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
// (c) Meta Platforms, Inc. and affiliates. Confidential and proprietary. | ||
|
||
using Meta.XR.BuildingBlocks.Editor; | ||
using System.Reflection; | ||
using UnityEditor; | ||
using UnityEngine; | ||
|
||
namespace Meta.XR.Movement.Networking.Block.Editor | ||
{ | ||
/// <summary> | ||
/// Installation helper menu for Movement SDK. | ||
/// </summary> | ||
public static class InstallMovementBuildingBlock | ||
{ | ||
private const string _buildingBlockAssetName = "INetworkPoseRetargeter"; | ||
private const BindingFlags _flags = BindingFlags.NonPublic | BindingFlags.Instance; | ||
|
||
[MenuItem("GameObject/Movement SDK/Networking/Add Networked Retargeted Character")] | ||
private static void InstallNetworkedRetargetedCharacterBuildingBlock() | ||
{ | ||
var guids = AssetDatabase.FindAssets(_buildingBlockAssetName); | ||
if (guids == null || guids.Length == 0) | ||
{ | ||
Debug.LogError($"Asset {_buildingBlockAssetName} cannot be found."); | ||
return; | ||
} | ||
|
||
InterfaceBlockData blockData = null; | ||
foreach (var guid in guids) | ||
{ | ||
var pathToAsset = AssetDatabase.GUIDToAssetPath(guid); | ||
blockData = AssetDatabase.LoadAssetAtPath<InterfaceBlockData>(pathToAsset); | ||
if (blockData != null) | ||
{ | ||
break; | ||
} | ||
} | ||
if (blockData == null) | ||
{ | ||
Debug.LogError("Could not find block data."); | ||
return; | ||
} | ||
|
||
var installMethod = typeof(BlockData).GetMethod("ContextMenuInstall", _flags); | ||
if (installMethod == null) | ||
{ | ||
Debug.LogError("Could not find install method."); | ||
return; | ||
} | ||
installMethod.Invoke(blockData, null); | ||
} | ||
} | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.