Skip to content

Commit

Permalink
[Automated] Merged dev into main
Browse files Browse the repository at this point in the history
  • Loading branch information
actions-user committed Jan 24, 2025
2 parents ee96eec + 26150b6 commit a80a852
Show file tree
Hide file tree
Showing 579 changed files with 158,238 additions and 9 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
## [72.0.0]
- Updated sample scenes to use OpenXRHands.
- Fixed readme, documentation links and UI path.
- Changed Normal recalculator to run independently by default.
- Added `VisemeDriver.cs` to allow using visemes.

## [71.0.0]
- Normal recalculator has been fixed to run on submeshes with index greater than zero.
- New networking sample shows how to efficiently network body movement by compressing the joint-related movement information for transmission and is compatible with common network providers.
Expand Down
8 changes: 8 additions & 0 deletions Editor/Tracking/Viseme.meta

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

108 changes: 108 additions & 0 deletions Editor/Tracking/Viseme/VisemeDriverEditor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
// Copyright (c) Meta Platforms, Inc. and affiliates.

using UnityEditor;
using UnityEditor.SceneManagement;
using UnityEngine;

namespace Meta.XR.Movement.FaceTracking
{
/// <summary>
/// Custom Editor for <see cref="VisemeDriver">.
/// </summary>
/// <remarks>
/// Custom Editor for <see cref="VisemeDriver"> that:
/// - Allows users to access and modify <see cref="SkinnedMeshRenderer"/> <see cref="FaceViseme[]"/> <see cref="OVRFaceExpressions"/> in <see cref="VisemeDriver"/>.
/// - Creates buttons to auto-generate and clear blendshape mappings.
/// - Allows users to modify the <see cref="FaceViseme"> for the blendshapes in the <see cref="SkinnedMeshRenderer"/>.
/// </remarks>
[CustomEditor(typeof(VisemeDriver))]
public class VisemeDriverEditor : UnityEditor.Editor
{
private SerializedProperty _mappings;
private SerializedProperty _mesh;
private SerializedProperty _ovrExpressions;
private bool _showBlendshapes = true;
private bool _logErrorShown = false;
private VisemeDriver _visemeDriver;

protected virtual void OnEnable()
{
_visemeDriver = (VisemeDriver)target;
_visemeDriver.VisemeMesh = _visemeDriver.GetComponent<SkinnedMeshRenderer>();

_mappings = serializedObject.FindProperty("_visemeMapping");
_mesh = serializedObject.FindProperty("_mesh");
_ovrExpressions = serializedObject.FindProperty("_ovrFaceExpressions");
}

/// <inheritdoc/>
public override void OnInspectorGUI()
{
var renderer = _visemeDriver.VisemeMesh;

EditorGUILayout.PropertyField(_ovrExpressions, new GUIContent(nameof(OVRFaceExpressions)));
EditorGUILayout.PropertyField(_mesh, new GUIContent(nameof(SkinnedMeshRenderer)));

if (renderer.sharedMesh == null || renderer.sharedMesh.blendShapeCount == 0)
{
if (_logErrorShown == false)
{
Debug.LogError($"The mesh renderer on {target.name} must have blendshapes.");
_logErrorShown = true;
}
return;
}
else
{
if (_logErrorShown == true)
{
_logErrorShown = false;
}
}

if (_mappings.arraySize != renderer.sharedMesh.blendShapeCount)
{
_mappings.ClearArray();
_mappings.arraySize = renderer.sharedMesh.blendShapeCount;
for (int i = 0; i < renderer.sharedMesh.blendShapeCount; ++i)
{
_mappings.GetArrayElementAtIndex(i).intValue = (int)OVRFaceExpressions.FaceViseme.Invalid;
}
}

_showBlendshapes = EditorGUILayout.BeginFoldoutHeaderGroup(_showBlendshapes, "Blendshapes");

if (_showBlendshapes)
{
if (GUILayout.Button("Auto Generate Mapping"))
{
_visemeDriver.AutoMapBlendshapes();
Refresh(_visemeDriver);
}

if (GUILayout.Button("Clear Mapping"))
{
_visemeDriver.ClearBlendshapes();
Refresh(_visemeDriver);
}

EditorGUILayout.Space();

for (int i = 0; i < renderer.sharedMesh.blendShapeCount; ++i)
{
EditorGUILayout.PropertyField(_mappings.GetArrayElementAtIndex(i),
new GUIContent(renderer.sharedMesh.GetBlendShapeName(i)));
}
}
serializedObject.ApplyModifiedProperties();
serializedObject.Update();

static void Refresh(VisemeDriver face)
{
EditorUtility.SetDirty(face);
PrefabUtility.RecordPrefabInstancePropertyModifications(face);
EditorSceneManager.MarkSceneDirty(face.gameObject.scene);
}
}
}
}
11 changes: 11 additions & 0 deletions Editor/Tracking/Viseme/VisemeDriverEditor.cs.meta

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

9 changes: 5 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@ The Unity-Movement package is released under the [Oculus License](https://github
- 2021.3.26f1 (2021 LTS or newer)
- 2022.3.11f2 (2022 LTS or newer)
- Unity 6 or newer
- v71.0 or newer of the Meta XR SDK. You will need the [Meta XR Core SDK](https://assetstore.unity.com/packages/tools/integration/meta-xr-core-sdk-269169) and the [Meta XR Interaction SDK](https://assetstore.unity.com/packages/tools/integration/meta-xr-interaction-sdk-265014) packages found [on this page](https://assetstore.unity.com/publishers/25353).
- A project set up with these [steps](https://developers.meta.com/horizon/documentation/unity/move-overview/#unity-project-setup).
- v72.0 or newer of the Meta XR SDK. You will need the [Meta XR Core SDK](https://assetstore.unity.com/packages/tools/integration/meta-xr-core-sdk-269169) and the [Meta XR Interaction SDK](https://assetstore.unity.com/packages/tools/integration/meta-xr-interaction-sdk-265014) packages found [on this page](https://assetstore.unity.com/publishers/25353).
- A project set up with these [steps](https://developers.meta.com/horizon/documentation/unity/move-unity-getting-started#unity-project-setup).


## Getting Started
First, ensure that all of the [requirements](#requirements) are met.
Expand All @@ -36,7 +37,7 @@ If the new scene or an existing scene doesn’t have a GameObject with the OVRCa

Layer index 10, layer index 11, and the HiddenMesh layer must be present in the project for RecalculateNormals to work correctly.

Some Project Settings can be validated via **Movement->Check Project Settings**. For a more thorough check, please use **Oculus->Tools->Project Setup Tool**.
Some Project Settings can be validated via **Movement** > **Check Project Settings**. For a more thorough check, please use **Meta** > **Tools** > **Project Setup Tool**.

## Rendering Quality
Navigate to your Project Settings (**Edit->Project Settings...**) and click on
Expand Down Expand Up @@ -65,7 +66,7 @@ The project contains several sample scenes. To test the samples, they must be im

For more information about body tracking, please refer to [this page](https://developers.meta.com/horizon/documentation/unity/move-body-tracking/).

For more information about the samples, please refer to [this page](https://developers.meta.com/horizon/documentation/unity/move-samples/).
For more information about the samples, please refer to [this page](https://developers.meta.com/horizon/documentation/unity/body-tracking-samples).

## Player Settings

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ public class RecalculateNormals : MonoBehaviour
/// </summary>
[SerializeField]
[Tooltip(RecalculateNormalsTooltips.RecalculateIndependently)]
protected bool _recalculateIndependently = false;
protected bool _recalculateIndependently = true;

/// <summary>
/// The layer of the duplicate mesh with recalculate normals, should
Expand Down
10 changes: 10 additions & 0 deletions Runtime/Scripts/Tooltips.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2031,4 +2031,14 @@ public static class TargetOffsetCorrectionTooltips
public const string GroundingConstraint =
"Foot grounding constraint.";
}

public static class VisemeDriverTooltips
{
public const string OvrFaceExpression =
"OvrFaceExpression component in the scene.";
public const string VisemeMapping =
"The mapping between the blendshapes and the FaceViseme.";
public const string Mesh =
"The mesh with viseme-compatible blendshapes.";
}
}
8 changes: 8 additions & 0 deletions Runtime/Scripts/Tracking/Viseme.meta

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

160 changes: 160 additions & 0 deletions Runtime/Scripts/Tracking/Viseme/VisemeDriver.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
// Copyright (c) Meta Platforms, Inc. and affiliates.

using Oculus.Movement;
using System;
using UnityEngine;
using UnityEngine.Assertions;
using static OVRFaceExpressions;

namespace Meta.XR.Movement.FaceTracking
{
/// <summary>
/// This component drives the blendshapes from the <see cref="SkinnedMeshRenderer"/>
/// based on the weights that we we get for each visemes using <see cref="OVRFaceExpressions"/>.
/// The blendshapes are mapped with an array of Visemes via <see cref="FaceViseme"/>.
/// The fields are accessible with the help of <see cref="VisemeDriverEditor"/>.
/// </summary>
[RequireComponent(typeof(SkinnedMeshRenderer))]
public class VisemeDriver : MonoBehaviour
{
/// <summary>
/// This mesh is accessed and set on enable in the <see cref="VisemeDriverEditor"/>
/// </summary>
public SkinnedMeshRenderer VisemeMesh
{
get { return _mesh; }
set { _mesh = value; }
}

/// <summary>
/// Checks if visemes are valid and gets the weights received from the visemes.
/// </summary>
[SerializeField]
[Tooltip(VisemeDriverTooltips.OvrFaceExpression)]
protected OVRFaceExpressions _ovrFaceExpressions;

/// <summary>
/// The array is populated based on the number of blendshapes in the <see cref="SkinnedMeshRenderer"/>.
/// The blendshapes get assigned to the closest <see cref="FaceViseme"/> based on the
/// blendshape name using <see cref="GetClosestViseme(string)"/>.
/// </summary>
[SerializeField]
[Tooltip(VisemeDriverTooltips.VisemeMapping)]
protected FaceViseme[] _visemeMapping;

/// <summary>
/// The mesh that should contain viseme-compatible blendshapes.
/// </summary>
[SerializeField]
[Tooltip(VisemeDriverTooltips.Mesh)]
protected SkinnedMeshRenderer _mesh;

private const string _VISEME_PREFIX = "viseme_";

private void Awake()
{
Assert.IsNotNull(_mesh);
Assert.IsNotNull(_ovrFaceExpressions);
}

private void Update()
{
if (_ovrFaceExpressions.AreVisemesValid)
{
UpdateVisemes();
}
}

/// <summary>
/// Map the <see cref="FaceViseme"/> to the blendshapes in the <see cref="SkinnedMeshRenderer"/>
/// after pressing the "Auto Generate Mapping" button in the <see cref="VisemeDriverEditor"/>.
/// </summary>
public void AutoMapBlendshapes()
{
_visemeMapping = new FaceViseme[_mesh.sharedMesh.blendShapeCount];

for (int i = 0; i < _mesh.sharedMesh.blendShapeCount; i++)
{
_visemeMapping[i] = GetClosestViseme(_mesh.sharedMesh.GetBlendShapeName(i).ToLower());
}
}

/// <summary>
/// Clears blendshapes by turning all the <see cref="_visemeMapping"/> to <see cref=" OVRFaceExpressions.FaceViseme.Invalid"/>.
/// </summary>
public void ClearBlendshapes()
{
if (_mesh == null || _mesh.sharedMesh.blendShapeCount == 0)
{
return;
}

for (int i = 0; i < _mesh.sharedMesh.blendShapeCount; ++i)
{
_visemeMapping[i] = OVRFaceExpressions.FaceViseme.Invalid;
}
}

private FaceViseme GetClosestViseme(string blendshapeName)
{
foreach (FaceViseme viseme in Enum.GetValues(typeof(FaceViseme)))
{
if (viseme == FaceViseme.Invalid || viseme == FaceViseme.Count)
{
continue;
}

string visemeName = viseme.ToString().ToLower();

if (blendshapeName == visemeName)
{
return viseme;
}

string prefixedName = _VISEME_PREFIX + visemeName;

if (blendshapeName == prefixedName)
{
return viseme;
}

char firstChar = visemeName[0];
prefixedName = _VISEME_PREFIX + firstChar;
if (blendshapeName == prefixedName)
{
return viseme;
}

if (visemeName.Length > 1 && visemeName.Length <= 2)
{
char secondChar = visemeName[1];
prefixedName = _VISEME_PREFIX + secondChar;
if (blendshapeName == prefixedName)
{
return viseme;
}
}
}
return OVRFaceExpressions.FaceViseme.Invalid;
}

private void UpdateVisemes()
{
if (_mesh == null || _visemeMapping.Length == 0 || _ovrFaceExpressions != null)
{
return;
}

for (int i = 0; i < _visemeMapping.Length; i++)
{
if (_visemeMapping[i] == FaceViseme.Invalid || _visemeMapping[i] == FaceViseme.Count)
{
continue;
}

_ovrFaceExpressions.TryGetFaceViseme(_visemeMapping[i], out float visemeWeight);
_mesh.SetBlendShapeWeight(i, visemeWeight);
}
}
}
}
11 changes: 11 additions & 0 deletions Runtime/Scripts/Tracking/Viseme/VisemeDriver.cs.meta

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

8 changes: 8 additions & 0 deletions Samples.meta

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

8 changes: 8 additions & 0 deletions Samples/AdvancedSamples.meta

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

Loading

0 comments on commit a80a852

Please sign in to comment.