Bagikan melalui


Tema visual — MRTK2

Tema memungkinkan kontrol aset UX yang fleksibel sebagai respons terhadap berbagai transisi status. Ini mungkin melibatkan perubahan warna tombol, mengubah ukuran elemen sebagai respons terhadap fokus, dll. Kerangka kerja Tema Visual terdiri dari dua bagian utama: 1) konfigurasi dan 2) mesin runtime.

Konfigurasi tema adalah definisi properti dan jenis sementara Theme Engines adalah kelas yang menggunakan konfigurasi dan mengimplementasikan logika untuk memperbarui transformasi, bahan, dan banyak lagi saat runtime.

Konfigurasi tema

Konfigurasi tema adalah ScriptableObjects yang menentukan bagaimana Theme Engines akan diinisialisasi pada runtime. Mereka menentukan properti dan nilai apa yang akan digunakan sebagai respons terhadap input atau perubahan status lainnya saat aplikasi berjalan. Sebagai aset ScriptableObjects , konfigurasi tema dapat ditentukan sekali dan kemudian digunakan kembali di berbagai komponen UX.

Untuk membuat aset baru Theme :

  1. Klik kanan di Jendela Proyek
  2. Pilih Buat> Mixed RealityTemaToolkit>

Contoh aset konfigurasi Tema dapat ditemukan di bawah MRTK/SDK/Features/UX/Interactable/Themes.

Contoh Tema ScriptableObject di inspektur

Status

Saat membuat baru Theme, hal pertama yang harus ditetapkan adalah status apa yang tersedia. Properti States menunjukkan berapa banyak nilai yang perlu didefinisikan oleh konfigurasi Tema karena akan ada satu nilai per status. Dalam contoh gambar di atas, status default yang ditentukan untuk komponen Yang Dapat Berinteraksi adalah Default, Fokus, Ditekan, dan Dinonaktifkan. Ini didefinisikan dalam DefaultInteractableStates file aset (Aset/MRTK/SDK/Features/UX/Interactable/States).

Untuk membuat aset baru State :

  1. Klik kanan di Jendela Proyek
  2. Pilih Buat>Mixed Reality Status Toolkit>

Contoh Status ScriptableObject di inspektur

State ScriptableObject mendefinisikan daftar status serta jenis StateModel yang akan dibuat untuk status ini. StateModel adalah kelas yang memperluas BaseStateModel dan mengimplementasikan logika komputer status untuk menghasilkan status saat ini saat runtime. Status saat ini dari kelas ini umumnya digunakan oleh Theme Engines pada runtime untuk menentukan nilai apa yang akan diatur terhadap properti material, transformasi GameObject, dan banyak lagi.

Properti mesin tema

Di luar Status, aset Theme juga mendefinisikan daftar Mesin Tema dan properti terkait untuk mesin ini. Mesin Tema kembali mendefinisikan logika untuk mengatur nilai yang benar terhadap GameObject saat runtime.

Aset Theme dapat menentukan beberapa Mesin Tema untuk mencapai transisi status visual canggih yang menargetkan beberapa properti GameObject.

Runtime Tema

Mendefinisikan jenis kelas mesin Tema yang akan dibuat

Mengurangi

Beberapa Mesin Tema, jika mereka mendefinisikan properti mereka IsEasingSupported sebagai true, mendukung pelingan antar status. Misalnya, melakukan lerping di antara dua warna saat perubahan status terjadi. Durasi menentukan dalam detik berapa lama untuk memudahkan dari nilai awal ke nilai akhir dan Kurva Animasi menentukan tingkat perubahan selama periode waktu tersebut.

Properti shader

Beberapa Mesin Tema, jika mereka mendefinisikan propertinya AreShadersSupported sebagai true, akan memodifikasi properti shader tertentu saat runtime. Bidang Shader dan Properti menentukan properti shader ke target.

Membuat konfigurasi tema melalui kode

Secara umum, lebih mudah untuk merancang konfigurasi Tema melalui inspektur Unity tetapi ada kasus di mana Tema harus dihasilkan secara dinamis pada runtime melalui kode. Cuplikan kode di bawah ini memberikan contoh cara menyelesaikan tugas ini.

Untuk membantu mempercepat pengembangan, metode pembantu berikut berguna untuk menyederhanakan penyiapan.

Interactable.GetDefaultInteractableStates() - membuat States ScriptableObject baru dengan empat nilai status default yang digunakan dalam komponen Interactable .

ThemeDefinition.GetDefaultThemeDefinition<T>() - Setiap Mesin Tema mendefinisikan konfigurasi default dengan properti yang benar yang diperlukan untuk jenis runtime Tema tersebut. Pembantu ini membuat definisi untuk jenis Theme Engine yang diberikan.

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

Mesin tema

Mesin Tema adalah kelas yang diperluas dari InteractableThemeBase kelas . Kelas-kelas ini dibuat saat runtime dan dikonfigurasi dengan objek seperti yang ThemeDefinition diuraikan sebelumnya.

Mesin tema default

MRTK dikirim dengan sekumpulan Theme Engines default yang tercantum di bawah ini:

Mesin Tema default dapat ditemukan di bawah MRTK/SDK/Features/UX/Scripts/VisualThemes/ThemeEngines.

Mesin tema kustom

Seperti yang dinyatakan, Mesin Tema didefinisikan sebagai kelas yang meluas dari InteractableThemeBase kelas . Dengan demikian, Mesin Tema baru hanya perlu memperluas kelas ini dan menerapkan hal berikut:

Implementasi wajib

public abstract void SetValue(ThemeStateProperty property, int index, float percentage)

Untuk properti yang diberikan, yang dapat diidentifikasi oleh ThemeStateProperty.Name, tetapkan nilai statusnya saat ini pada host GameObject yang ditargetkan (yaitu mengatur warna bahan, dll). Indeks menunjukkan nilai status saat ini untuk mengakses dan persentase, float antara 0 dan 1, digunakan untuk meringankan/memperingkat antara nilai.

public abstract ThemePropertyValue GetProperty(ThemeStateProperty property)

Untuk properti yang diberikan, yang dapat diidentifikasi oleh ThemeStateProperty.Name, mengembalikan nilai saat ini yang ditetapkan pada Host GameObject yang ditargetkan (yaitu warna bahan saat ini, offset posisi lokal saat ini, dll). Ini terutama digunakan untuk penembolokan nilai awal saat mereda di antara status.

public abstract ThemeDefinition GetDefaultThemeDefinition()

Mengembalikan ThemeDefinition objek yang menentukan properti dan konfigurasi default yang diperlukan untuk tema kustom

protected abstract void SetValue(ThemeStateProperty property, ThemePropertyValue value)

Varian definisi publik SetValue() yang dilindungi, kecuali menyediakan ThemePropertyValue untuk diatur alih-alih mengarahkan untuk menggunakan konfigurasi indeks dan/atau persentase.

InteractableThemeBase.Init(GameObject host, ThemeDefinition settings)

Lakukan langkah-langkah inisialisasi apa pun di sini yang menargetkan parameter GameObject yang disediakan dan menggunakan properti dan konfigurasi yang ditentukan dalam parameter ThemeDefinition . Disarankan untuk memanggil base.Init(host, settings) di awal penimpaan.

InteractableThemeBase.IsEasingSupported

Jika Mesin Tema kustom dapat mendukung permudah antara nilai yang dikonfigurasi melalui ThemeDefinition.Easing properti .

InteractableThemeBase.AreShadersSupported

Jika Mesin Tema kustom dapat mendukung penargetan properti shader. Disarankan untuk memperluas dari InteractableShaderTheme untuk mendapatkan manfaat dari infrastruktur yang ada untuk mengatur/mendapatkan properti shader secara efisien melalui MaterialPropertyBlocks. Informasi properti shader disimpan di masing-masing ThemeStateProperty melalui ThemeStateProperty.TargetShader dan ThemeStateProperty.ShaderPropertyName.

Catatan

Jika memperluas InteractableShaderTheme, ini juga dapat berguna untuk mengambil alih InteractableShaderTheme.DefaultShaderProperty melalui yang baru.

Contoh kode: protected new const string DefaultShaderProperty = "_Color";

Selain itu, kelas berikut di bawah ini memperluas InteractableShaderTheme kelas yang lagi menggunakan MaterialPropertyBlocks untuk memodifikasi nilai properti shader. Pendekatan ini membantu performa karena MaterialPropertyBlocks tidak membuat materi instans baru saat nilai berubah. Namun, mengakses properti kelas Material yang khas tidak akan mengembalikan nilai yang diharapkan. Gunakan MaterialPropertyBlocks untuk mendapatkan dan memvalidasi nilai properti material saat ini (yaitu _Color atau _MainTex).

InteractableThemeBase.Reset

Mengarahkan tema untuk mengatur ulang properti yang dimodifikasi kembali ke nilai aslinya yang diatur pada host GameObject ketika mesin tema ini diinisialisasi.

Contoh mesin tema kustom

Kelas di bawah ini adalah contoh Mesin Tema baru kustom. Implementasi ini akan menemukan komponen MeshRenderer pada objek host yang diinisialisasi dan mengontrol visibilitasnya berdasarkan status saat ini.

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

Contoh end-to-end

Memperluas Mesin Tema kustom yang ditentukan di bagian sebelumnya, contoh kode di bawah ini menunjukkan cara mengontrol tema ini saat runtime. Secara khusus, cara mengatur status saat ini pada tema sehingga visibilitas MeshRenderer diperbarui dengan tepat.

Catatan

theme.OnUpdate(state,force) umumnya harus dipanggil dalam metode Update() untuk mendukung Theme Engines yang menggunakan pelonggaran/lerping di antara nilai.

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

Lihat juga