Visuele thema's — MRTK2
Thema's maken flexibel beheer van UX-assets mogelijk als reactie op verschillende statusovergangen. Dit kan nodig zijn om de kleur van een knop te wijzigen, het formaat van een element te wijzigen als reactie op focus, enzovoort. Het framework Visual Themes 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 om transformaties, materialen en meer bij runtime bij te werken.
Themaconfiguratie
Themaconfiguraties zijn ScriptableObjects die bepalen hoe Thema-engines tijdens runtime worden geïnitialiseerd. 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 Theme
asset maken:
- Klik met de rechtermuisknop in het projectvenster
- Selecteer Create>Mixed Reality Toolkit>Theme
Voorbeelden van themaconfiguratieassets vindt u onder MRTK/SDK/Features/UX/Interactable/Themes
.
Staten
Wanneer u een nieuwe Theme
maakt, moet u eerst instellen welke statussen beschikbaar zijn. De eigenschap Staten geeft aan hoeveel waarden een themaconfiguratie moet definiëren, omdat er één waarde per status is. In de bovenstaande voorbeeldafbeelding zijn de standaardstatussen die zijn gedefinieerd voor het onderdeel Interactie mogelijkStandaard, Focus, Ingedrukt en Uitgeschakeld. Deze worden gedefinieerd in het DefaultInteractableStates
assetbestand (Assets/MRTK/SDK/Features/UX/Interactable/States).
Een nieuwe State
asset maken:
- Klik met de rechtermuisknop in het projectvenster
- Selecteer Create>Mixed Reality Toolkit>State
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 statuscomputerlogica uitbreidt BaseStateModel
en implementeert om de huidige status tijdens runtime te genereren. De huidige status van deze klasse wordt over 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 Theme
asset ook een lijst met 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 Theme
asset kan meerdere thema-engines definiëren om geavanceerde overgangen van visuele statussen te bereiken die zijn gericht op meerdere GameObject-eigenschappen.
Themaruntime
Definieert het klassetype van de thema-engine die wordt gemaakt
Versoepeling
Als sommige thema-engines hun eigenschap IsEasingSupported definiëren als waar, ondersteunen ze versoepeling tussen staten. Bijvoorbeeld lerping tussen twee kleuren wanneer een statuswijziging plaatsvindt. De Duur definieert in seconden hoe lang u van beginwaarde naar eindwaarde moet versoepelen en de Animatiecurve definieert de snelheid van wijziging tijdens die periode.
Arceringseigenschappen
Als sommige thema-engines de eigenschap AreShadersSupported als true definiëren, worden bepaalde arceringseigenschappen tijdens runtime gewijzigd. De velden Shader en Eigenschap definiëren de arceringseigenschap die u wilt gebruiken.
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 bevat een voorbeeld van hoe u deze taak kunt uitvoeren.
Om de ontwikkeling te versnellen, zijn de volgende helpermethoden handig voor het vereenvoudigen van de installatie.
Interactable.GetDefaultInteractableStates()
- maakt een nieuw StatusScriptableObject met de vier standaardstatuswaarden die worden gebruikt in het onderdeel Interactie.
ThemeDefinition.GetDefaultThemeDefinition<T>()
- Elke thema-engine definieert een standaardconfiguratie met de juiste eigenschappen die nodig zijn voor dat themaruntimetype. Met deze helper maakt u 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 zich uitstrekt van de InteractableThemeBase
klasse. Deze klassen worden geïnstantieerd tijdens runtime en geconfigureerd met een ThemeDefinition
object zoals eerder beschreven.
Standaardthema-engines
MRTK wordt geleverd met een standaardset thema-engines die hieronder worden vermeld:
InteractableActivateTheme
InteractableAnimatorTheme
InteractableAudioTheme
InteractableColorChildrenTheme
InteractableColorTheme
InteractableGrabScaleTheme
InteractableMaterialTheme
InteractableOffsetTheme
InteractableRotationTheme
InteractableScaleTheme
InteractableShaderTheme
InteractableStringTheme
InteractableTextureTheme
ScaleOffsetColorTheme
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 zich uitbreidt van de InteractableThemeBase
klasse. De nieuwe thema-engine hoeft dus alleen deze klasse uit te breiden en het volgende te implementeren:
Verplichte implementaties
public abstract void SetValue(ThemeStateProperty property, int index, float percentage)
Voor de opgegeven eigenschap, die kan worden geïdentificeerd door ThemeStateProperty.Name
, stelt u de huidige statuswaarde in op de doel-GameObject-host (d.w.z. de materiaalkleur instellen, enzovoort). De index geeft de huidige statuswaarde aan die moet worden geopend en het percentage, een float tussen 0 en 1, wordt gebruikt voor versoepeling/tolerantie tussen waarden.
public abstract ThemePropertyValue GetProperty(ThemeStateProperty property)
Voor de opgegeven eigenschap, die kan worden geïdentificeerd door ThemeStateProperty.Name
, retourneert u de huidige waarde die is ingesteld op het doelhost-GameObject (d.w.w.v. de huidige materiaalkleur, de huidige verschuiving van de lokale positie, enzovoort). Dit wordt voornamelijk gebruikt voor het opslaan in de cache van de beginwaarde bij het versoepelen tussen statussen.
public abstract ThemeDefinition 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 SetValue()
definitie, met uitzondering van opgegeven ThemePropertyValue om in te stellen in plaats van om index- en/of percentageconfiguratie te gebruiken.
Aanbevolen onderdrukkingen
InteractableThemeBase.Init(GameObject host, ThemeDefinition settings)
Voer hier eventuele initialisatiestappen uit die gericht zijn op de opgegeven GameObject-parameter en gebruik de eigenschappen en configuraties die zijn gedefinieerd in de parameter ThemeDefinition . Het wordt aanbevolen om aan te roepen base.Init(host, settings)
aan het begin van een onderdrukking.
InteractableThemeBase.IsEasingSupported
Of de aangepaste thema-engine ondersteuning kan bieden voor versoepeling tussen waarden die via de ThemeDefinition.Easing
eigenschap zijn geconfigureerd.
InteractableThemeBase.AreShadersSupported
Als de aangepaste thema-engine ondersteuning kan bieden voor arceringseigenschappen. Het wordt aanbevolen om uit InteractableShaderTheme
te breiden van om te profiteren van de bestaande infrastructuur om efficiënt arceringseigenschappen in te stellen/te verkrijgen via MaterialPropertyBlocks. De informatie over de arceringseigenschap wordt opgeslagen in elke ThemeStateProperty
via ThemeStateProperty.TargetShader
en ThemeStateProperty.ShaderPropertyName
.
Notitie
Als u uitbreidt InteractableShaderTheme
, kan het ook handig zijn om de InteractableShaderTheme.DefaultShaderProperty via nieuw te overschrijven.
Voorbeeldcode: protected new const string DefaultShaderProperty = "_Color";
Bovendien breiden de volgende klassen hieronder de InteractableShaderTheme
klasse uit die opnieuw MaterialPropertyBlocks gebruikt om arceringseigenschapswaarden te wijzigen. Deze benadering helpt de prestaties omdat MaterialPropertyBlocks geen nieuw exemplaarmateriaal maakt wanneer waarden veranderen. Het openen van de typische eigenschappen van de materiaalklasse retourneert echter geen verwachte waarden. Gebruik MaterialPropertyBlocks om huidige materiaaleigenschapswaarden ( dat wil _Color of _MainTex) op te halen en te valideren.
Hiermee wordt het thema om gewijzigde eigenschappen terug te zetten naar de oorspronkelijke waarden die zijn ingesteld op de host GameObject toen deze thema-engine werd geïnitialiseerd.
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 geïnitialiseerde hostobject en bepaalt 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 ziet u hoe u dit thema tijdens runtime kunt beheren, naast de aangepaste thema-engine die in de eerdere sectie is gedefinieerd. In het bijzonder hoe u de huidige status van het thema instelt, zodat de zichtbaarheid van MeshRenderer op de juiste manier wordt bijgewerkt.
Notitie
theme.OnUpdate(state,force)
moet over het algemeen worden aangeroepen in de methode Update() ter ondersteuning van Theme Engines die gebruikmaken van versoepeling/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;
}
}