Visuele thema's

Thema's bieden flexibele controle over UX-assets in reactie op verschillende overgangen van staten. Dit kan betrekking hebben op het wijzigen van de kleur van een knop, het wijzigen van het formaat van een element als reactie op de focus, enzovoort. Het Visual Themes-framework bestaat uit twee belangrijke onderdelen: 1) configuratie en 2) runtime-engines.

Themaconfiguraties zijn definities van eigenschappen en typen, terwijl Thema-engines klassen zijn die de configuraties gebruiken en de logica implementeren voor het bijwerken van transformaties, materialen en meer tijdens runtime.

Themaconfiguratie

Themaconfiguraties zijn ScriptableObjects die definiëren hoe thema-engines tijdens runtime worden initialiseren. Ze definiëren welke eigenschappen en waarden moeten worden gebruikt als reactie op invoer- of andere statuswijzigingen wanneer de app wordt uitgevoerd. Als ScriptableObjects-assets kunnen themaconfiguraties eenmaal worden gedefinieerd en vervolgens opnieuw worden gebruikt in verschillende UX-onderdelen.

Een nieuwe asset Theme maken:

  1. Klik met de rechtermuisknop in Project venster
  2. Selecteer Een > Mixed Reality Toolkit > maken

Voorbeeld van assets voor de configuratie van thema's vindt u onder MRTK/SDK/Features/UX/Interactable/Themes .

Voorbeeld van ThemascriptableObject in inspector

Staten

Bij het maken van een Theme nieuwe moet u eerst instellen welke staten beschikbaar zijn. De eigenschap Statussen geeft aan hoeveel waarden een themaconfiguratie moet definiëren, aangezien er één waarde per status is. In de bovenstaande voorbeeldafbeelding zijn de standaardwaarden die zijn gedefinieerd voor het onderdeel Interactable Standaard, Focus, Ingedrukt en Uitgeschakeld. Deze worden gedefinieerd in het assetbestand DefaultInteractableStates Assets/MRTK/SDK/Features/UX/Interactable/States.

Een nieuwe asset State maken:

  1. Klik met de rechtermuisknop in Project venster
  2. Selecteer Een > Mixed Reality Toolkit > maken

ScriptableObject-voorbeeld in inspector

Een State ScriptableObject definieert zowel de lijst met statussen als het type StateModel dat voor deze statussen moet worden gemaakt. Een StateModel is een klasse die de logica van de statusmachine uitbreidt en implementeert om de BaseStateModel huidige status tijdens runtime te genereren. De huidige status van deze klasse wordt in het algemeen gebruikt door Thema-engines tijdens runtime om te bepalen welke waarden moeten worden ingesteld op basis van materiaaleigenschappen, GameObject-transformaties en meer.

Eigenschappen van thema-engine

Buiten Staten definieert een asset ook een lijst met Theme thema-engines en de bijbehorende eigenschappen voor deze engines. Een thema-engine definieert opnieuw de logica voor het instellen van de juiste waarden voor een GameObject tijdens runtime.

Een asset kan meerdere thema-engines definiëren om geavanceerde visuele overgangen voor de staten te bereiken die Theme zijn gericht op meerdere GameObject-eigenschappen.

Themaruntime

Hiermee definieert u het klassetype van de thema-engine die wordt gemaakt

Versoepeling

Sommige thema-engines bieden ondersteuning voor easing tussen staten als ze hun eigenschap IsEasingSupported definiëren als true. Bijvoorbeeld wanneer er een statuswijziging optreedt tussen twee kleuren. De Duur definieert in seconden hoe lang de beginwaarde naar de eindwaarde moet worden vereengeld en de animatiecurve definieert de wijzigingsfrequentie gedurende die periode.

Eigenschappen van shader

Sommige thema-engines, als ze hun eigenschap AreShadersSupported definiëren als true, wijzigen bepaalde shadereigenschappen tijdens runtime. De velden Shader en Eigenschap definiëren de shader-eigenschap die moet worden gericht.

Een themaconfiguratie maken via code

Over het algemeen is het eenvoudiger om Themaconfiguraties te ontwerpen via de Unity Inspector, maar er zijn gevallen waarin thema's dynamisch moeten worden gegenereerd tijdens runtime via code. Het onderstaande codefragment geeft een voorbeeld van hoe u deze taak kunt uitvoeren.

Om de ontwikkeling te versnellen, zijn de volgende helpermethoden handig om de installatie te vereenvoudigen.

Interactable.GetDefaultInteractableStates()- maakt een nieuw States ScriptableObject met de vier standaard statuswaarden die worden gebruikt in het onderdeel Interactable.

ThemeDefinition.GetDefaultThemeDefinition<T>() - Elke thema-engine definieert een standaardconfiguratie met de juiste eigenschappen die nodig zijn voor dat type themaruntime. Deze helper maakt een definitie voor het opgegeven type thema-engine.

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

Thema-engines

Een thema-engine is een klasse die uit de klasse InteractableThemeBase is uitgebreid. Deze klassen worden tijdens runtime gemaakt en geconfigureerd met een ThemeDefinition -object zoals eerder beschreven.

Standaardthema-engines

MRTK wordt geleverd met een standaardset thema-engines die hieronder worden vermeld:

De standaardthema-engines vindt u onder MRTK/SDK/Features/UX/Scripts/VisualThemes/ThemeEngines .

Aangepaste thema-engines

Zoals vermeld, wordt een thema-engine gedefinieerd als een klasse die van de klasse InteractableThemeBase is uitgebreid. De nieuwe thema-engine hoeft deze klasse dus alleen uit te breiden en het volgende te implementeren:

Verplichte implementaties

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

Voor de opgegeven eigenschap, die kan worden geïdentificeerd door , stelt u de huidige statuswaarde in op de ThemeStateProperty.Name doelhost van GameObject (dat wil zeggen de kleur van het materiaal instellen, enzovoort). De index geeft de huidige statuswaarde aan die moet worden gebruikt en het percentage, een float tussen 0 en 1, wordt gebruikt voor het toegankelijkheid/afwisselen tussen waarden.

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

Voor de opgegeven eigenschap, die kan worden geïdentificeerd door , retourneert u de huidige waarde die is ingesteld op het ThemeStateProperty.Name doelhost-GameObject (dat wil zeggen de kleur van het huidige materiaal, de huidige verschuiving van de lokale positie, enzovoort). Dit wordt voornamelijk gebruikt voor het in de caching van de beginwaarde bij het ruimen tussen staten.

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

Retourneert een ThemeDefinition -object dat de standaardeigenschappen en configuratie definieert die nodig zijn voor het aangepaste thema

protected abstract void SetValue(ThemeStateProperty property, ThemePropertyValue value)

Beveiligde variant van de openbare definitie, behalve de opgegeven ThemePropertyValue om in te stellen in plaats van te sturen naar het gebruik SetValue() van index- en/of percentageconfiguratie.

InteractableThemeBase.Init(GameObject host, ThemeDefinition settings)

Voer hier initialisatiestappen uit die zijn gericht op de opgegeven Parameter GameObject en gebruik de eigenschappen en configuraties die zijn gedefinieerd in de parameter ThemeDefinition. Het is raadzaam om aan te base.Init(host, settings) roepen aan het begin van een overschrijven.

InteractableThemeBase.IsEasingSupported

Als de aangepaste thema-engine ondersteuning biedt voor het ruimen tussen waarden die zijn geconfigureerd via de ThemeDefinition.Easing eigenschap .

InteractableThemeBase.AreShadersSupported

Of de aangepaste thema-engine ondersteuning kan bieden voor de eigenschappen van de shader. Het is raadzaam om uit te breiden van om te profiteren van de bestaande infrastructuur om op efficiënte wijze shader-eigenschappen in te stellen/op te halen InteractableShaderTheme via MaterialPropertyBlocks. De informatie over de shader-eigenschap wordt in elk ThemeStateProperty opgeslagen via ThemeStateProperty.TargetShader en ThemeStateProperty.ShaderPropertyName .

Notitie

Als u uitbreidt, kan het ook handig zijn om InteractableShaderTheme InteractableShaderTheme.DefaultShaderProperty te overschrijven via de nieuwe.

Voorbeeldcode: protected new const string DefaultShaderProperty = "_Color";

Bovendien breiden de volgende klassen hieronder de klasse uit die opnieuw InteractableShaderTheme materialPropertyBlocks gebruikt om de eigenschapswaarden van de shader te wijzigen. Deze aanpak helpt de prestaties, omdat MaterialPropertyBlocks geen nieuwe instantiematerialen maakt wanneer waarden veranderen. Toegang tot de typische eigenschappen van materiaalklassen retourneert echter geen verwachte waarden. MaterialPropertyBlocks gebruiken om de huidige eigenschapswaarden van materiaal op te halen en te valideren (dat wil zeggen _Color of _MainTex).

InteractableThemeBase.Reset

Hiermee wordt het thema om gewijzigde eigenschappen terug te zetten naar de oorspronkelijke waarden die zijn ingesteld op de host GameObject tijdens de initialiseren van deze thema-engine.

Voorbeeld van aangepaste thema-engine

De onderstaande klasse is een voorbeeld van een aangepaste nieuwe thema-engine. Deze implementatie vindt een MeshRenderer-onderdeel op het geitialiseerde hostobject en controleert de zichtbaarheid ervan op basis van de huidige status.

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

Voorbeeld van het hele proces

In het onderstaande codevoorbeeld wordt gedemonstreerd hoe u dit thema tijdens runtime kunt bepalen. Dit is een uitbreiding van de aangepaste thema-engine die in de vorige sectie is gedefinieerd. In het bijzonder hoe u de huidige status voor het thema in kunt stellen, zodat de zichtbaarheid van MeshRenderer op de juiste wijze wordt bijgewerkt.

Notitie

theme.OnUpdate(state,force) moet over het algemeen worden aangeroepen in de update()-methode ter ondersteuning van thema-engines die gebruikmaken van vereending/lerping tussen waarden.

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

Zie ook