Thèmes visuels — MRTK2

Les thèmes permettent un contrôle flexible des ressources d’expérience utilisateur en réponse aux différentes transitions d’états. Cela peut impliquer la modification de la couleur d’un bouton, le redimensionnement d’un élément en réponse au focus, etc. L’infrastructure De thèmes visuels est constituée de deux éléments clés : 1) configuration et 2) moteurs d’exécution.

Les configurations de thème sont des définitions de propriétés et de types tandis que les moteurs de thème sont des classes qui consomment les configurations et implémentent la logique pour mettre à jour les transformations, les matériaux et bien plus encore au moment de l’exécution.

Configuration du thème

Les configurations de thème sont ScriptableObjects qui définissent la façon dont les moteurs de thème seront initialisés au moment de l’exécution. Ils définissent les propriétés et les valeurs à utiliser en réponse aux modifications d’état d’entrée ou d’autres modifications d’état lorsque l’application est en cours d’exécution. En tant que ressources ScriptableObjects, les configurations de thème peuvent être définies une seule fois, puis réutilisées sur différents composants d’expérience utilisateur.

Pour créer une ressource Theme :

  1. Cliquez avec le bouton droit dans la fenêtre Project
  2. Sélectionner Créer>Mixed Reality Thème du kit de ressources>

Vous trouverez des exemples de ressources de configuration de thème sous MRTK/SDK/Features/UX/Interactable/Themes.

Theme ScriptableObject example in inspector

États

Lors de la création d’un nouveau Theme, la première chose à définir est ce que les états sont disponibles. La propriété States indique le nombre de valeurs dont la configuration de thème doit être définie, car il y aura une valeur par état. Dans l’exemple d’image ci-dessus, les états par défaut définis pour le composant interagissant sont Default, Focus, Pressed et Disabled. Ces éléments sont définis dans le DefaultInteractableStates fichier de ressources (Assets/MRTK/SDK/Features/UX/Interactable/States).

Pour créer une ressource State :

  1. Cliquez avec le bouton droit dans la fenêtre Project
  2. Sélectionner Créer> Mixed RealityÉtatdu kit de ressources>

States ScriptableObject example in inspector

Un State ScriptableObject définit à la fois la liste des états ainsi que le type de StateModel à créer pour ces états. StateModel est une classe qui étend BaseStateModel et implémente la logique de l’ordinateur d’état pour générer l’état actuel au moment de l’exécution. L’état actuel de cette classe est généralement utilisé par les moteurs de thème au moment de l’exécution pour dicter les valeurs à définir sur les propriétés matérielles, les transformations GameObject, etc.

Propriétés du moteur de thème

En dehors des États, une Theme ressource définit également une liste de moteurs de thème et les propriétés associées pour ces moteurs. Un moteur de thème définit à nouveau la logique pour définir les valeurs correctes sur un GameObject au moment de l’exécution.

Une Theme ressource peut définir plusieurs moteurs de thème pour obtenir des transitions d’états visuels sophistiqués ciblant plusieurs propriétés GameObject.

Runtime de thème

Définit le type de classe du moteur de thème qui sera créé

Assouplissement

Certains moteurs de thème, s’ils définissent leur propriété IsEasingSupported comme vrai, prennent en charge l’accélération entre les états. Par exemple, lerping entre deux couleurs lorsqu’une modification d’état se produit. La durée définit en secondes la durée de facilité entre la valeur de début et la valeur de fin et la courbe d’animation définit le taux de modification pendant cette période.

Propriétés du nuanceur

Certains moteurs de thème, s’ils définissent leur propriété AreShadersSupported comme vrai, modifient des propriétés de nuanceur particulières au moment de l’exécution. Les champs Nuanceur et Propriété définissent la propriété nuanceur à cibler.

Créer une configuration de thème via du code

En général, il est plus facile de concevoir des configurations de thème via l’inspecteur Unity, mais il existe des cas où les thèmes doivent être générés dynamiquement au moment de l’exécution via du code. L’extrait de code ci-dessous montre comment accomplir cette tâche.

Pour accélérer le développement, les méthodes d’assistance suivantes sont utiles pour simplifier l’installation.

Interactable.GetDefaultInteractableStates() - crée un ScriptableObject États avec les quatre valeurs d’état par défaut utilisées dans le composant Interactable .

ThemeDefinition.GetDefaultThemeDefinition<T>() - Chaque moteur de thème définit une configuration par défaut avec les propriétés appropriées nécessaires pour ce type d’exécution de thème. Cet assistance crée une définition pour le type de moteur de thème donné.

// This code example builds a Theme ScriptableObject that can be used with an Interactable component.
// A random color is selected for the on pressed state every time this code is executed.

// Use the default states utilized in the Interactable component
var defaultStates = Interactable.GetDefaultInteractableStates();

// Get the default configuration for the Theme engine InteractableColorTheme
var newThemeType = ThemeDefinition.GetDefaultThemeDefinition<InteractableColorTheme>().Value;

// Define a color for every state in our Default Interactable States
newThemeType.StateProperties[0].Values = new List<ThemePropertyValue>()
{
    new ThemePropertyValue() { Color = Color.black},  // Default
    new ThemePropertyValue() { Color = Color.black}, // Focus
    new ThemePropertyValue() { Color = Random.ColorHSV()},   // Pressed
    new ThemePropertyValue() { Color = Color.black},   // Disabled
};

// Create the Theme configuration asset
Theme testTheme = ScriptableObject.CreateInstance<Theme>();
testTheme.States = defaultStates;
testTheme.Definitions = new List<ThemeDefinition>() { newThemeType };

Moteurs de thème

Un moteur de thème est une classe qui s’étend de la InteractableThemeBase classe. Ces classes sont instanciées au moment de l’exécution et configurées avec un ThemeDefinition objet comme décrit précédemment.

Moteurs de thème par défaut

MRTK est fourni avec un ensemble par défaut de moteurs de thème répertoriés ci-dessous :

Les moteurs de thème par défaut sont disponibles sous MRTK/SDK/Features/UX/Scripts/VisualThemes/ThemeEngines.

Moteurs de thème personnalisés

Comme indiqué, un moteur de thème est défini comme une classe qui s’étend de la InteractableThemeBase classe. Ainsi, le nouveau moteur de thème n’a besoin que d’étendre cette classe et d’implémenter les éléments suivants :

Implémentations obligatoires

public abstract void SetValue(ThemeStateProperty property, int index, float percentage) (xref:Microsoft.MixedReality.Toolkit.UI.InteractableThemeBase.SetValue)

Pour la propriété donnée, qui peut être identifiée par ThemeStateProperty.Name, définissez sa valeur d’état actuelle sur l’hôte GameObject ciblé (c’est-à-dire définir la couleur du matériau, etc.). L’index indique la valeur d’état actuelle à accéder et le pourcentage, un flotteur compris entre 0 et 1, est utilisé pour l’accélération/lerping entre les valeurs.

public abstract ThemePropertyValue GetProperty(ThemeStateProperty property)(xref:Microsoft.MixedReality.Toolkit.UI.InteractableThemeBase.GetProperty)

Pour la propriété donnée, qui peut être identifiée par ThemeStateProperty.Name, retournez la valeur actuelle définie sur l’Hôte GameObject ciblé (c’est-à-dire la couleur de matériau actuelle, le décalage de position local actuel, etc.). Ceci est principalement utilisé pour mettre en cache la valeur de début lors de l’accélération entre les états.

public abstract ThemeDefinition GetDefaultThemeDefinition()(xref:Microsoft.MixedReality.Toolkit.UI.InteractableThemeBase.GetDefaultThemeDefinition)

Retourne un ThemeDefinition objet qui définit les propriétés et la configuration par défaut nécessaires pour le thème personnalisé

protected abstract void SetValue(ThemeStateProperty property, ThemePropertyValue value)

Variante protégée de la définition publique SetValue() , à l’exception du paramètre ThemePropertyValue à définir au lieu de diriger pour utiliser l’index et/ou la configuration de pourcentage.

InteractableThemeBase.Init(GameObject host, ThemeDefinition settings)

Effectuez toutes les étapes d’initialisation ici ciblant le paramètre GameObject fourni et en utilisant les propriétés et les configurations définies dans le paramètre ThemeDefinition . Il est recommandé d’appeler base.Init(host, settings) au début d’un remplacement.

InteractableThemeBase.IsEasingSupported

Si le moteur de thème personnalisé peut prendre en charge l’accélération entre les valeurs configurées via la ThemeDefinition.Easing propriété.

InteractableThemeBase.AreShadersSupported

Si le moteur de thème personnalisé peut prendre en charge les propriétés du nuanceur de ciblage. Il est recommandé d’étendre l’infrastructure InteractableShaderTheme existante pour définir/obtenir efficacement les propriétés du nuanceur via MaterialPropertyBlocks. Les informations de propriété du nuanceur sont stockées dans chaque ThemeStateProperty via ThemeStateProperty.TargetShader et ThemeStateProperty.ShaderPropertyName.

Notes

Si vous étendez InteractableShaderTheme, il peut également être utile de remplacer l’InteractableShaderTheme.DefaultShaderProperty via new.

Exemple de code : protected new const string DefaultShaderProperty = "_Color";

En outre, les classes suivantes ci-dessous étendent la InteractableShaderTheme classe qui utilise à nouveau MaterialPropertyBlocks pour modifier les valeurs de propriété du nuanceur. Cette approche aide les performances , car MaterialPropertyBlocks ne crée pas de matériaux instanced lorsque les valeurs changent. Toutefois, l’accès aux propriétés de classe Material standard ne retourne pas les valeurs attendues. Utilisez MaterialPropertyBlocks pour obtenir et valider les valeurs de propriété matérielle actuelles (c’est-à-dire _Color ou _MainTex).

InteractableThemeBase.Reset

Dirige le thème pour réinitialiser toutes les propriétés modifiées à leurs valeurs d’origine définies sur l’hôte GameObject lorsque ce moteur de thème a été initialisé.

Exemple de moteur de thème personnalisé

La classe ci-dessous est un exemple de nouveau moteur de thème personnalisé. Cette implémentation recherche un composant MeshRenderer sur l’objet hôte initialisé et contrôle sa visibilité en fonction de l’état actuel.

using Microsoft.MixedReality.Toolkit.UI;
using System;
using System.Collections.Generic;
using UnityEngine;

// This class demonstrates a custom theme to control a Host's MeshRenderer visibility
public class MeshVisibilityTheme : InteractableThemeBase
{
    // Bool visibility does not make sense for lerping
    public override bool IsEasingSupported => false;

    // No material or shaders are being modified
    public override bool AreShadersSupported => false;

    // Cache reference to the MeshRenderer component on our Host
    private MeshRenderer meshRenderer;

    public MeshVisibilityTheme()
    {
        Types = new Type[] { typeof(MeshRenderer) };
        Name = "Mesh Visibility Theme";
    }

    // Define a default configuration to simplify initialization of this theme engine
    // There is only one state property with a value per available state
    // This state property is a boolean that defines whether the renderer is enabled
    public override ThemeDefinition GetDefaultThemeDefinition()
    {
        return new ThemeDefinition()
        {
            ThemeType = GetType(),
            StateProperties = new List<ThemeStateProperty>()
            {
                new ThemeStateProperty()
                {
                    Name = "Mesh Visible",
                    Type = ThemePropertyTypes.Bool,
                    Values = new List<ThemePropertyValue>(),
                    Default = new ThemePropertyValue() { Bool = true }
                },
            },
            CustomProperties = new List<ThemeProperty>()
        };
    }

    // When initializing, cache a reference to the MeshRenderer component
    public override void Init(GameObject host, ThemeDefinition definition)
    {
        base.Init(host, definition);

        meshRenderer = host.GetComponent<MeshRenderer>();
    }

    // Get the current state of the MeshRenderer visibility
    public override ThemePropertyValue GetProperty(ThemeStateProperty property)
    {
        return new ThemePropertyValue()
        {
            Bool = meshRenderer.enabled
        };
    }

    // Update the MeshRenderer visibility based on the property state value data
    public override void SetValue(ThemeStateProperty property, int index, float percentage)
    {
        meshRenderer.enabled = property.Values[index].Bool;
    }
}

Exemple de bout en bout

L’extension du moteur de thème personnalisé défini dans la section précédente, l’exemple de code ci-dessous montre comment contrôler ce thème au moment de l’exécution. En particulier, comment définir l’état actuel sur le thème afin que la visibilité de MeshRenderer soit mise à jour de manière appropriée.

Notes

theme.OnUpdate(state,force) doit généralement être appelé dans la méthode Update() pour prendre en charge les moteurs de thème qui utilisent l’accélération/lerping entre les valeurs.

using Microsoft.MixedReality.Toolkit.UI;
using System;
using System.Collections.Generic;
using UnityEngine;

public class MeshVisibilityController : MonoBehaviour
{
    private MeshVisibilityTheme themeEngine;
    private bool hideMesh = false;

    private void Start()
    {
        // Define the default configuration. State 0 will be on while State 1 will be off
        var themeDefinition = ThemeDefinition.GetDefaultThemeDefinition<MeshVisibilityTheme>().Value;
        themeDefinition.StateProperties[0].Values = new List<ThemePropertyValue>()
        {
            new ThemePropertyValue() { Bool = true }, // show state
            new ThemePropertyValue() { Bool = false }, // hide state
        };

        // Create the actual Theme engine and initialize it with the GameObject we are attached to
        themeEngine = (MeshVisibilityTheme)InteractableThemeBase.CreateAndInitTheme(themeDefinition, this.gameObject);
    }

    private void Update()
    {
        // Update the theme engine to set our MeshRenderer visibility
        // based on our current state (i.e the hideMesh variable)
        themeEngine.OnUpdate(Convert.ToInt32(hideMesh));
    }

    public void ToggleVisibility()
    {
        // Alternate state of visibility
        hideMesh = !hideMesh;
    }
}

Voir aussi