Vizuální motivy

Motivy umožňují flexibilní kontrolu nad prostředky uživatelského rozhraní v reakci na přechody různých stavů. To může zahrnovat změnu barvy tlačítka, změnu velikosti prvku v reakci na fokus atd. Rozhraní vizuálních motivů se skládá ze dvou klíčových částí: 1) konfigurace a 2) modulů runtime.

Konfigurace motivů jsou definice vlastností a typů, zatímco moduly motivů jsou třídy, které využívají konfigurace a implementují logiku pro aktualizaci transformací, materiálů a dalších funkcí za běhu.

Konfigurace motivu

Konfigurace motivů jsou objekty ScriptableObject, které definují, jak budou moduly motivu inicializovány za běhu. Definují, které vlastnosti a hodnoty se mají použít v reakci na změny stavu nebo vstupu, když je aplikace spuštěná. Jako prostředky ScriptableObjects je možné konfigurace motivů definovat jednou a pak je znovu použít napříč různými komponentami uživatelského prostředí.

Vytvoření nového Theme assetu:

  1. Klikněte pravým tlačítkem do Project okna.
  2. Vyberte Create Mixed Reality ToolkitTheme (Vytvořit Mixed Reality Toolkitmotivu).

Příklad prostředků konfigurace motivu najdete v části MRTK/SDK/Features/UX/Interactable/Themes .

Příklad objektu ScriptableObject motivu v inspektoru

Stavy

Při vytváření nového Theme je první věcí, kterou je třeba nastavit, jaké stavy jsou k dispozici. Vlastnost States určuje, kolik hodnot musí konfigurace Motivu definovat, protože pro každý stav bude jedna hodnota. Na výše uvedeném obrázku jsou výchozí stavy definované pro komponentu Interactablevýchozí, fokus,stisknutou azakázanou. Jsou definované v souboru prostředků DefaultInteractableStates (Assets/MRTK/SDK/Features/UX/Interactable/States).

Vytvoření nového State assetu:

  1. Klikněte pravým tlačítkem do Project okna.
  2. Vyberte VytvořitMixed Reality Toolkitstavu.

Příklad States ScriptableObject v inspektoru

Objekt ScriptableObject definuje seznam stavů i typ StateState který se má pro tyto stavy vytvořit. StateModel je třída, která rozšiřuje a implementuje logiku stavového počítače a generuje aktuální stav za běhu. Aktuální stav z této třídy se obecně používá moduly motivů za běhu k diktování hodnot, které se mají nastavit pro vlastnosti materiálu, transformace GameObject a další.

Vlastnosti modulu motivu

Mimo Statesdefinuje asset také seznam modulů motivů a přidružených vlastností pro tyto moduly. Modul motivu znovu definuje logiku pro nastavení správných hodnot proti objektu GameObject za běhu.

Asset Theme může definovat více modulů motivů, aby bylo možné dosáhnout sofistikovaných vizuálních stavů přechodů cílených na více vlastností GameObject.

Modul runtime motivu

Definuje typ třídy modulu Motiv, který se vytvoří.

Uvolňování

Některé moduly motivů, pokud definují svou vlastnost IsEasingSupported jako true, podporují usnadnění mezi stavy. Například když dojde ke změně stavu, může se tolerovat mezi dvěma barvami. Doba trvání definuje v sekundách, jak dlouho se má usnadnit od počáteční hodnoty po koncovou hodnotu, a animační křivka definuje rychlost změn během tohoto časového období.

Vlastnosti shaderu

Některé moduly motivů, pokud definují svou vlastnost AreShadersSupported jako true, upraví konkrétní vlastnosti shaderu za běhu. Pole Shader a Property definují vlastnost shaderu, na který se má cílit.

Vytvoření konfigurace motivu prostřednictvím kódu

Obecně je jednodušší navrhnout konfigurace motivů prostřednictvím inspektoru Unity, ale existují případy, kdy se motivy musí dynamicky generovat za běhu prostřednictvím kódu. Následující fragment kódu obsahuje příklad, jak tuto úlohu provést.

Pro usnadnění vývoje jsou užitečné následující pomocné metody, které zjednodušují nastavení.

Interactable.GetDefaultInteractableStates()– vytvoří nový objekt States ScriptableObject se čtyřmi výchozími hodnotami stavu použitými v Interactable.GetDefaultInteractableStates()

ThemeDefinition.GetDefaultThemeDefinition<T>() – Každý modul motivů definuje výchozí konfiguraci se správnými vlastnostmi potřebnými pro tento typ modulu runtime motivu. Tento pomocná metoda vytvoří definici pro daný typ modulu motivu.

// 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 };

Moduly motivů

Theme Engine je třída, která rozšiřuje třídu . Tyto třídy jsou vytvořeny za běhu a nakonfigurovány ThemeDefinition objektem, jak je uvedeno výše.

Výchozí moduly motivů

MrTK se dodává s výchozí sadu modulů motivů uvedených níže:

Výchozí moduly motivů najdete v části MRTK/SDK/Features/UX/Scripts/VisualThemes/ThemeEngines .

Moduly s vlastním motivem

Jak jsme uvedli, modul motivů je definován jako třída, která rozšiřuje třídu InteractableThemeBase . Nový modul motivů proto potřebuje pouze rozšířit tuto třídu a implementovat následující:

Povinné implementace

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

Pro danou vlastnost, kterou lze identifikovat pomocí , nastavte jeho aktuální hodnotu stavu na cílovém hostiteli GameObject (tj. nastavte barvu materiálu ThemeStateProperty.Name atd.). Index označuje aktuální hodnotu stavu, ke které se má získat přístup, a procentuální hodnotu (float)mezi 0 a 1, která se používá k usnadnění/uskutečování mezi hodnotami.

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

Pro danou vlastnost, kterou lze identifikovat pomocí , vraťte aktuální hodnotu nastavenou u cílového objektu Host GameObject (tj. aktuální barvu materiálu, posun ThemeStateProperty.Name aktuální místní pozice atd.). To se primárně používá pro ukládání počáteční hodnoty do mezipaměti při usnadnění mezi stavy.

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

Vrátí ThemeDefinition objekt, který definuje výchozí vlastnosti a konfiguraci potřebné pro vlastní motiv.

protected abstract void SetValue(ThemeStateProperty property, ThemePropertyValue value)

Chráněná varianta veřejné definice s výjimkou poskytnuté hodnoty ThemePropertyValue k nastavení namísto použití konfigurace indexu nebo SetValue() procenta.

InteractableThemeBase.Init(GameObject host, ThemeDefinition settings)

Proveďte všechny kroky inicializace, které cílí na poskytnutý parametr GameObject a pomocí vlastností a konfigurací definovaných v parametru ThemeDefinition. Doporučuje se volat base.Init(host, settings) na začátku přepsání.

InteractableThemeBase.IsEasingSupported

Pokud vlastní modul motivů podporuje usnadnění mezi hodnotami, které se konfigurují prostřednictvím ThemeDefinition.Easing vlastnosti .

InteractableThemeBase.AreShadersSupported

Pokud vlastní modul motivů podporuje cílení na vlastnosti shaderu. Doporučujeme rozšířit z na výhody stávající infrastruktury a efektivně InteractableShaderTheme nastavit/získat vlastnosti shaderu prostřednictvím InteractableShaderTheme. Informace o vlastnostech shaderu jsou uložené v jednotlivých ThemeStateProperty objektech prostřednictvím a ThemeStateProperty.TargetShaderThemeStateProperty.ShaderPropertyName .

Poznámka

Pokud rozšiřujete , může být také užitečné přepsat InteractableShaderThemeInteractableShaderTheme prostřednictvím nového.

Příklad kódu: protected new const string DefaultShaderProperty = "_Color";

Následující třídy dále rozšiřují třídu , která znovu používá InteractableShaderThemeInteractableShaderTheme k úpravě hodnot vlastností shaderu. Tento přístup pomáhá výkon,protože MaterialPropertyBlocks při změně hodnot nevytváří nové instance materiálů. Přístup k typickým vlastnostem třídy Material ale nevrátí očekávané hodnoty. MaterialPropertyBlocks slouží k získání a ověření aktuálních hodnot vlastností material (tj. _Color nebo _MainTex).

InteractableThemeBase.Reset

Nasměruje motiv tak, aby obnovil všechny změněné vlastnosti zpět na původní hodnoty, které byly nastaveny na hostitelském objektu GameObject při inicializaci tohoto modulu motivu.

Příklad modulu vlastních motivů

Níže uvedená třída je příkladem vlastního nového modulu motivu. Tato implementace najde komponentu MeshRenderer u inicializovaného objektu hostitele a řídí jeho viditelnost na základě aktuálního stavu.

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;
    }
}

Kompletní příklad

Rozšíření vlastního modulu motivu definovaného v předchozí části ukazuje následující příklad kódu, jak tento motiv řídit za běhu. Konkrétně jak nastavit aktuální stav motivu tak, aby se viditelnost MeshRendereru odpovídajícím způsobem aktualizovala.

Poznámka

theme.OnUpdate(state,force) Metoda Update() by obecně měla být volána, aby podporovala moduly motivů, které využívají usnadnění nebolerování mezi hodnotami.

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;
    }
}

Viz také