<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: tststs</title>
    <description>The latest articles on DEV Community by tststs (@tststs).</description>
    <link>https://dev.to/tststs</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F562875%2F3bd86b4f-6463-4864-88dd-d03bb1dfc5b0.jpeg</url>
      <title>DEV Community: tststs</title>
      <link>https://dev.to/tststs</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/tststs"/>
    <language>en</language>
    <item>
      <title>Unity MR Part 12: Improve Scene</title>
      <dc:creator>tststs</dc:creator>
      <pubDate>Thu, 11 Jan 2024 08:51:30 +0000</pubDate>
      <link>https://dev.to/taikonauten/part-12-improve-scene-135c</link>
      <guid>https://dev.to/taikonauten/part-12-improve-scene-135c</guid>
      <description>&lt;p&gt;👀 Stumbled here on accident? Start with the &lt;a href="https://dev.to/taikonauten/part-0-introduction-56fl"&gt;introduction&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;📚 The aim of this article is to enhance the visual and interactive elements of our scene. We will focus on several key improvements:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Graphics Enhancement&lt;/strong&gt;: We'll enhance the graphics by configuring the Universal Render Pipeline (URP) assets.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Remove Debug Plane Material&lt;/strong&gt;: The debug plane material, used for initial testing, will be removed for a cleaner look.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Door Shadow Effects&lt;/strong&gt;: We'll set up the scene so that the door casts shadows on planes that will now be invisible, adding depth and realism.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Create a 'Behind the Door' Scene&lt;/strong&gt;: We will develop a scene that is only revealed when the door is open, adding an element of surprise and exploration.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This article incorporates some advanced techniques that can significantly elevate your MR project. If you encounter any challenges or need further clarification, feel free to send us a message. Additionally, you can refer to the final project in our GitHub repository dedicated to this article series.&lt;/p&gt;




&lt;p&gt;ℹ️ If you find yourself facing any difficulties, remember that you can always refer to or download the code from our accompanying &lt;a href="https://github.com/taikonauten/unity-mr-article-series/tree/main/12_ImproveScene"&gt;GitHub repository&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Light Estimation
&lt;/h2&gt;

&lt;p&gt;ℹ️ Light estimation for MR devices like the Meta Quest 3 involves assessing the real-world lighting conditions and applying that information to the virtual environment to create a more immersive and realistic experience.&lt;/p&gt;

&lt;p&gt;Regrettably, as indicated by Unity in their forums, this feature is not currently supported.&lt;/p&gt;




&lt;h2&gt;
  
  
  Instantiate the door facing the user
&lt;/h2&gt;

&lt;p&gt;Currently, the door Prefab is instantiated with a consistent rotation. Let's modify the &lt;code&gt;MRArticleSeriesController&lt;/code&gt; Script so that the door faces the user upon instantiation. To do this, locate the &lt;code&gt;OnButtonPressedRightAsync&lt;/code&gt; method in the &lt;code&gt;MRArticleSeriesController&lt;/code&gt; Script and update it as follows.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;OnButtonPressedRightAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;InputAction&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CallbackContext&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"MRArticleSeriesController -&amp;gt; OnButtonPressedRightAsync()"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;doorInstance&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"MRArticleSeriesController -&amp;gt; OnButtonPressedRightAsync(): Door already instantiated"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rayInteractor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;TryGetCurrent3DRaycastHit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;out&lt;/span&gt; &lt;span class="n"&gt;RaycastHit&lt;/span&gt; &lt;span class="n"&gt;hit&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Pose&lt;/span&gt; &lt;span class="n"&gt;pose&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;point&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Quaternion&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;identity&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;Result&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ARAnchor&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;anchorManager&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;TryAddAnchorAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pose&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;TryGetResult&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;out&lt;/span&gt; &lt;span class="n"&gt;ARAnchor&lt;/span&gt; &lt;span class="n"&gt;anchor&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;anchor&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// Instantiate the door Prefab&lt;/span&gt;
            &lt;span class="n"&gt;doorInstance&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;Instantiate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;door&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;hit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;point&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Quaternion&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;identity&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="c1"&gt;// Unity recommends parenting your content to the anchor.&lt;/span&gt;
            &lt;span class="n"&gt;doorInstance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parent&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;anchor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

            &lt;span class="c1"&gt;// Make the door face the user after instantiating&lt;/span&gt;
            &lt;span class="n"&gt;doorInstance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;LookAt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Vector3&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="n"&gt;Camera&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;position&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;doorInstance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;position&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;Camera&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;position&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;z&lt;/span&gt;
            &lt;span class="p"&gt;));&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, we have added a call to &lt;code&gt;doorInstance.transform.LookAt&lt;/code&gt; in the script. After making this addition, save the file and return to the Unity Editor to apply these changes.&lt;/p&gt;

&lt;p&gt;ℹ️ For more information on the &lt;code&gt;LookAt&lt;/code&gt; function and how it works, you can refer to the Unity documentation. This resource provides detailed insights into how &lt;code&gt;LookAt&lt;/code&gt; can be used to orient objects in your scene: &lt;a href="https://docs.unity3d.com/2023.2/Documentation/ScriptReference/Transform.LookAt.html"&gt;Unity - Scripting API: Transform.LookAt&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Update AR Default Plane
&lt;/h2&gt;

&lt;p&gt;In this step, we will modify the material of the &lt;code&gt;AR Default Plane&lt;/code&gt; to make it transparent while still allowing it to receive shadows. This adjustment enables us to see the shadows cast by the door on our floor. Implementing this change enhances the realism of our MR experience, as it allows virtual objects like the door to interact more naturally with the environment.&lt;/p&gt;

&lt;p&gt;Go to &lt;strong&gt;Window → Package Manager&lt;/strong&gt; and install the package &lt;code&gt;https://github.com/Cyanilux/URP_ShaderGraphCustomLighting.git&lt;/code&gt; with &lt;code&gt;Install package from git URL&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft6orrodzo5xmj7hy3t5f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft6orrodzo5xmj7hy3t5f.png" alt="Install a package via git" width="226" height="286"&gt;&lt;/a&gt;&lt;/p&gt;
Install a package via git







&lt;p&gt;Once you have completed the installation, close the Package Manager. Now, edit the &lt;code&gt;AR Default Plane&lt;/code&gt; by double-clicking it in the &lt;code&gt;Project&lt;/code&gt; window.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F129vbnmzc158tvhk0f18.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F129vbnmzc158tvhk0f18.png" alt="Replacing the default material with the ShadowReceiver material" width="670" height="595"&gt;&lt;/a&gt;&lt;/p&gt;
Replacing the default material with the ShadowReceiver material






&lt;p&gt;Replace the default Material with &lt;code&gt;ShadowReceiver&lt;/code&gt; as seen in the above screenshot. That’s all for the &lt;code&gt;AR Default Plane&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If you can’t find &lt;code&gt;ShadowReceiver&lt;/code&gt; via search you can also drag and drop the material from &lt;strong&gt;Packages/com.cyanilux.shadergraph-customlighting/Examples/ShadowReceiver.mat.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Optimize Lightning
&lt;/h2&gt;

&lt;p&gt;In this step, we will focus on optimizing the &lt;code&gt;Directional Light&lt;/code&gt; in our scene. You have the option to adjust the values as shown in the upcoming screenshot, or alternatively, you can modify the settings according to your own preferences and the specific requirements&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvezmwqtkpoakh16t6ynb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvezmwqtkpoakh16t6ynb.png" alt="Optimizing the Directional Light" width="517" height="785"&gt;&lt;/a&gt;&lt;/p&gt;
Optimizing the Directional Light






&lt;h2&gt;
  
  
  Optimize URP
&lt;/h2&gt;

&lt;p&gt;We are currently set to the &lt;code&gt;Balanced&lt;/code&gt; quality level for the Android build. Let's switch to using the &lt;code&gt;High Fidelity&lt;/code&gt; quality setting by default, as illustrated in the upcoming screenshot. This change will enhance the visual quality of our application, offering a more detailed and immersive experience on Android devices.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7jtkn85lnmhc0r5u0297.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7jtkn85lnmhc0r5u0297.png" alt="Set High Fidelity as the default quality on Android" width="800" height="531"&gt;&lt;/a&gt;&lt;/p&gt;
Set High Fidelity as the default quality on Android






&lt;p&gt;Next, we must disable &lt;code&gt;HDR&lt;/code&gt; in our URP asset. &lt;code&gt;HDR&lt;/code&gt; is not supported in this context and will cause the application to crash if enabled. You can locate the URP asset at &lt;strong&gt;Assets/Settings/URP-HighFidelity.asset&lt;/strong&gt;. The HDR option is available as the first option under the Quality section.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2y5w1vzqyr68ohl8fbxa.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2y5w1vzqyr68ohl8fbxa.png" alt="Disabling HDR in our URP asset" width="617" height="486"&gt;&lt;/a&gt;&lt;/p&gt;
Disabling HDR in our URP asset






&lt;p&gt;The &lt;code&gt;High Fidelity&lt;/code&gt; settings utilize the &lt;code&gt;Renderer Features&lt;/code&gt; &lt;code&gt;Screen Space Ambient Occlusion&lt;/code&gt;, which significantly impacts performance. To optimize, you can either disable this feature or remove it entirely —both approaches are effective. You can find this setting in the asset located at &lt;strong&gt;Assets/Settings/URP-HighFidelity-Renderer.asset&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fydn03fgjqz5b83fpwjx5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fydn03fgjqz5b83fpwjx5.png" alt="Disabling Screen Space Ambient Occlusion from the High Fidelity-Renderer" width="581" height="723"&gt;&lt;/a&gt;&lt;/p&gt;
Disabling Screen Space Ambient Occlusion from the High Fidelity-Renderer






&lt;h2&gt;
  
  
  The behind the door
&lt;/h2&gt;

&lt;p&gt;Let's create a straightforward effect that simulates a scene visible only when the door is open and the user looks through it. This approach will add an intriguing layer of interactivity to our project, enhancing the user experience by revealing a hidden scene.&lt;/p&gt;

&lt;p&gt;Edit our door prefab by double-clicking &lt;code&gt;Assets/Prefabs/Door&lt;/code&gt; in the Project window.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Disable the &lt;code&gt;Door&lt;/code&gt; mesh through the inspector so we can look through the door.&lt;/li&gt;
&lt;li&gt;Add a plane into the root of the prefab via &lt;strong&gt;Create → 3D → Plane.&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Use the following Transform values as follows:&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;X&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Y&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Z&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Position&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;1.025&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Rotation&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;90&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Scale&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;0.1&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;0.205&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The prefab should now resemble the appearance displayed in the upcoming screenshot.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fotju9w0jjjq5p68p80zz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fotju9w0jjjq5p68p80zz.png" alt="Creating a Plane inside our door prefab" width="800" height="419"&gt;&lt;/a&gt;&lt;/p&gt;
Creating a Plane inside our door prefab






&lt;p&gt;As you will notice, this method effectively creates the illusion where the "inside" of the door is only visible from the front. To observe this effect, take a look at the door from the back in the Scene view, as illustrated in the upcoming screenshot.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F906fsgu0ibspvxi37kvo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F906fsgu0ibspvxi37kvo.png" alt="The “invisible” plane as seen from the back of the door" width="800" height="1141"&gt;&lt;/a&gt;&lt;/p&gt;
The “invisible” plane as seen from the back of the door






&lt;p&gt;Now create a new &lt;code&gt;Render Texture&lt;/code&gt; in &lt;strong&gt;Assets/Materials&lt;/strong&gt; and name it &lt;code&gt;DoorPlaneRenderTexture&lt;/code&gt;. Edit the &lt;code&gt;Render Texture&lt;/code&gt; as follows:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F613doduq8bzlc0ibdbf0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F613doduq8bzlc0ibdbf0.png" alt="DoorPlaneRenderTexture (Render Texture)" width="590" height="430"&gt;&lt;/a&gt;&lt;/p&gt;
DoorPlaneRenderTexture (Render Texture)






&lt;p&gt;As you can observe, we have set the &lt;code&gt;Size&lt;/code&gt; to 1024x2048, which correlates with our plane's approximate dimensions of a 1:2 ratio. This size selection ensures that the texture or material applied to the plane is properly scaled and aligned, reflecting the plane's physical proportions in the virtual environment.&lt;/p&gt;

&lt;p&gt;Now create a new &lt;code&gt;Material&lt;/code&gt; in &lt;strong&gt;Assets/Materials&lt;/strong&gt; and name it &lt;code&gt;DoorPlaneRenderTexture&lt;/code&gt;. Edit the &lt;code&gt;Material&lt;/code&gt; as follows:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4fu8s4iqn9kz2z996hfm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4fu8s4iqn9kz2z996hfm.png" alt="DoorPlaneRenderTexture (Material)" width="591" height="670"&gt;&lt;/a&gt;&lt;/p&gt;
DoorPlaneRenderTexture (Material)






&lt;p&gt;Now, choose the &lt;code&gt;DoorPlaneRenderTexture&lt;/code&gt; as the &lt;code&gt;Base Map&lt;/code&gt; as seen in the next screenshot.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvuyuzyxqr9tuju3sz9q9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvuyuzyxqr9tuju3sz9q9.png" alt="Choosing the DoorPlaneRenderTexture as the Base Map" width="518" height="772"&gt;&lt;/a&gt;&lt;/p&gt;
Choosing the DoorPlaneRenderTexture as the Base Map






&lt;p&gt;For the final step, assign the &lt;code&gt;DoorPlaneRenderTexture&lt;/code&gt; material to the &lt;code&gt;Mesh Renderer&lt;/code&gt; of the &lt;code&gt;Plane&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq60d93q9yhusdtoj0v83.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq60d93q9yhusdtoj0v83.png" alt="Assign the DoorPlaneRenderTexture material to the Planes Mesh Renderer" width="592" height="290"&gt;&lt;/a&gt;&lt;/p&gt;
Assign the DoorPlaneRenderTexture material to the Planes Mesh Renderer






&lt;p&gt;Now, let's create a simple scene that will be rendered onto the plane. Before we start, make sure to return to the &lt;code&gt;SampleScene&lt;/code&gt; and exit the prefab editor.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;In your hierarchy, create an empty GameObject. You can do this by selecting &lt;code&gt;Create Empty&lt;/code&gt;. Name this GameObject &lt;code&gt;DoorPlaneScene&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Ensure the position of &lt;code&gt;DoorPlaneScene&lt;/code&gt; is set to &lt;strong&gt;X: 0, Y: 0, Z: 0&lt;/strong&gt;, unless it's already positioned there.&lt;/li&gt;
&lt;li&gt;Create another empty GameObject as a child of &lt;code&gt;DoorPlaneScene&lt;/code&gt; and name it &lt;code&gt;CameraOffset&lt;/code&gt; . Set the &lt;strong&gt;Y&lt;/strong&gt; position of &lt;code&gt;CameraOffset&lt;/code&gt; to &lt;strong&gt;1.1176&lt;/strong&gt; in its Transform properties.&lt;/li&gt;
&lt;li&gt;To the &lt;code&gt;CameraOffset&lt;/code&gt; GameObject, add a Camera component. This camera will capture the scene for rendering onto the plane.&lt;/li&gt;
&lt;li&gt;Add another empty GameObject under &lt;code&gt;DoorPlaneScene&lt;/code&gt; and name it &lt;code&gt;Scene&lt;/code&gt;. This GameObject will hold the elements of your rendered scene.&lt;/li&gt;
&lt;li&gt;Inside &lt;code&gt;Scene&lt;/code&gt;, create a Cube (&lt;strong&gt;3D Object → Cube&lt;/strong&gt;). Position this Cube with its &lt;strong&gt;Z&lt;/strong&gt; coordinate set to &lt;strong&gt;5&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;These steps set up a basic scene structure, with a camera positioned to capture the scene, and a simple Cube as a visual element. The scene will be rendered from the perspective of the added camera.&lt;/p&gt;

&lt;p&gt;The result looks as follows:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz7bg2uhzrkep3g5yj7yi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz7bg2uhzrkep3g5yj7yi.png" alt="Hierarchy after adding the scene which will be rendered onto our plane" width="800" height="496"&gt;&lt;/a&gt;&lt;/p&gt;
Hierarchy after adding the scene which will be rendered onto our plane






&lt;p&gt;We aim for our new &lt;code&gt;Camera&lt;/code&gt; to render only the contents of the &lt;code&gt;Scene&lt;/code&gt; GameObject. To achieve this, navigate to &lt;strong&gt;Layers → Edit Layers...&lt;/strong&gt;, as illustrated in the upcoming screenshot. Here, add a new user layer and name it &lt;code&gt;DoorPlaneScene&lt;/code&gt;. This step is crucial for ensuring that the camera specifically captures the elements within the &lt;code&gt;Scene&lt;/code&gt;, isolating its view to this particular part of your project for targeted rendering.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn1r8jotz9edpzt3f73d5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn1r8jotz9edpzt3f73d5.png" alt="Adding a new user layer DoorPlaneScene" width="607" height="329"&gt;&lt;/a&gt;&lt;/p&gt;
Adding a new user layer DoorPlaneScene






&lt;p&gt;Now, select the &lt;code&gt;DoorPlaneScene&lt;/code&gt; GameObject in the hierarchy and change its layer to &lt;code&gt;DoorPlaneScene&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkeh68qsiq7z8j9pquu54.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkeh68qsiq7z8j9pquu54.png" alt="Selecting the DoorPlaneScene layer for our DoorPlaneScene GameObject" width="596" height="243"&gt;&lt;/a&gt;&lt;/p&gt;
Selecting the DoorPlaneScene layer for our DoorPlaneScene GameObject






&lt;p&gt;Confirm by also changing the layer for all children:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw0ekx9ed070t8ktvh56c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw0ekx9ed070t8ktvh56c.png" alt="Changing the layer for all children" width="397" height="157"&gt;&lt;/a&gt;&lt;/p&gt;
Changing the layer for all children






&lt;p&gt;Lets configure the new &lt;code&gt;Camera&lt;/code&gt;. Select our &lt;code&gt;Main Camera&lt;/code&gt; in the hierarchy and copy the component values as seen in the next screenshot.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F08fyf236xzhoih7qf7k5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F08fyf236xzhoih7qf7k5.png" alt="Copy the component values from Main Camera" width="619" height="454"&gt;&lt;/a&gt;&lt;/p&gt;
Copy the component values from Main Camera






&lt;p&gt;Now select the new &lt;code&gt;Camera&lt;/code&gt; again and paste the component values:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3uoarnm5s4wf4v1eu9t0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3uoarnm5s4wf4v1eu9t0.png" alt="Paste component values to the new Camera" width="619" height="492"&gt;&lt;/a&gt;&lt;/p&gt;
Paste component values to the new Camera






&lt;p&gt;Now, let's configure some additional settings for the new &lt;code&gt;Camera&lt;/code&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Set the tag of the Camera to &lt;code&gt;Untagged&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Under the Rendering tab, change the &lt;code&gt;Culling Mask&lt;/code&gt; to include only the &lt;code&gt;DoorPlaneScene&lt;/code&gt; and &lt;code&gt;Ignore Raycast&lt;/code&gt;. This ensures the camera renders only the objects in the &lt;code&gt;DoorPlaneScene&lt;/code&gt; layer.&lt;/li&gt;
&lt;li&gt;Assign &lt;code&gt;DoorPlaneRenderTexture&lt;/code&gt; as the &lt;code&gt;Output Texture&lt;/code&gt;. This means the camera's view will be rendered to this texture.&lt;/li&gt;
&lt;li&gt;Set the &lt;code&gt;Far&lt;/code&gt; value under &lt;code&gt;Clipping Planes&lt;/code&gt; to &lt;strong&gt;250&lt;/strong&gt;. This determines how far the camera can see.&lt;/li&gt;
&lt;li&gt;Choose &lt;code&gt;Skybox&lt;/code&gt; as the &lt;code&gt;Background Type&lt;/code&gt; under the &lt;code&gt;Environment&lt;/code&gt; tab.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;After making these changes, your camera should be set up as shown in the following screenshot.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgwqe9w0faf03gmy40jwc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgwqe9w0faf03gmy40jwc.png" alt="The configured new Camera" width="518" height="870"&gt;&lt;/a&gt;&lt;/p&gt;
The configured new Camera






&lt;p&gt;Finally, create a prefab from the &lt;code&gt;DoorPlaneScene&lt;/code&gt; and then remove it from the hierarchy, following the same process we used for the &lt;code&gt;Reticle&lt;/code&gt; in the &lt;code&gt;Raycasts&lt;/code&gt; article.&lt;/p&gt;

&lt;p&gt;Our plan is to incorporate the &lt;code&gt;DoorPlaneScene&lt;/code&gt; into our Door prefab. This way, &lt;code&gt;DoorPlaneScene&lt;/code&gt; will only be rendered when necessary. To do this, edit the &lt;code&gt;Door&lt;/code&gt; prefab and drag and drop the &lt;code&gt;DoorPlaneScene&lt;/code&gt; into the root of the prefab. This action is depicted in the upcoming screenshot and ensures that the scene is efficiently integrated with the Door prefab.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvi4o4g0jwurps893c3eo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvi4o4g0jwurps893c3eo.png" alt="Adding the DoorPlaneScene to our Door prefab" width="800" height="523"&gt;&lt;/a&gt;&lt;/p&gt;
Adding the DoorPlaneScene to our Door prefab






&lt;p&gt;Save the prefab and return to the &lt;code&gt;SampleScene&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Select the &lt;code&gt;Main Camera&lt;/code&gt; again and set the &lt;code&gt;Culling Mask&lt;/code&gt; from &lt;code&gt;Everthing&lt;/code&gt; to: &lt;code&gt;Default&lt;/code&gt;, &lt;code&gt;TransparentFX&lt;/code&gt;, &lt;code&gt;Ignore Raycast&lt;/code&gt; &lt;code&gt;Water&lt;/code&gt; and &lt;code&gt;UI&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9o8lci5k2ffccluwggba.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9o8lci5k2ffccluwggba.png" alt="Selecting the Culling Mask for the Main Camera" width="595" height="786"&gt;&lt;/a&gt;&lt;/p&gt;
Selecting the Culling Mask for the Main Camera






&lt;p&gt;Drag and drop the prefab &lt;code&gt;Door&lt;/code&gt; into your scene to investigate the changes we made. The plane now should look as follows:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2457i59dupmr8ack8jrb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2457i59dupmr8ack8jrb.png" alt="Plain rendering the scene we just created" width="800" height="508"&gt;&lt;/a&gt;&lt;/p&gt;
Plain rendering the scene we just created






&lt;p&gt;As you can observe, we now have our new scene projected onto the plane inside the door.&lt;/p&gt;

&lt;p&gt;Next, re-enable the &lt;code&gt;Door&lt;/code&gt; mesh, which we had disabled in a previous step. However, there's still an issue to address: the scene is static and doesn't adapt to the user's movements. Let's resolve this.&lt;/p&gt;

&lt;p&gt;Create a new script and name it &lt;code&gt;MimicCamera&lt;/code&gt;, then attach it to our newly added &lt;code&gt;Camera&lt;/code&gt;. The script will be structured as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Collections&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Collections.Generic&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;UnityEngine&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;Taikonauten.Unity.ArticleSeries&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MimicCamera&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;MonoBehaviour&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;float&lt;/span&gt; &lt;span class="n"&gt;offsetDistance&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;30.0f&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;SerializeField&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="n"&gt;GameObject&lt;/span&gt; &lt;span class="n"&gt;sceneCamera&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="n"&gt;Camera&lt;/span&gt; &lt;span class="n"&gt;mainCamera&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;Transform&lt;/span&gt; &lt;span class="n"&gt;DoorTransform&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Awake&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;mainCamera&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Camera&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Update&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DoorTransform&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;

            &lt;span class="c1"&gt;// Calculate the direction and position offset from the door to the main camera&lt;/span&gt;
            &lt;span class="n"&gt;Vector3&lt;/span&gt; &lt;span class="n"&gt;directionToCamera&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mainCamera&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;position&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="n"&gt;DoorTransform&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;position&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="n"&gt;Vector3&lt;/span&gt; &lt;span class="n"&gt;sceneCameraPosition&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;DoorTransform&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;position&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="n"&gt;directionToCamera&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;normalized&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="n"&gt;offsetDistance&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

            &lt;span class="n"&gt;sceneCameraPosition&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sceneCameraPosition&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="m"&gt;2f&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="m"&gt;2f&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;sceneCameraPosition&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

            &lt;span class="c1"&gt;// Update the position and rotation of the scene camera&lt;/span&gt;
            &lt;span class="n"&gt;sceneCamera&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;position&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sceneCameraPosition&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="n"&gt;sceneCamera&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rotation&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Quaternion&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;LookRotation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DoorTransform&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;position&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="n"&gt;sceneCameraPosition&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Select the required values for the &lt;code&gt;MimicCamera&lt;/code&gt; script as seen in the following screenshot:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxvci914o8ww4bv46ujn2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxvci914o8ww4bv46ujn2.png" alt="Select the required values for the MimicCamera script" width="517" height="308"&gt;&lt;/a&gt;&lt;/p&gt;
Select the required values for the MimicCamera script






&lt;p&gt;We still need to assign the &lt;code&gt;DoorTransform&lt;/code&gt; when the &lt;code&gt;Door&lt;/code&gt; is instantiated. To do this, edit the &lt;code&gt;MRArticleSeriesController&lt;/code&gt; script and add a private field for the &lt;code&gt;MimicCamera&lt;/code&gt; script. This modification is shown on line 1 in the following code snippet.&lt;/p&gt;

&lt;p&gt;Afterward, assign the &lt;code&gt;DoorTransform&lt;/code&gt; following our &lt;code&gt;LookAt&lt;/code&gt; method call. If you need guidance, you can also refer to the code in the &lt;code&gt;12_ImproveScene&lt;/code&gt; project for a clearer understanding &lt;a href="https://github.com/taikonauten/unity-mr-article-series/tree/main/12_ImproveScene"&gt;12_ImproveScene&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="p"&gt;...&lt;/span&gt;

&lt;span class="c1"&gt;// Make the door face the user after instantiating&lt;/span&gt;
&lt;span class="n"&gt;doorInstance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;LookAt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Vector3&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="n"&gt;Camera&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;position&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="n"&gt;doorInstance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;position&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;Camera&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;position&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;z&lt;/span&gt;
&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="n"&gt;doorInstance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetComponentInChildren&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;MimicCamera&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;().&lt;/span&gt;&lt;span class="n"&gt;DoorTransform&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;doorInstance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="p"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Adding a complex scene behind the door
&lt;/h2&gt;

&lt;p&gt;For the final step, we'll upgrade from the simple cube to a more complex scene. In our example, we utilized the &lt;code&gt;Free Low Poly Nature Forest&lt;/code&gt; asset, which you can find here: &lt;a href="https://assetstore.unity.com/packages/3d/environments/landscapes/free-low-poly-nature-forest-205742"&gt;Free Low Poly Nature Forest&lt;/a&gt;. Add the asset to your project.&lt;/p&gt;

&lt;p&gt;Find the '&lt;code&gt;Demo_01&lt;/code&gt; scene from the package within the &lt;strong&gt;Assets/Pure Poly/Free Low Poly Nature Pack/Scenes&lt;/strong&gt; directory. Then, drag and drop it into your hierarchy, as demonstrated in the upcoming screenshot.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcbu9wpnfyxzmv2ojj0fx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcbu9wpnfyxzmv2ojj0fx.png" alt="Drop the Demo_01 scene into our hierarchy" width="239" height="272"&gt;&lt;/a&gt;&lt;/p&gt;
Drop the Demo_01 scene into our hierarchy






&lt;p&gt;If the &lt;code&gt;Demo_01&lt;/code&gt; scene looks as follows, we need to replace the shader that is used for the material.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fagu2zwk5vsf11dugb758.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fagu2zwk5vsf11dugb758.png" alt="Demo_01 with an invalid material" width="800" height="418"&gt;&lt;/a&gt;&lt;/p&gt;
Demo_01 with an invalid material






&lt;p&gt;Open the material located here: &lt;strong&gt;Assets/Pure Poly/Free Low Poly Nature Pack/Materials/PP_Standard_Material&lt;/strong&gt;. Edit the material as follows:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe63fdawuv2jcwuqlqqic.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe63fdawuv2jcwuqlqqic.png" alt="Fixing the invalid material" width="457" height="1376"&gt;&lt;/a&gt;&lt;/p&gt;
Fixing the invalid material






&lt;ol&gt;
&lt;li&gt;Set the shader to &lt;code&gt;Universal Render Pipeline/Lit&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;As the &lt;code&gt;Base Map&lt;/code&gt; choose the file &lt;code&gt;PP_Color_Palette&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Set &lt;code&gt;Smoothness&lt;/code&gt; to &lt;strong&gt;0&lt;/strong&gt; for the &lt;code&gt;Metallic Map&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Copy the &lt;code&gt;Free_Forest&lt;/code&gt; GameObject, then edit our &lt;code&gt;DoorPlaneScene&lt;/code&gt; prefab. Within the prefab, replace the cube with the &lt;code&gt;Free_Forest&lt;/code&gt; GameObject, as illustrated in the next screenshot:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fom4ou6sjezi2h2uqjh62.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fom4ou6sjezi2h2uqjh62.png" alt="Replacing the cube with the Free_Forest GameObject in our DoorPlaneScene prefab" width="800" height="605"&gt;&lt;/a&gt;&lt;/p&gt;
Replacing the cube with the Free_Forest GameObject in our DoorPlaneScene prefab






&lt;p&gt;Set the &lt;code&gt;Transform&lt;/code&gt; of the &lt;code&gt;Free_Forest&lt;/code&gt; GameObject as follows:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;X&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Y&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Z&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Position&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;-3.7&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Rotation&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;-135&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Scale&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F73tbd1frhf4xotcy2kar.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F73tbd1frhf4xotcy2kar.png" alt="Set the Transform of the Free_Forest GameObject" width="461" height="212"&gt;&lt;/a&gt;&lt;/p&gt;
Set the Transform of the Free_Forest GameObject






&lt;p&gt;Also ensure, that the layer of &lt;code&gt;Free_Forest&lt;/code&gt; is set to &lt;code&gt;DoorPlaneScene&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0u6uu7p88y1itluexivc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0u6uu7p88y1itluexivc.png" alt="Setting the Free_Forest layer to DoorPlaneScene" width="462" height="273"&gt;&lt;/a&gt;&lt;/p&gt;
Setting the Free_Forest layer to DoorPlaneScene






&lt;p&gt;Save the prefab and return to your scene. Now remove the &lt;code&gt;Demo_01&lt;/code&gt; scene from your hierarchy:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvydp885fiqm87fsxyl06.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvydp885fiqm87fsxyl06.png" alt="Remove the Demo_01 scene from your hierarchy" width="404" height="448"&gt;&lt;/a&gt;&lt;/p&gt;
Remove the Demo_01 scene from your hierarchy






&lt;p&gt;This enhancement significantly elevates the visual appeal and immersion of the scene, demonstrating the versatility and potential of using varied assets in your MR environment.&lt;/p&gt;

&lt;p&gt;ℹ️ If you find yourself facing any difficulties, remember that you can always refer to or download the code from our accompanying GitHub repository. &lt;a href="https://github.com/taikonauten/unity-mr-article-series/tree/main/12_ImproveScene"&gt;12_ImproveScene&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Testing the app
&lt;/h2&gt;

&lt;p&gt;We are now ready to test the final version of our app. Here's what you need to do:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Choose &lt;code&gt;Build and Run&lt;/code&gt; in Unity.&lt;/li&gt;
&lt;li&gt;Once the app is running, press the trigger on the left controller.&lt;/li&gt;
&lt;li&gt;You should see a label displaying the message "...Listening...".&lt;/li&gt;
&lt;li&gt;Say the phrase “open the door”.&lt;/li&gt;
&lt;li&gt;After a short delay, the animation of the door opening should begin.&lt;/li&gt;
&lt;li&gt;Feel free to move around and explore what lies behind the door.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This test will allow you to experience the full functionality of the app, from voice command recognition to the dynamic opening of the door and the revealing of the scene behind it. Enjoy the immersive experience of exploring the new environment you've created!&lt;/p&gt;

&lt;p&gt;👏&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://player.vimeo.com/video/901578624" width="710" height="399"&gt;
&lt;/iframe&gt;
&lt;/p&gt;
Video of the app where the door opens when the phrase “open the door“ is recognized






</description>
      <category>unity3d</category>
      <category>mixedreality</category>
      <category>tutorial</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Unity MR Part 11: Animation</title>
      <dc:creator>tststs</dc:creator>
      <pubDate>Thu, 11 Jan 2024 08:51:23 +0000</pubDate>
      <link>https://dev.to/taikonauten/part-11-animation-5gok</link>
      <guid>https://dev.to/taikonauten/part-11-animation-5gok</guid>
      <description>&lt;p&gt;👀 Stumbled here on accident? Start with the &lt;a href="https://dev.to/taikonauten/part-0-introduction-56fl"&gt;introduction&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;📚 The objective of this article is to animate the door in response to the voice command “open the door”. To achieve this, we will develop an animation specifically for the door and make necessary updates to the &lt;code&gt;Player&lt;/code&gt; and &lt;code&gt;OpenDoorConduit&lt;/code&gt; scripts. This integration of voice command functionality with animation will enhance the interactivity and realism of our application.&lt;/p&gt;




&lt;p&gt;ℹ️ If you find yourself facing any difficulties, remember that you can always refer to or download the code from our accompanying &lt;a href="https://github.com/taikonauten/unity-mr-article-series/tree/main/11_Animation" rel="noopener noreferrer"&gt;GitHub repository&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;Lets start with the animation. Edit our &lt;code&gt;Door&lt;/code&gt; Prefab by double-clicking it within the &lt;code&gt;Project&lt;/code&gt; window. Select the &lt;code&gt;Door&lt;/code&gt; mesh as seen in the next screenshot.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnveulq3156oysv07v015.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnveulq3156oysv07v015.png" alt="Selecting the Door mesh on our door Prefab"&gt;&lt;/a&gt;&lt;/p&gt;
Selecting the Door mesh on our door Prefab






&lt;p&gt;Now add the component &lt;code&gt;Animator&lt;/code&gt; via &lt;code&gt;Add Component&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcq4ciqsbm4jf80mvay0e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcq4ciqsbm4jf80mvay0e.png" alt="Adding the Animator component to the Door mesh"&gt;&lt;/a&gt;&lt;/p&gt;
Adding the Animator component to the Door mesh






&lt;p&gt;With the &lt;code&gt;Door&lt;/code&gt; mesh still selected, navigate to &lt;strong&gt;Window → Animation → Animation&lt;/strong&gt; to open the animation window in Unity. Once the animation window is open, click on the &lt;code&gt;Create&lt;/code&gt; button. You will then be prompted to choose a location for saving the Animation Clip. Save it in a new folder &lt;strong&gt;Assets/Animations&lt;/strong&gt; and name it &lt;code&gt;DoorAnimation&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6aldlbofledgbskbjq51.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6aldlbofledgbskbjq51.png" alt="The animation window after clicking Create"&gt;&lt;/a&gt;&lt;/p&gt;
The animation window after clicking Create






&lt;p&gt;The next step involves adding a property to animate. As we are crafting an “opening the door” animation, we need to animate the Transform rotation. To do this, click on &lt;code&gt;Add Property&lt;/code&gt;, and then select &lt;strong&gt;Transform → Rotation&lt;/strong&gt;. This action allows us to specifically target and animate the door's rotation, creating a realistic opening effect in our animation sequence.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F63fbn8yrmto73qhzd8kw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F63fbn8yrmto73qhzd8kw.png" alt="Adding the rotation property to the animation"&gt;&lt;/a&gt;&lt;/p&gt;
Adding the rotation property to the animation






&lt;p&gt;First move the &lt;code&gt;Timeline&lt;/code&gt; to &lt;code&gt;60&lt;/code&gt;. You can either drag and drop the indicator or enter &lt;code&gt;60&lt;/code&gt; on the left side of the &lt;code&gt;Timeline&lt;/code&gt;. Then, enter &lt;code&gt;-120&lt;/code&gt; for the &lt;code&gt;Rotation.y&lt;/code&gt; value.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feaum4f39pvwiv9nlkjxz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feaum4f39pvwiv9nlkjxz.png" alt="The animation window with the configured Rotation.y property"&gt;&lt;/a&gt;&lt;/p&gt;
The animation window with the configured Rotation.y property






&lt;p&gt;In your &lt;code&gt;Scene&lt;/code&gt; window the door should now look as follows:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftzcwy9vmemrwtp4m4ccl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftzcwy9vmemrwtp4m4ccl.png" alt="Door state at the end of the animation"&gt;&lt;/a&gt;&lt;/p&gt;
Door state at the end of the animation






&lt;p&gt;When creating an animation in Unity, the default setting typically causes the animation to loop continuously. However, since our objective is to trigger the door animation just once upon recognizing the correct voice command, we need to adjust the looping behavior in the &lt;code&gt;Door&lt;/code&gt; &lt;code&gt;Animation Controller&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;To make this change, navigate to &lt;strong&gt;Assets/Animations&lt;/strong&gt; in the Unity Editor and double-click on the &lt;code&gt;Door&lt;/code&gt; &lt;code&gt;Animation&lt;/code&gt; controller. This action will open the Animator window with the Door.controller loaded. In the Animator window, we can modify the settings to ensure that the door animation plays only once instead of looping endlessly.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fii51uugfiacdycf58ug9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fii51uugfiacdycf58ug9.png" alt="Door controller in our Animator"&gt;&lt;/a&gt;&lt;/p&gt;
Door controller in our Animator






&lt;p&gt;Right-click on an empty space within the &lt;code&gt;Animator&lt;/code&gt; window and select &lt;strong&gt;Create State -&amp;gt; Empty&lt;/strong&gt;, as shown in the upcoming screenshot. This step will add a new, empty state to the animation controller.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fagkweha4crqwst4bb2np.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fagkweha4crqwst4bb2np.png" alt="Creating an empty state in the Animator"&gt;&lt;/a&gt;&lt;/p&gt;
Creating an empty state in the Animator






&lt;p&gt;Right-click on the newly created state, named &lt;code&gt;New State&lt;/code&gt;, and select &lt;code&gt;Set as Layer Default State&lt;/code&gt;. This action will designate the &lt;code&gt;New State&lt;/code&gt; as the default state for that particular layer in the animation controller, ensuring that this is the starting state when the animation sequence begins.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnw8i0z8aih4e7i09lghz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnw8i0z8aih4e7i09lghz.png" alt="Setting New State as the default layer"&gt;&lt;/a&gt;&lt;/p&gt;
Setting New State as the default layer






&lt;p&gt;The result should be as follows: Since the state is empty and no properties have been added to it, this results in the absence of any animation when the GameObject loads. This setup ensures that the door remains static initially, allowing for the animation to be triggered specifically by an event, such as a voice command, rather than starting automatically upon loading.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh9yneco4znmertvhs865.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh9yneco4znmertvhs865.png" alt="New State is the default layer"&gt;&lt;/a&gt;&lt;/p&gt;
New State is the default layer






&lt;p&gt;Now, select the &lt;code&gt;DoorAnimation&lt;/code&gt; animation clip in your &lt;code&gt;Project&lt;/code&gt;window. Then, in the inspector, uncheck &lt;code&gt;Loop Time&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F06kcdu3jh41v8kqujtzm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F06kcdu3jh41v8kqujtzm.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We are now good to go to trigger the animation in our &lt;code&gt;MRArticleSeriesController&lt;/code&gt; script.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;

&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Collections&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Collections.Generic&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Meta.WitAi&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Meta.WitAi.Requests&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;UnityEngine&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;UnityEngine.InputSystem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;UnityEngine.XR.ARFoundation&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;UnityEngine.XR.ARSubsystems&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;UnityEngine.XR.Interaction.Toolkit&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;Taikonauten.Unity.ArticleSeries&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MRArticleSeriesController&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;MonoBehaviour&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;SerializeField&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="n"&gt;ARAnchorManager&lt;/span&gt; &lt;span class="n"&gt;anchorManager&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;SerializeField&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="n"&gt;GameObject&lt;/span&gt; &lt;span class="n"&gt;door&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;SerializeField&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="n"&gt;GameObject&lt;/span&gt; &lt;span class="n"&gt;uI&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;SerializeField&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="n"&gt;InputActionReference&lt;/span&gt; &lt;span class="n"&gt;buttonActionLeft&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;SerializeField&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="n"&gt;InputActionReference&lt;/span&gt; &lt;span class="n"&gt;buttonActionRight&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;SerializeField&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="n"&gt;VoiceService&lt;/span&gt; &lt;span class="n"&gt;voiceService&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;SerializeField&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="n"&gt;XRRayInteractor&lt;/span&gt; &lt;span class="n"&gt;rayInteractor&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="n"&gt;VoiceServiceRequest&lt;/span&gt; &lt;span class="n"&gt;voiceServiceRequest&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="n"&gt;VoiceServiceRequestEvents&lt;/span&gt; &lt;span class="n"&gt;voiceServiceRequestEvents&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="n"&gt;GameObject&lt;/span&gt; &lt;span class="n"&gt;doorInstance&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;OnEnable&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;Debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"MRArticleSeriesController -&amp;gt; OnEnable()"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="n"&gt;buttonActionRight&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;performed&lt;/span&gt; &lt;span class="p"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;OnButtonPressedRightAsync&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="n"&gt;buttonActionLeft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;performed&lt;/span&gt; &lt;span class="p"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;OnButtonPressedLeft&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;OnDisable&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;Debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"MRArticleSeriesController -&amp;gt; OnDisable()"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;buttonActionRight&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;performed&lt;/span&gt; &lt;span class="p"&gt;-=&lt;/span&gt; &lt;span class="n"&gt;OnButtonPressedRightAsync&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="n"&gt;buttonActionLeft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;performed&lt;/span&gt; &lt;span class="p"&gt;-=&lt;/span&gt; &lt;span class="n"&gt;OnButtonPressedLeft&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;ActivateVoiceService&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;Debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"MRArticleSeriesController -&amp;gt; ActivateVoiceService()"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;voiceServiceRequestEvents&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;voiceServiceRequestEvents&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;VoiceServiceRequestEvents&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

                &lt;span class="n"&gt;voiceServiceRequestEvents&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OnInit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;OnInit&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="n"&gt;voiceServiceRequestEvents&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OnComplete&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;OnComplete&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;

            &lt;span class="n"&gt;voiceServiceRequest&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;voiceService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Activate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;voiceServiceRequestEvents&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;DeactivateVoiceService&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;Debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"MRArticleSeriesController -&amp;gt; DeactivateVoiceService()"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;voiceServiceRequest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;DeactivateAudio&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;OnInit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;VoiceServiceRequest&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;uI&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SetActive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;OnComplete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;VoiceServiceRequest&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;uI&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SetActive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="nf"&gt;DeactivateVoiceService&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;OnButtonPressedRightAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;InputAction&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CallbackContext&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;Debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"MRArticleSeriesController -&amp;gt; OnButtonPressedRightAsync()"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;doorInstance&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;Debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"MRArticleSeriesController -&amp;gt; OnButtonPressedRightAsync(): Door already instantiated"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

                &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;

            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rayInteractor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;TryGetCurrent3DRaycastHit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;out&lt;/span&gt; &lt;span class="n"&gt;RaycastHit&lt;/span&gt; &lt;span class="n"&gt;hit&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;Pose&lt;/span&gt; &lt;span class="n"&gt;pose&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;point&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Quaternion&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;identity&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="n"&gt;Result&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ARAnchor&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;anchorManager&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;TryAddAnchorAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pose&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

                &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;TryGetResult&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;out&lt;/span&gt; &lt;span class="n"&gt;ARAnchor&lt;/span&gt; &lt;span class="n"&gt;anchor&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;anchor&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="c1"&gt;// Instantiate the door Prefab&lt;/span&gt;
                    &lt;span class="n"&gt;doorInstance&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;Instantiate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;door&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;hit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;point&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Quaternion&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;identity&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                    &lt;span class="c1"&gt;// Unity recommends parenting your content to the anchor.&lt;/span&gt;
                    &lt;span class="n"&gt;doorInstance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parent&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;anchor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;OnButtonPressedLeft&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;InputAction&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CallbackContext&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;Debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"MRArticleSeriesController -&amp;gt; OnButtonPressedLeft()"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="nf"&gt;ActivateVoiceService&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;OpenDoor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;Debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"MRArticleSeriesController -&amp;gt; OpenDoor()"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;doorInstance&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;Debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"MRArticleSeriesController -&amp;gt; OpenDoor(): no door instantiated yet."&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

                &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;

            &lt;span class="n"&gt;Animator&lt;/span&gt; &lt;span class="n"&gt;animator&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;doorInstance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetComponentInChildren&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Animator&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
            &lt;span class="n"&gt;animator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Play&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"DoorAnimation"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;



&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Let's go over the modifications made to the &lt;code&gt;MRArticleSeriesController&lt;/code&gt; script:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Added &lt;code&gt;private GameObject doorInstance;&lt;/code&gt; This variable holds the reference to the instantiated door in the scene.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;OnButtonPressedRightAsync&lt;/code&gt;: In this method, we now check if a door has already been instantiated in the scene. If a door is present, the method returns early to prevent another door from being instantiated.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;OpenDoor&lt;/code&gt;: This public method will be called from the &lt;code&gt;OpenDoorConduit&lt;/code&gt;. It triggers the door's animation using &lt;code&gt;animator.Play&lt;/code&gt;, initiating the opening sequence of the door.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;These changes enhance the functionality of the Player script, ensuring proper management and control of the door animation in response to user interactions and voice commands.&lt;/p&gt;

&lt;p&gt;Now, edit the &lt;code&gt;OpenDoorConduit&lt;/code&gt; script.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;

&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Collections&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Collections.Generic&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Meta.WitAi&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;UnityEngine&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;Taikonauten.Unity.ArticleSeries&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;OpenDoorConduit&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;MonoBehaviour&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;SerializeField&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="n"&gt;MRArticleSeriesController&lt;/span&gt; &lt;span class="n"&gt;mRArticleSeriesController&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;OPEN_DOOR_INTENT&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"open_door"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;MatchIntent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;OPEN_DOOR_INTENT&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;OpenDoor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;values&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;Debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"OpenDoorConduit -&amp;gt; OpenDoor()"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;action&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;values&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
            &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;entity&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;values&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(!&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;IsNullOrEmpty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;IsNullOrEmpty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;action&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"open"&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;entity&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"door"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="n"&gt;mRArticleSeriesController&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;OpenDoor&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;



&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Let's go over the modifications made to the &lt;code&gt;OpenDoorConduit&lt;/code&gt; script:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;[SerializeField] private MRArticleSeriesController mRArticleSeriesController;&lt;/code&gt; This line declares a private variable and marks it with &lt;code&gt;[SerializeField]&lt;/code&gt; so it can be assigned via the Unity Editor. This variable holds the reference to our Player component, allowing the script to interact with the Player component's public methods and properties.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;OpenDoor&lt;/code&gt;: In this part of the script, we invoke the &lt;code&gt;OpenDoor&lt;/code&gt; public method of the Player script which starts the door animation.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;These modifications are essential for enabling communication and interaction between different components and scripts in our Unity project, particularly for handling the door-opening functionality.&lt;/p&gt;

&lt;p&gt;Make sure to select the &lt;code&gt;MRArticleSeriesController&lt;/code&gt; component in the inspector:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw37jyk5lyxj7eggawzpm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw37jyk5lyxj7eggawzpm.png" alt="Selecting the MRArticleSeriesController for the Open Door Conduit script"&gt;&lt;/a&gt;&lt;/p&gt;
Selecting the MRArticleSeriesController for the Open Door Conduit script






&lt;h2&gt;
  
  
  Testing the app
&lt;/h2&gt;

&lt;p&gt;We are now prepared to test the app. Select &lt;code&gt;Build and Run&lt;/code&gt;.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Press the trigger on the left controller.&lt;/li&gt;
&lt;li&gt;The label indicated "...Listening...".&lt;/li&gt;
&lt;li&gt;Speak the word phrase “open the door”.&lt;/li&gt;
&lt;li&gt;After a brief delay the door animation should now be playing.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;iframe src="https://player.vimeo.com/video/901565203" width="710" height="399"&gt;
&lt;/iframe&gt;
&lt;/p&gt;
Video of the app where the door opens when the phrase “open the door“ is recognized






&lt;h2&gt;
  
  
  Next article
&lt;/h2&gt;

&lt;p&gt;In the next article, we will focus on enhancing the visual appeal of our scene. This will include implementing graphic improvements, adding a scene to be displayed behind the door, and disabling the plane material, which was previously used solely for debugging purposes. These refinements are aimed at elevating the aesthetic quality and immersive experience of our application, making it more engaging and visually appealing to users.&lt;/p&gt;

</description>
      <category>unity3d</category>
      <category>mixedreality</category>
      <category>tutorial</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Unity MR Part 10: Voice SDK</title>
      <dc:creator>tststs</dc:creator>
      <pubDate>Thu, 11 Jan 2024 08:51:19 +0000</pubDate>
      <link>https://dev.to/taikonauten/part-10-voice-sdk-4nna</link>
      <guid>https://dev.to/taikonauten/part-10-voice-sdk-4nna</guid>
      <description>&lt;p&gt;👀 Stumbled here on accident? Start with the &lt;a href="https://dev.to/taikonauten/part-0-introduction-56fl"&gt;introduction&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;📚 The aim of this article is to incorporate the Meta - Voice SDK into our application, enabling it to respond to specific word sequences. This functionality will allow us to interact with the door we rendered in the previous article, providing a more immersive and interactive experience in our application.&lt;/p&gt;




&lt;p&gt;ℹ️ If you find yourself facing any difficulties, remember that you can always refer to or download the code from our accompanying &lt;a href="https://github.com/taikonauten/unity-mr-article-series/tree/main/10_VoiceSDK"&gt;GitHub repository&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;Login to the Unity Store &lt;a href="https://assetstore.unity.com/"&gt;Unity Asset Store - The Best Assets for Game Making&lt;/a&gt; and add &lt;a href="https://assetstore.unity.com/packages/tools/integration/meta-voice-sdk-immersive-voice-commands-264555"&gt;Meta - Voice SDK - Immersive Voice Commands&lt;/a&gt; to your library.&lt;/p&gt;

&lt;p&gt;Return to the Unity Editor and install the &lt;code&gt;Meta - Voice SDK&lt;/code&gt; through the &lt;code&gt;Package Manager&lt;/code&gt;. You can directly access &lt;code&gt;My Assets&lt;/code&gt; via &lt;strong&gt;Window -&amp;gt; My Assets&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fms8qcm0jt15ti2chmsmd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fms8qcm0jt15ti2chmsmd.png" alt="Adding the Meta - Voice SDK with the Package Manager" width="800" height="484"&gt;&lt;/a&gt;&lt;/p&gt;
Adding the Meta - Voice SDK with the Package Manager






&lt;p&gt;Before we begin utilizing the &lt;code&gt;Meta - Voice SDK&lt;/code&gt;, it's necessary to create an account on &lt;a href="https://Wit.ai"&gt;Wit.ai&lt;/a&gt; . You can conveniently use your existing Meta developer account for this purpose by clicking on &lt;code&gt;Continue with Meta&lt;/code&gt; on the &lt;a href="https://Wit.ai"&gt;Wit.ai&lt;/a&gt; landing page.&lt;/p&gt;

&lt;p&gt;ℹ️ &lt;a href="https://Wit.ai"&gt;Wit.ai&lt;/a&gt; (often referred to as &lt;a href="https://Wit.io"&gt;Won in Translation, by David Jacobs&lt;/a&gt; from its URL) is a natural language processing (NLP) service created by Facebook. It enables developers to build applications that can understand human language by providing a powerful and easy-to-use API.&lt;/p&gt;

&lt;p&gt;Once you've set up your &lt;a href="https://Wit.ai"&gt;Wit.ai&lt;/a&gt; account, you can create a new application at &lt;a href="https://wit.ai/apps"&gt;Wit.ai&lt;/a&gt;. If you're unsure about what to name the application, simply go with &lt;code&gt;unity_example&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;After your app is created, click on &lt;code&gt;unity_example&lt;/code&gt;. Then, as illustrated in the upcoming screenshot, add an &lt;code&gt;Utterance&lt;/code&gt; for the &lt;code&gt;Intent&lt;/code&gt; &lt;code&gt;open_door&lt;/code&gt;. This step is crucial for training your application to recognize and respond to specific user inputs related to the action of opening a door.&lt;/p&gt;

&lt;p&gt;ℹ️ An &lt;code&gt;Utterance&lt;/code&gt; in the context of natural language processing (NLP), linguistics, and conversational AI, refers to a sequence of words or sounds made by a speaker. It's essentially a unit of speech. In practical terms, an utterance can be as short as a single word (like a command or an exclamation) or as long as a complete sentence or multiple sentences.&lt;/p&gt;

&lt;p&gt;ℹ️ In &lt;a href="https://Wit.ai"&gt;Wit.ai&lt;/a&gt;, an &lt;code&gt;Intent&lt;/code&gt; represents the purpose or goal behind a user's input, typically a spoken or written phrase. It's a fundamental concept in natural language understanding (NLU) and is used to categorize user utterances into specific actions that the application should perform.&lt;/p&gt;

&lt;p&gt;1. Fill in the phrase “open the door” as the &lt;code&gt;Utterance&lt;/code&gt; and select the &lt;code&gt;open_door&lt;/code&gt; intent in the &lt;code&gt;Intent&lt;/code&gt; dropdown.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9fitw5ds9usw9vjnrtcl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9fitw5ds9usw9vjnrtcl.png" alt="Adding the Utterance for the Intent open_door" width="800" height="520"&gt;&lt;/a&gt;&lt;/p&gt;
Adding the Utterance for the Intent open_door






&lt;p&gt;2. In the &lt;code&gt;Utterance&lt;/code&gt; input field select the word “open”. This will open the entity form. Fill in &lt;code&gt;action&lt;/code&gt; as the entity and click on &lt;code&gt;+ Create Entity&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F36nn324uw4orbppj8j3k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F36nn324uw4orbppj8j3k.png" alt="Creating the action entity" width="800" height="544"&gt;&lt;/a&gt;&lt;/p&gt;
Creating the action entity






&lt;p&gt;3. In the &lt;code&gt;Utterance&lt;/code&gt; input field select the word “door”. This will open the entity form. Fill in &lt;code&gt;entity&lt;/code&gt; as the entity and click on &lt;code&gt;+ Create Entity&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3a6erm37bj1luekcwbn4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3a6erm37bj1luekcwbn4.png" alt="Creating the entity entity" width="800" height="381"&gt;&lt;/a&gt;&lt;/p&gt;
Creating the entity entity






&lt;p&gt;4. After creating the entities, they will now be highlighted as seen in the next screenshot.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fatjkco1od4s3k4ksrvob.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fatjkco1od4s3k4ksrvob.png" alt="The Utterance view after creating our entities" width="800" height="408"&gt;&lt;/a&gt;&lt;/p&gt;
The Utterance view after creating our entities






&lt;p&gt;Now, click on &lt;code&gt;Train and Validate&lt;/code&gt;. Once the training process is complete (indicator on the top left next to the app name), return to the Unity Editor and navigate to &lt;strong&gt;Oculus → Voice SDK → Get Started&lt;/strong&gt;. In the first dialog enter the Wit &lt;code&gt;Server Access Token&lt;/code&gt;. The access token can be found on the &lt;a href="https://Wit.ai"&gt;Wit.ai&lt;/a&gt; website under &lt;strong&gt;Management → Settings&lt;/strong&gt; within your &lt;code&gt;unity_example&lt;/code&gt; app.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0vvu7n5j4ufr5thzp2wp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0vvu7n5j4ufr5thzp2wp.png" alt="Enter the Server Access Token" width="452" height="552"&gt;&lt;/a&gt;&lt;/p&gt;
Enter the Server Access Token






&lt;p&gt;You will be prompted to choose a location for saving your Wit asset. Save it in your &lt;strong&gt;Assets/Settings&lt;/strong&gt; folder and name it &lt;code&gt;wit&lt;/code&gt;. Once you have saved the asset, the following screen will appear.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff7zrajuav80vc8xzl6pw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff7zrajuav80vc8xzl6pw.png" alt="The Wit Configurations after entering the server token" width="800" height="540"&gt;&lt;/a&gt;&lt;/p&gt;
The Wit Configurations after entering the server token






&lt;p&gt;Now, click on &lt;code&gt;Specify Assemblies&lt;/code&gt; and uncheck everything except the first entry:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcpv962m3rg3gcws2c48z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcpv962m3rg3gcws2c48z.png" alt="De-selecting unnecessary assemblies" width="800" height="540"&gt;&lt;/a&gt;&lt;/p&gt;
De-selecting unnecessary assemblies






&lt;p&gt;Click on &lt;code&gt;Generate Manifest&lt;/code&gt; then close the &lt;code&gt;Voice Hub&lt;/code&gt; for now.&lt;/p&gt;

&lt;p&gt;The next step is to respond to the &lt;code&gt;Utterance&lt;/code&gt; “open the door”. Create a new Script under &lt;strong&gt;Assets/Scripts/VoiceSDK&lt;/strong&gt; and name it &lt;code&gt;OpenDoorConduit&lt;/code&gt;. Add the Script to the &lt;code&gt;XR Origin (XR Rig)&lt;/code&gt; via &lt;code&gt;Add Component&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F93o16kt71eku5z1lx9gk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F93o16kt71eku5z1lx9gk.png" alt="Creating the OpenDoorConduit Script under Scripts/VoiceSDK" width="486" height="391"&gt;&lt;/a&gt;&lt;/p&gt;
Creating the OpenDoorConduit Script under Scripts/VoiceSDK






&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzafqvgdajvlnofi3om6i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzafqvgdajvlnofi3om6i.png" alt="Adding the OpenDoorConduit Script to the XR Origin (XR Rig) GameObject" width="506" height="329"&gt;&lt;/a&gt;&lt;/p&gt;
Adding the OpenDoorConduit Script to the XR Origin (XR Rig) GameObject






&lt;p&gt;The Script looks as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Collections&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Collections.Generic&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Meta.WitAi&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;UnityEngine&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;Taikonauten.Unity.ArticleSeries&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;OpenDoorConduit&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;MonoBehaviour&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;OPEN_DOOR_INTENT&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"open_door"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;MatchIntent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;OPEN_DOOR_INTENT&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;OpenDoor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;values&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;Debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"OpenDoorConduit -&amp;gt; OpenDoor()"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;action&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;values&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
            &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;entity&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;values&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(!&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;IsNullOrEmpty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;IsNullOrEmpty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;Debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"OpenDoorConduit -&amp;gt; OpenDoor(): match"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see we are using &lt;code&gt;MatchIntent&lt;/code&gt; with the &lt;code&gt;open_door&lt;/code&gt; Intent which we created in a previous step. The method &lt;code&gt;OpenDoor&lt;/code&gt; is automatically called by the &lt;code&gt;ConduitDispatcher&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;ℹ️ &lt;code&gt;ConduitDispatcher&lt;/code&gt; is used to manage voice commands, direct them to the appropriate processing channels, or handle the distribution of responses or actions triggered by voice input.&lt;/p&gt;

&lt;p&gt;Now, proceed by adding the &lt;code&gt;App Voice Experience&lt;/code&gt; component to the &lt;code&gt;XR Origin (XR Rig)&lt;/code&gt; GameObject. Once you have added this component, it's necessary to select the Wit configuration, which you have created during the Get Started process for Wit.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F75rqfuws0dw8c3r4r4bp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F75rqfuws0dw8c3r4r4bp.png" alt="Adding App Voice Experience to the XR Origin (XR Rig) GameObject and selecting the Wit configuration" width="506" height="841"&gt;&lt;/a&gt;&lt;/p&gt;
Adding App Voice Experience to the XR Origin (XR Rig) GameObject and selecting the Wit configuration






&lt;p&gt;For the final step, we must add the &lt;code&gt;Response Matcher&lt;/code&gt;. This component generates the Android Intent &lt;code&gt;open_door&lt;/code&gt; in the Android manifest file, and upon receiving a successful response from Wit, it triggers our &lt;code&gt;OpenDoor&lt;/code&gt; method, which we defined earlier.&lt;/p&gt;

&lt;p&gt;To do this, open the &lt;code&gt;Understanding Viewer&lt;/code&gt; via &lt;strong&gt;Oculus → Understanding Viewer&lt;/strong&gt;. Enter “open the door“ in the &lt;code&gt;Utterance&lt;/code&gt; field and click &lt;code&gt;Send&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now right-click &lt;code&gt;value&lt;/code&gt; and select &lt;code&gt;Add response matcher to XR Origin (XR Rig)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi1mecyzqnt23b0le39km.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi1mecyzqnt23b0le39km.png" alt="Adding the response matcher via the Understanding Viewer" width="800" height="502"&gt;&lt;/a&gt;&lt;/p&gt;
Adding the response matcher via the Understanding Viewer






&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp2d6h70098eohkfxou7w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp2d6h70098eohkfxou7w.png" alt="Adding the value matcher via the Understanding Viewer" width="800" height="740"&gt;&lt;/a&gt;&lt;/p&gt;
Adding the value matcher via the Understanding Viewer






&lt;p&gt;This will result in the following screenshot:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F02zndy184qq5664uy8sh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F02zndy184qq5664uy8sh.png" alt="The XR Origin (XR Rig) after adding the response matcher and value matchers" width="671" height="995"&gt;&lt;/a&gt;&lt;/p&gt;
The XR Origin (XR Rig) after adding the response matcher and value matchers






&lt;p&gt;Next, create an entry under &lt;code&gt;On Multi Value Event&lt;/code&gt; and select the values as follows:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs1shhs3n6qbgkq33ux3b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs1shhs3n6qbgkq33ux3b.png" alt="Selecting the OpenDoor method for the new On Multi Value Event" width="667" height="1326"&gt;&lt;/a&gt;&lt;/p&gt;
Selecting the OpenDoor method for the new On Multi Value Event






&lt;h2&gt;
  
  
  Android Setup
&lt;/h2&gt;

&lt;p&gt;To ensure compatibility with the Voice SDK, some adjustments are needed for the Android build. Access the &lt;code&gt;Project Settings&lt;/code&gt; by going to &lt;strong&gt;Edit → Project Settings&lt;/strong&gt;. This step is crucial for configuring your project to work seamlessly with the Voice SDK on Android.&lt;/p&gt;

&lt;p&gt;1. In the &lt;code&gt;Project Settings&lt;/code&gt;, navigate to the &lt;code&gt;Player section&lt;/code&gt;. There, change the &lt;code&gt;Minimum API Level&lt;/code&gt; to &lt;code&gt;Android 10.0 (API Level 29)&lt;/code&gt; and the &lt;code&gt;Target API Level&lt;/code&gt; to &lt;code&gt;Android 12L (API Level 32)&lt;/code&gt;. These options are located under &lt;code&gt;Other Settings&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmga22sgr4ijotiedgsqp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmga22sgr4ijotiedgsqp.png" alt="Setting the Minimum and Target API level for Android" width="800" height="483"&gt;&lt;/a&gt;&lt;/p&gt;
Setting the Minimum and Target API level for Android






&lt;p&gt;2. In the &lt;code&gt;Project Settings&lt;/code&gt;, go to the &lt;code&gt;Player&lt;/code&gt; section, find &lt;code&gt;Application Entry Point&lt;/code&gt; under &lt;code&gt;Other Settings&lt;/code&gt; and change the value from &lt;code&gt;GameActivity&lt;/code&gt; to &lt;code&gt;Activity&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw7r6rmk29insor4g3dmy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw7r6rmk29insor4g3dmy.png" alt="Setting Activity instead of GameActivity as the Application Entry Point" width="800" height="483"&gt;&lt;/a&gt;&lt;/p&gt;
Setting Activity instead of GameActivity as the Application Entry Point






&lt;p&gt;ℹ️ You can find more information about application entry points in the Unity documentation &lt;a href="https://docs.unity3d.com/2023.2/Documentation/Manual/android-application-entries.html"&gt;Unity - Manual:  Android application entry points&lt;/a&gt;. As of the time of writing, it's important to note that &lt;code&gt;GameActivity&lt;/code&gt; is not compatible with the Meta Voice SDK.&lt;/p&gt;

&lt;p&gt;3. In the &lt;code&gt;Project Settings&lt;/code&gt;, go to the &lt;code&gt;Player&lt;/code&gt; section, open the &lt;code&gt;Publishing Settings&lt;/code&gt; tab and enable &lt;code&gt;Custom Main Manifest&lt;/code&gt;. After activating this option, you will find the manifest file located at &lt;strong&gt;Assets/Plugins/Android/AndroidManifest.xml&lt;/strong&gt;. This step is essential for gaining direct control over the Android manifest file, allowing you to make specific customizations needed for your project.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4vpnp6eweds43qmkwuuf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4vpnp6eweds43qmkwuuf.png" alt="Enable the Custom Main Manifest option for Android" width="800" height="483"&gt;&lt;/a&gt;&lt;/p&gt;
Enable the Custom Main Manifest option for Android






&lt;p&gt;Open the &lt;code&gt;AndroidManifest&lt;/code&gt; file in your code editor and modify its content as follows.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?xml version="1.0" encoding="utf-8"?&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;manifest&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="na"&gt;xmlns:android=&lt;/span&gt;&lt;span class="s"&gt;"http://schemas.android.com/apk/res/android"&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="na"&gt;xmlns:tools=&lt;/span&gt;&lt;span class="s"&gt;"http://schemas.android.com/tools"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;application&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;activity&lt;/span&gt; &lt;span class="na"&gt;android:name=&lt;/span&gt;&lt;span class="s"&gt;"com.unity3d.player.UnityPlayerActivity"&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="na"&gt;android:theme=&lt;/span&gt;&lt;span class="s"&gt;"@style/UnityThemeSelector"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;intent-filter&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;action&lt;/span&gt; &lt;span class="na"&gt;android:name=&lt;/span&gt;&lt;span class="s"&gt;"android.intent.action.MAIN"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;category&lt;/span&gt; &lt;span class="na"&gt;android:name=&lt;/span&gt;&lt;span class="s"&gt;"android.intent.category.LAUNCHER"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/intent-filter&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;meta-data&lt;/span&gt; &lt;span class="na"&gt;android:name=&lt;/span&gt;&lt;span class="s"&gt;"unityplayer.UnityActivity"&lt;/span&gt; &lt;span class="na"&gt;android:value=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;meta-data&lt;/span&gt; &lt;span class="na"&gt;android:name=&lt;/span&gt;&lt;span class="s"&gt;"unityplayer.SkipPermissionsDialog"&lt;/span&gt; &lt;span class="na"&gt;android:value=&lt;/span&gt;&lt;span class="s"&gt;"false"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/activity&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/application&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/manifest&amp;gt;&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's review the changes we've made. This will help us understand the adjustments and their impact on the application's functionality and compatibility.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;We have removed the &lt;code&gt;GameActivity&lt;/code&gt; block, as only one &lt;code&gt;Activity&lt;/code&gt; is permitted and we previously opted for &lt;code&gt;UnityActivity&lt;/code&gt; instead of &lt;code&gt;GameActivity&lt;/code&gt; in the &lt;code&gt;Project Settings&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;We included the &lt;code&gt;unityplayer.SkipPermissionsDialog&lt;/code&gt; setting with a value of &lt;code&gt;false&lt;/code&gt; to ensure that required permission dialogs are not automatically bypassed. This adjustment is important for guaranteeing that the application appropriately prompts users for necessary permissions, aligning with best practices for user consent and app functionality.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Adding some UI
&lt;/h2&gt;

&lt;p&gt;Before we can test our implementation, it is essential to integrate some user interface elements into the scene. We will add a UI Label that becomes visible when the application starts listening to the user's voice. This label will then disappear once the recording ceases, triggered by a successful response from Wit. This UI component plays a crucial role in providing visual feedback to the user about the state of voice recognition within the application.&lt;/p&gt;

&lt;p&gt;To set up the user interface for voice recognition feedback, follow these steps:&lt;/p&gt;

&lt;p&gt;1. Create an empty GameObject in your scene and name it &lt;code&gt;UI&lt;/code&gt;.&lt;br&gt;
2. Within the &lt;code&gt;UI&lt;/code&gt; GameObject, add another empty GameObject and name it &lt;code&gt;VoiceSDK&lt;/code&gt;.&lt;br&gt;
3. With the &lt;code&gt;VoiceSDK&lt;/code&gt; GameObject selected in the hierarchy attach the &lt;code&gt;Lazy Follow&lt;/code&gt; script via &lt;code&gt;Add Component&lt;/code&gt;. Configure the script as follows:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl13aoxwjn0go1qe7xli5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl13aoxwjn0go1qe7xli5.png" alt="Image description" width="577" height="690"&gt;&lt;/a&gt;&lt;/p&gt;
Enable the Custom Main Manifest option for Android





&lt;p&gt;4. Add a Canvas to the &lt;code&gt;VoiceSDK&lt;/code&gt; GameObject by right-clicking it and navigating to &lt;strong&gt;UI -&amp;gt; Canvas&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;5. Inside the Canvas, add a Text element by choosing &lt;strong&gt;UI → Text - TextMeshPro&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This setup creates a structured UI hierarchy in your scene, with the &lt;code&gt;VoiceSDK&lt;/code&gt; GameObject serving as a container for the elements that will provide visual feedback for voice recognition. The &lt;code&gt;Lazy Follow&lt;/code&gt; script will manage the positioning, and the &lt;code&gt;TextMeshPro&lt;/code&gt; element will display the necessary information or status messages.&lt;/p&gt;

&lt;p&gt;Your hierarchy should now look as follows:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2zb2f2acc546bfnm54xw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2zb2f2acc546bfnm54xw.png" alt="Hierarchy after adding the UI" width="282" height="213"&gt;&lt;/a&gt;&lt;/p&gt;
Hierarchy after adding the UI





&lt;p&gt;Select the &lt;code&gt;EventSystem&lt;/code&gt; GameObject in your hierarchy and delete and add components like follows:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffi21ifbxx5ql4ki2f6ov.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffi21ifbxx5ql4ki2f6ov.png" alt="The UI EventSystem" width="579" height="855"&gt;&lt;/a&gt;&lt;/p&gt;
The UI EventSystem





&lt;p&gt;Don’t forget to remove the &lt;code&gt;Standalone Input Module&lt;/code&gt; if any.&lt;/p&gt;

&lt;p&gt;Next, we need to configure our &lt;code&gt;Canvas&lt;/code&gt; and &lt;code&gt;Text (TMP)&lt;/code&gt; elements. Select the &lt;code&gt;Canvas&lt;/code&gt; GameObject in your hierarchy and set it up as follows (Add components as seen in the screenshot via &lt;code&gt;Add Component&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;ℹ️ We won't be delving into UI-related topics in this article series. For those who need assistance or guidance with Unity's UI system, I recommend checking out the Unity documentation. It provides comprehensive resources and tutorials that can help you understand and effectively use Unity's UI tools in your projects.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvt7mcb5001xpgmhnfpd5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvt7mcb5001xpgmhnfpd5.png" alt="The complete Canvas configuration" width="462" height="967"&gt;&lt;/a&gt;&lt;/p&gt;
The complete Canvas configuration





&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsmmmifid286zg9tk0fs2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsmmmifid286zg9tk0fs2.png" alt="The complete Text (TMP) configuration" width="461" height="798"&gt;&lt;/a&gt;&lt;/p&gt;
The complete Text (TMP) configuration





&lt;p&gt;Lastly, deactivate the &lt;code&gt;VoiceSDK&lt;/code&gt; GameObject, as we won't be displaying it immediately. The visibility of the UI will be managed later through our script.&lt;/p&gt;

&lt;p&gt;ℹ️ If you're not familiar with how to deactivate a GameObject in the Unity Inspector, I recommend consulting the Unity documentation: &lt;a href="https://docs.unity3d.com/2023.2/Documentation/Manual/DeactivatingGameObjects.html"&gt;Unity - Manual:  Deactivate GameObjects&lt;/a&gt;.&lt;/p&gt;


&lt;h2&gt;
  
  
  Updating our MRArticleSeriesController Script
&lt;/h2&gt;

&lt;p&gt;For the final step in this article, we'll update our &lt;code&gt;MRArticleSeriesController&lt;/code&gt; Script to enable and disable the Voice Service using the left &lt;code&gt;Trigger&lt;/code&gt;. This modification will allow for straightforward control of the Voice Service directly through user input, enhancing the interactive capabilities of our application.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Collections&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Collections.Generic&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Meta.WitAi&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Meta.WitAi.Requests&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;UnityEngine&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;UnityEngine.InputSystem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;UnityEngine.XR.ARFoundation&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;UnityEngine.XR.ARSubsystems&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;UnityEngine.XR.Interaction.Toolkit&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;Taikonauten.Unity.ArticleSeries&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MRArticleSeriesController&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;MonoBehaviour&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;SerializeField&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="n"&gt;ARAnchorManager&lt;/span&gt; &lt;span class="n"&gt;anchorManager&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;SerializeField&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="n"&gt;GameObject&lt;/span&gt; &lt;span class="n"&gt;door&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;SerializeField&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="n"&gt;GameObject&lt;/span&gt; &lt;span class="n"&gt;uI&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;SerializeField&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="n"&gt;InputActionReference&lt;/span&gt; &lt;span class="n"&gt;buttonActionLeft&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;SerializeField&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="n"&gt;InputActionReference&lt;/span&gt; &lt;span class="n"&gt;buttonActionRight&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;SerializeField&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="n"&gt;VoiceService&lt;/span&gt; &lt;span class="n"&gt;voiceService&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;SerializeField&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="n"&gt;XRRayInteractor&lt;/span&gt; &lt;span class="n"&gt;rayInteractor&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="n"&gt;VoiceServiceRequest&lt;/span&gt; &lt;span class="n"&gt;voiceServiceRequest&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="n"&gt;VoiceServiceRequestEvents&lt;/span&gt; &lt;span class="n"&gt;voiceServiceRequestEvents&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;OnEnable&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;Debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"MRArticleSeriesController -&amp;gt; OnEnable()"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="n"&gt;buttonActionRight&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;performed&lt;/span&gt; &lt;span class="p"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;OnButtonPressedRightAsync&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="n"&gt;buttonActionLeft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;performed&lt;/span&gt; &lt;span class="p"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;OnButtonPressedLeft&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;OnDisable&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;Debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"MRArticleSeriesController -&amp;gt; OnDisable()"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;buttonActionRight&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;performed&lt;/span&gt; &lt;span class="p"&gt;-=&lt;/span&gt; &lt;span class="n"&gt;OnButtonPressedRightAsync&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="n"&gt;buttonActionLeft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;performed&lt;/span&gt; &lt;span class="p"&gt;-=&lt;/span&gt; &lt;span class="n"&gt;OnButtonPressedLeft&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;ActivateVoiceService&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;Debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"MRArticleSeriesController -&amp;gt; ActivateVoiceService()"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;voiceServiceRequestEvents&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;voiceServiceRequestEvents&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;VoiceServiceRequestEvents&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

                &lt;span class="n"&gt;voiceServiceRequestEvents&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OnInit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;OnInit&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="n"&gt;voiceServiceRequestEvents&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OnComplete&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;OnComplete&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;

            &lt;span class="n"&gt;voiceServiceRequest&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;voiceService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Activate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;voiceServiceRequestEvents&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;DeactivateVoiceService&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;Debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"MRArticleSeriesController -&amp;gt; DeactivateVoiceService()"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;voiceServiceRequest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;DeactivateAudio&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;OnInit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;VoiceServiceRequest&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;uI&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SetActive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;OnComplete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;VoiceServiceRequest&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;uI&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SetActive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="nf"&gt;DeactivateVoiceService&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;OnButtonPressedRightAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;InputAction&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CallbackContext&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;Debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"MRArticleSeriesController -&amp;gt; OnButtonPressedRightAsync()"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rayInteractor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;TryGetCurrent3DRaycastHit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;out&lt;/span&gt; &lt;span class="n"&gt;RaycastHit&lt;/span&gt; &lt;span class="n"&gt;hit&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;Pose&lt;/span&gt; &lt;span class="n"&gt;pose&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;point&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Quaternion&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;identity&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="n"&gt;Result&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ARAnchor&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;anchorManager&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;TryAddAnchorAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pose&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

                &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;TryGetResult&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;out&lt;/span&gt; &lt;span class="n"&gt;ARAnchor&lt;/span&gt; &lt;span class="n"&gt;anchor&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;anchor&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="c1"&gt;// Instantiate the door Prefab&lt;/span&gt;
                    &lt;span class="n"&gt;GameObject&lt;/span&gt; &lt;span class="n"&gt;_door&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;Instantiate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;door&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;hit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;point&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Quaternion&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;identity&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

                    &lt;span class="c1"&gt;// Unity recommends parenting your content to the anchor.&lt;/span&gt;
                    &lt;span class="n"&gt;_door&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parent&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;anchor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;OnButtonPressedLeft&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;InputAction&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CallbackContext&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;Debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"MRArticleSeriesController -&amp;gt; OnButtonPressedLeft()"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="nf"&gt;ActivateVoiceService&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's review the updates quickly:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Added a field named &lt;code&gt;uI&lt;/code&gt; to hold the GameObject that will be activated or deactivated based on the VoiceService state.&lt;/li&gt;
&lt;li&gt;Included a field called &lt;code&gt;voiceService&lt;/code&gt; to reference the App Voice Experience component added to the &lt;code&gt;XR Origin (XR Rig)&lt;/code&gt; GameObject.&lt;/li&gt;
&lt;li&gt;Introduced a field &lt;code&gt;voiceServiceRequest&lt;/code&gt; to store the active request to the VoiceService.&lt;/li&gt;
&lt;li&gt;Added a &lt;code&gt;voiceServiceRequestEvents&lt;/code&gt; field, which is passed to the VoiceService. This ensures that the &lt;code&gt;OnInit&lt;/code&gt; and &lt;code&gt;OnComplete&lt;/code&gt; methods are called by the VoiceService.&lt;/li&gt;
&lt;li&gt;In &lt;code&gt;OnEnable&lt;/code&gt; and &lt;code&gt;OnDisable&lt;/code&gt; we add and remove the &lt;code&gt;OnButtonPressedLeft&lt;/code&gt; action, so we can respond to the left controller &lt;code&gt;Trigger&lt;/code&gt; press.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ActivateVoiceService&lt;/code&gt; method, which activates the VoiceService, creates &lt;code&gt;VoiceServiceRequestEvents&lt;/code&gt; if not already initialized, and is called via &lt;code&gt;OnButtonPressedLeft&lt;/code&gt; when the user presses the left Trigger.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;DeactivateVoiceService&lt;/code&gt; which simple deactivates the recording of the &lt;code&gt;VoiceService&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;OnInit&lt;/code&gt; Invoked when the VoiceService starts listening. It enables the UI GameObject to inform the user that the app is now listening.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;OnComplete&lt;/code&gt; called when a voice request succeeds. It also invokes &lt;code&gt;DeactivateVoiceService&lt;/code&gt; to stop the VoiceService from listening.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;OnButtonPressedLeft&lt;/code&gt; triggered when the left Trigger is pressed.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Please be aware that we have also renamed some variables and methods. After saving these changes, remember to return to the Unity Editor and update the fields for the &lt;code&gt;Player&lt;/code&gt; component accordingly.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvslzf30wx3ppoytk4an9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvslzf30wx3ppoytk4an9.png" alt="Updating our values on the MRArticleSeriesController component" width="673" height="560"&gt;&lt;/a&gt;&lt;/p&gt;
Updating our values on the MRArticleSeriesController component






&lt;h2&gt;
  
  
  Testing the app
&lt;/h2&gt;

&lt;p&gt;We are now prepared to test the app. Select &lt;code&gt;Build and Run&lt;/code&gt;, and once the app is running, press the trigger on the left controller. You should see a label appear in front of you indicating "...Listening...". At this point, say the phrase "open the door". After a brief delay, the label should disappear. This process will allow you to verify the functionality of the voice recognition feature in your application.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl9dbixb031ip1wn5xiuu.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl9dbixb031ip1wn5xiuu.jpg" alt="View of the app after a left Trigger press" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;
View of the app after a left Trigger press






&lt;p&gt;Additionally, you can verify in the console if the Intent was triggered, as shown in the following screenshot. This will provide a clear indication of whether the voice command was successfully recognized.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzfnffw6ppo3znmw0v360.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzfnffw6ppo3znmw0v360.png" alt="Console output after the voice command was successfully recognized" width="800" height="335"&gt;&lt;/a&gt;&lt;/p&gt;
Console output after the voice command was successfully recognized






&lt;h2&gt;
  
  
  Next article
&lt;/h2&gt;

&lt;p&gt;In our upcoming article, we will take an exciting step forward by leveraging the voice command functionality we've established to initiate an animation that opens the door. This integration represents a significant enhancement in our application, blending voice recognition with dynamic visual feedback.&lt;/p&gt;

</description>
      <category>unity3d</category>
      <category>mixedreality</category>
      <category>tutorial</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Unity MR Part 9: Instantiate Prefab</title>
      <dc:creator>tststs</dc:creator>
      <pubDate>Thu, 11 Jan 2024 08:51:13 +0000</pubDate>
      <link>https://dev.to/taikonauten/part-9-instantiate-prefab-3jf1</link>
      <guid>https://dev.to/taikonauten/part-9-instantiate-prefab-3jf1</guid>
      <description>&lt;p&gt;👀 Stumbled here on accident? Start with the &lt;a href="https://dev.to/taikonauten/part-0-introduction-56fl"&gt;introduction&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;📚 The objective of this article is to demonstrate how to instantiate a Prefab — in our example, a door — and subsequently anchor it within the MR environment. This process is key to effectively integrating virtual objects, like the door, into the MR space, ensuring they are correctly positioned and maintained within the real-world context.&lt;/p&gt;




&lt;p&gt;ℹ️ If you find yourself facing any difficulties, remember that you can always refer to or download the code from our accompanying &lt;a href="https://github.com/taikonauten/unity-mr-article-series/tree/main/09_InstantiatePrefab"&gt;GitHub repository&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;First, let's create the door Prefab required for this article. Download the following archive &lt;a href="https://github.com/taikonauten/unity-mr-article-series/blob/main/blog/door.rar"&gt;door.rar&lt;/a&gt; and extract its contents into your &lt;strong&gt;Assets/3DModel&lt;/strong&gt; folder. Confirm the following dialog with &lt;code&gt;Fix now&lt;/code&gt; after dropping the files.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa1jii5sn7q97nyu61xqp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa1jii5sn7q97nyu61xqp.png" alt="Confirm with Fix now to mark the texture as a normal map" width="402" height="332"&gt;&lt;/a&gt;&lt;/p&gt;
Confirm with Fix now to mark the texture as a normal map






&lt;p&gt;Then, create a new Prefab in your &lt;strong&gt;Assets/Prefabs&lt;/strong&gt; folder using the same method as we did for the reticle in a previous article. Once you've completed these steps, your Prefab should look like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftr83i50imhledgcnwo24.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftr83i50imhledgcnwo24.png" alt="The Door Prefab in edit mode" width="800" height="521"&gt;&lt;/a&gt;&lt;/p&gt;
The Door Prefab in edit mode






&lt;p&gt;We are now set to instantiate the door Prefab and anchor it within the environment. This action will occur when the user hovers over a valid plane and presses the &lt;code&gt;Trigger&lt;/code&gt; button.&lt;/p&gt;

&lt;p&gt;Here's how the updated &lt;code&gt;MRArticleSeriesController&lt;/code&gt; script will look:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Collections&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Collections.Generic&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;UnityEngine&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;UnityEngine.InputSystem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;UnityEngine.XR.ARFoundation&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;UnityEngine.XR.ARSubsystems&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;UnityEngine.XR.Interaction.Toolkit&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;Taikonauten.Unity.ArticleSeries&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MRArticleSeriesController&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;MonoBehaviour&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;ActionBasedController&lt;/span&gt; &lt;span class="n"&gt;controller&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;InputActionReference&lt;/span&gt; &lt;span class="n"&gt;buttonAction&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;XRRayInteractor&lt;/span&gt; &lt;span class="n"&gt;rayInteractor&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;ARAnchorManager&lt;/span&gt; &lt;span class="n"&gt;anchorManager&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;GameObject&lt;/span&gt; &lt;span class="n"&gt;door&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;OnEnable&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;Debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"MRArticleSeriesController -&amp;gt; OnEnable()"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;buttonAction&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;performed&lt;/span&gt; &lt;span class="p"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;OnButtonPressedAsync&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;OnDisable&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;Debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"MRArticleSeriesController -&amp;gt; OnDisable()"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;buttonAction&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;performed&lt;/span&gt; &lt;span class="p"&gt;-=&lt;/span&gt; &lt;span class="n"&gt;OnButtonPressedAsync&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;OnButtonPressedAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;InputAction&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CallbackContext&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;Debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"MRArticleSeriesController -&amp;gt; OnButtonPressed()"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rayInteractor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;TryGetCurrent3DRaycastHit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;out&lt;/span&gt; &lt;span class="n"&gt;RaycastHit&lt;/span&gt; &lt;span class="n"&gt;hit&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;Pose&lt;/span&gt; &lt;span class="n"&gt;pose&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;point&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Quaternion&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;identity&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="n"&gt;Result&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ARAnchor&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;anchorManager&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;TryAddAnchorAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pose&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

                &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;TryGetResult&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;out&lt;/span&gt; &lt;span class="n"&gt;ARAnchor&lt;/span&gt; &lt;span class="n"&gt;anchor&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;anchor&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="c1"&gt;// Instantiate the door Prefab&lt;/span&gt;
                    &lt;span class="n"&gt;GameObject&lt;/span&gt; &lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="n"&gt;_door&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;Instantiate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;door&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;hit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;point&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Quaternion&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;identity&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

                    &lt;span class="c1"&gt;// Unity recommends parenting your content to the anchor&lt;/span&gt;
                    &lt;span class="c1"&gt;// instead of adding a ARAnchor component to the GameObject&lt;/span&gt;
                    &lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="n"&gt;_door&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parent&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;anchor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's review the updates quickly:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; A public GameObject member named &lt;code&gt;door&lt;/code&gt; has been added, enabling us to select the door Prefab in the Inspector.&lt;/li&gt;
&lt;li&gt; Instead of simply logging the anchor instance, we now verify if the returned anchor is not null.&lt;/li&gt;
&lt;li&gt; The &lt;code&gt;door&lt;/code&gt; Prefab is instantiated at the raycast hit point.&lt;/li&gt;
&lt;li&gt; The &lt;code&gt;door&lt;/code&gt; (our content) is parented to the anchor, following Unity's recommended practices.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;With these updates to the &lt;code&gt;MRArticleSeriesController&lt;/code&gt; Script, don't forget to select the &lt;code&gt;door&lt;/code&gt; Prefab in the Inspector to complete the setup.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftywuwyitrjqyy0x51gyq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftywuwyitrjqyy0x51gyq.png" alt="Selecting the door Prefab in our MRArticleSeriesController Script" width="508" height="668"&gt;&lt;/a&gt;&lt;/p&gt;
Selecting the door Prefab in our MRArticleSeriesController Script






&lt;p&gt;To test the application, choose &lt;code&gt;Build and Run&lt;/code&gt;, as detailed in the previous articles. Hover over a Plane and press the &lt;code&gt;Trigger&lt;/code&gt; button. If all configurations are correct, you should see a similar result as seen in the next video:&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://player.vimeo.com/video/901491409" width="710" height="399"&gt;
&lt;/iframe&gt;
&lt;/p&gt;
Selecting the door Prefab in our MRArticleSeriesController Script






&lt;h2&gt;
  
  
  Next article
&lt;/h2&gt;

&lt;p&gt;In our forthcoming article, we will take an exciting step in our MR journey by integrating the &lt;code&gt;VoiceSDK&lt;/code&gt;. This addition will enable voice interaction within our MR environment, particularly focusing on using voice commands to interact with the door we've created. We'll guide you through the process of integrating the &lt;code&gt;VoiceSDK&lt;/code&gt; into your Unity project, setting up voice recognition, and configuring it to recognize specific commands -- such as "open the door".&lt;/p&gt;

</description>
      <category>unity3d</category>
      <category>mixedreality</category>
      <category>tutorial</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Unity MR Part 8: Anchors</title>
      <dc:creator>tststs</dc:creator>
      <pubDate>Thu, 11 Jan 2024 08:51:08 +0000</pubDate>
      <link>https://dev.to/taikonauten/part-8-anchors-3g4f</link>
      <guid>https://dev.to/taikonauten/part-8-anchors-3g4f</guid>
      <description>&lt;p&gt;👀 Stumbled here on accident? Start with the &lt;a href="https://dev.to/taikonauten/part-0-introduction-56fl"&gt;introduction&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;📚 This article will guide you through the concept of &lt;code&gt;Anchors&lt;/code&gt; MR, explaining their significance and functionality. Additionally, it will provide a comprehensive tutorial on implementing &lt;code&gt;Anchors&lt;/code&gt; within the Unity platform.&lt;/p&gt;




&lt;p&gt;ℹ️ If you find yourself facing any difficulties, remember that you can always refer to or download the code from our accompanying &lt;a href="https://github.com/taikonauten/unity-mr-article-series/tree/main/08_Anchors" rel="noopener noreferrer"&gt;GitHub repository&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;The aim of this article is to conduct hit tests on planes we created previously, using our controller. We'll then instantiate an Anchor at the identified position. This process is fundamental for accurately positioning virtual objects in relation to the real world.&lt;/p&gt;

&lt;p&gt;ℹ️ &lt;code&gt;Anchors&lt;/code&gt; in MR are virtual reference points that are fixed to a specific location in the real world. They are used to maintain the position and orientation of virtual objects consistently as the user moves around or interacts with the MR environment.&lt;/p&gt;

&lt;p&gt;A typical use case for anchors is to place virtual content in the physical world.&lt;/p&gt;




&lt;h2&gt;
  
  
  AR Anchor Manager component
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;AR Anchor Manager component&lt;/code&gt; creates GameObjects for each anchor and is a critical element for managing AR anchors. It acts as a central point for creating, tracking, and updating anchors in the AR environment. This component is essential for ensuring that virtual objects are anchored accurately to real-world locations, maintaining their position and orientation consistently.&lt;/p&gt;

&lt;p&gt;⚠️ Throughout its lifespan, the Meta Quest 3 device usually undertakes extra tasks to keep the anchor's position and orientation up to date. Given that anchors are typically resource-intensive objects, it's advisable to use them wisely.&lt;/p&gt;




&lt;h2&gt;
  
  
  Adding AR Anchor Manager component to the Scene
&lt;/h2&gt;

&lt;p&gt;In the hierarchy view find the &lt;code&gt;XR Origin (XR Rig)&lt;/code&gt; GameObject and add the &lt;code&gt;AR Anchor Manager&lt;/code&gt; script via &lt;code&gt;Add Component&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frl58nbi0ndcctrnc5ios.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frl58nbi0ndcctrnc5ios.png" alt="The XR Origin (XR Rig) GameObject with the added AR Anchor Manager Script"&gt;&lt;/a&gt;&lt;/p&gt;
The XR Origin (XR Rig) GameObject with the added AR Anchor Manager Script






&lt;p&gt;There's no need to modify any fields in the &lt;code&gt;AR Anchor Manager&lt;/code&gt;. The &lt;code&gt;trackables Changed&lt;/code&gt; is a list of &lt;code&gt;ARTrackables&lt;/code&gt;, managed by the &lt;code&gt;ARTrackableManager&lt;/code&gt;. Additionally, the &lt;code&gt;Anchor Prefab&lt;/code&gt; field is only necessary if there's a requirement to enhance the default Prefab instantiated for each Anchor.&lt;/p&gt;

&lt;p&gt;ℹ️ You can read more about the different Managers in &lt;code&gt;ARFoundation&lt;/code&gt; here: &lt;a href="https://docs.unity3d.com/Packages/com.unity.xr.arfoundation@6.0/manual/architecture/managers.html" rel="noopener noreferrer"&gt;Managers | AR Foundation | 6.0.0-pre.5.l&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Let's move on to updating our &lt;code&gt;MRArticleSeriesController.cs&lt;/code&gt; script. In this update, we'll adjust the script to instantiate an Anchor at the &lt;code&gt;Pose&lt;/code&gt; of a valid Raycast Hit. For the moment, we'll simply log the creation of the Anchor. In the following article, we will focus on instantiating a Prefab and attaching it to this Anchor.&lt;/p&gt;

&lt;p&gt;ℹ️ &lt;code&gt;Pose&lt;/code&gt; is a representation of a Position, and a Rotation in 3D Space. This structure is used primarily in XR applications to describe the current "pose" of a device in 3D space.&lt;/p&gt;

&lt;p&gt;The revised script will be structured as follows:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;

&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Collections&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Collections.Generic&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;UnityEngine&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;UnityEngine.InputSystem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;UnityEngine.XR.ARFoundation&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;UnityEngine.XR.ARSubsystems&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;UnityEngine.XR.Interaction.Toolkit&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;Taikonauten.Unity.ArticleSeries&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MRArticleSeriesController&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;MonoBehaviour&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;ActionBasedController&lt;/span&gt; &lt;span class="n"&gt;controller&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;InputActionReference&lt;/span&gt; &lt;span class="n"&gt;buttonAction&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;XRRayInteractor&lt;/span&gt; &lt;span class="n"&gt;rayInteractor&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;ARAnchorManager&lt;/span&gt; &lt;span class="n"&gt;anchorManager&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;OnEnable&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;Debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"MRArticleSeriesController -&amp;gt; OnEnable()"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;buttonAction&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;performed&lt;/span&gt; &lt;span class="p"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;OnButtonPressedAsync&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;OnDisable&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;Debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"MRArticleSeriesController -&amp;gt; OnDisable()"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;buttonAction&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;performed&lt;/span&gt; &lt;span class="p"&gt;-=&lt;/span&gt; &lt;span class="n"&gt;OnButtonPressedAsync&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;OnButtonPressedAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;InputAction&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CallbackContext&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;Debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"MRArticleSeriesController -&amp;gt; OnButtonPressed()"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rayInteractor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;TryGetCurrent3DRaycastHit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;out&lt;/span&gt; &lt;span class="n"&gt;RaycastHit&lt;/span&gt; &lt;span class="n"&gt;hit&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;Pose&lt;/span&gt; &lt;span class="n"&gt;pose&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;point&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Quaternion&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;identity&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="n"&gt;Result&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ARAnchor&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;anchorManager&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;TryAddAnchorAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pose&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

                &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;TryGetResult&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;out&lt;/span&gt; &lt;span class="n"&gt;ARAnchor&lt;/span&gt; &lt;span class="n"&gt;anchor&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

                &lt;span class="n"&gt;Debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;anchor&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;



&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Before testing the app, it's important to select our &lt;code&gt;AR Anchor Manager&lt;/code&gt;. To do this, locate the &lt;code&gt;XR Origin (XR Rig)&lt;/code&gt; GameObject in your hierarchy, and then, as indicated in the following screenshot, choose the &lt;code&gt;AR Anchor Manager&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx9vjx6n4sw9ngzut31jf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx9vjx6n4sw9ngzut31jf.png" alt="Selecting the AR Anchor Manager for the MRArticleSeriesController.cs Script"&gt;&lt;/a&gt;&lt;/p&gt;
Selecting the AR Anchor Manager for the MRArticleSeriesController.cs Script






&lt;p&gt;To test the application, choose &lt;code&gt;Build and Run&lt;/code&gt;, as detailed in the previous articles. Hover over a Plane and press the &lt;code&gt;Trigger&lt;/code&gt; button. If all configurations are correct, you should see the specified output in your console. Remember to select the correct device, not the Editor, as highlighted in previous articles.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3rhptd804roderla0s0p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3rhptd804roderla0s0p.png" alt="Console output for the Meta Quest 3 device"&gt;&lt;/a&gt;&lt;/p&gt;
Console output for the Meta Quest 3 device






&lt;h2&gt;
  
  
  Next article
&lt;/h2&gt;

&lt;p&gt;In the upcoming article, we will delve into the process of instantiating a prefab in a MR environment using Unity. This technique is key to bringing virtual objects into your MR space, allowing for a richer and more interactive experience.&lt;/p&gt;

</description>
      <category>unity3d</category>
      <category>mixedreality</category>
      <category>tutorial</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Unity MR Part 7: Raycasts</title>
      <dc:creator>tststs</dc:creator>
      <pubDate>Thu, 11 Jan 2024 08:51:03 +0000</pubDate>
      <link>https://dev.to/taikonauten/part-7-raycasts-1coh</link>
      <guid>https://dev.to/taikonauten/part-7-raycasts-1coh</guid>
      <description>&lt;p&gt;👀 Stumbled here on accident? Start with the &lt;a href="https://dev.to/taikonauten/part-0-introduction-56fl"&gt;introduction&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;📚 This article will guide you through the concept of &lt;code&gt;Raycasts&lt;/code&gt; in MR, explaining their significance and functionality. Additionally, it will provide a comprehensive tutorial on implementing &lt;code&gt;Raycasts&lt;/code&gt; within the Unity platform.&lt;/p&gt;




&lt;p&gt;ℹ️ If you find yourself facing any difficulties, remember that you can always refer to or download the code from our accompanying &lt;a href="https://github.com/taikonauten/unity-mr-article-series/tree/main/07_Raycasts"&gt;GitHub repository&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;The aim of this article is to conduct hit tests on planes we created previously, using our controller. We'll then, in the next article, place an Anchor at the identified position. This process is fundamental for accurately positioning virtual objects in relation to the real world.&lt;/p&gt;

&lt;p&gt;ℹ️ &lt;code&gt;Raycasts&lt;/code&gt; in Unity and MR are used to determine if and where a virtual ray intersects with objects in the game world or MR environment. They're crucial for interaction, allowing the detection of objects, surfaces, or points in 3D space. In MR, &lt;code&gt;Raycasts&lt;/code&gt; can be used for selecting or interacting with virtual objects overlaid on the real world.&lt;/p&gt;




&lt;h2&gt;
  
  
  Creating a custom Reticle
&lt;/h2&gt;

&lt;p&gt;ℹ️ In AR, a reticle is a visual indicator, often a small pointer or dot, used to help users accurately target and interact with virtual elements overlaid onto the real world. It provides a focal point for interaction, indicating where actions like tapping, selecting, or placing virtual objects will occur. Reticles are especially useful in AR experiences to improve precision and user experience in environments where direct touch interactions are not possible.&lt;/p&gt;

&lt;p&gt;To create a custom &lt;code&gt;Reticle&lt;/code&gt;, we'll utilize the asset provided in the link. Download the file directly into your Assets folder. For the purposes of this article, we'll organize it in a subfolder named &lt;strong&gt;3DModels&lt;/strong&gt;. Alternatively, you can download the asset to a different folder and then drag and drop it into the &lt;strong&gt;3DModels&lt;/strong&gt; folder within Unity.&lt;/p&gt;

&lt;p&gt;⬇️ &lt;a href="https://github.com/taikonauten/unity-mr-article-series/blob/main/blog/arrow.fbx"&gt;arrow.fbx&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's begin by creating a visual indicator, a &lt;code&gt;Reticle&lt;/code&gt;, which will appear when we hover over any of the planes managed by the &lt;code&gt;AR Plane Manager&lt;/code&gt;.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; First, create a new empty GameObject via &lt;strong&gt;Create → Empty&lt;/strong&gt; in your hierarchy and name it 'Reticle'.&lt;/li&gt;
&lt;li&gt; Next, drag and drop this GameObject into your Prefabs folder, then remove the &lt;code&gt;Reticle&lt;/code&gt; GameObject from the hierarchy.&lt;/li&gt;
&lt;li&gt; Double-click the prefab &lt;code&gt;Reticle&lt;/code&gt; you just created to start editing it.&lt;/li&gt;
&lt;li&gt; Make sure the &lt;code&gt;Reticle&lt;/code&gt; GameObject's position is set to &lt;strong&gt;X: 0, Y: 0, Z: 0&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt; Then, drag and drop the &lt;strong&gt;.fbx&lt;/strong&gt; file from your &lt;strong&gt;3DModels&lt;/strong&gt; folder onto the &lt;code&gt;Reticle&lt;/code&gt; GameObject in your hierarchy view.&lt;/li&gt;
&lt;li&gt; Make sure the &lt;code&gt;arrow&lt;/code&gt; GameObject's position is set to &lt;strong&gt;X: 0, Y: 0, Z: 0&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt; Finally, adjust the position, rotation, and scale of the Cone and Cylinder to suit your needs.&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Cone&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;X&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Y&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Z&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Position&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;-0.1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Rotation&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;90&lt;/td&gt;
&lt;td&gt;180&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Scale&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;0.2&lt;/td&gt;
&lt;td&gt;0.2&lt;/td&gt;
&lt;td&gt;0.2&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Cylinder&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;X&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Y&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Z&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Position&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;-0.3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Rotation&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;90&lt;/td&gt;
&lt;td&gt;180&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Scale&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;0.2&lt;/td&gt;
&lt;td&gt;0.2&lt;/td&gt;
&lt;td&gt;0.2&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;With the specified values, you will achieve the Prefab configuration as shown in the upcoming screenshot. If you are designing a custom Reticle, remember to modify only the position, rotation, and scale of the Mesh components. It's important to avoid altering these values for the &lt;code&gt;Reticle&lt;/code&gt; GameObject itself to maintain its intended functionality and alignment.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5tlnbphva8qb24deuy4s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5tlnbphva8qb24deuy4s.png" alt="Custom Reticle after updating Position, Rotation and Scale" width="800" height="526"&gt;&lt;/a&gt;&lt;/p&gt;
Custom Reticle after updating Position, Rotation and Scale






&lt;h2&gt;
  
  
  Updating our AR Default Plane
&lt;/h2&gt;

&lt;p&gt;We aim for the &lt;code&gt;Reticle&lt;/code&gt; to be visible only when hovering over one of our &lt;code&gt;AR Default Plane&lt;/code&gt;s. To achieve this, modify the &lt;code&gt;AR Default Plane&lt;/code&gt; Prefab (by double clicking the &lt;code&gt;AR Default Plane&lt;/code&gt; in the &lt;strong&gt;Assets/Prefabs&lt;/strong&gt; folder), add the &lt;code&gt;XR Simple Interactable&lt;/code&gt; Script and select the newly created &lt;code&gt;Reticle&lt;/code&gt; Prefab as the &lt;code&gt;Custom Reticle&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm2k4v074ixhdevftqrb8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm2k4v074ixhdevftqrb8.png" alt="Setting the custom Reticle on the AR Default Plane" width="502" height="734"&gt;&lt;/a&gt;&lt;/p&gt;
Setting the custom Reticle on the AR Default Plane






&lt;p&gt;This Prefab will now be instantiated at the position where our ray intersects with any of the planes registered in our &lt;code&gt;AR Plane Manager&lt;/code&gt;. When you run your app with these settings, you'll observe that the custom &lt;code&gt;Reticle&lt;/code&gt; is now accurately indicating the plane being hovered over.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fypuekxctud1cy1p8h5z4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fypuekxctud1cy1p8h5z4.png" alt="The custom Reticle in MR" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;
The custom Reticle in MR






&lt;h2&gt;
  
  
  Improve the appearance of the XR Interactor Line Visual
&lt;/h2&gt;

&lt;p&gt;In this step, we'll adjust the color gradients for &lt;code&gt;Valid&lt;/code&gt;, &lt;code&gt;Invalid&lt;/code&gt;, and &lt;code&gt;Blocked&lt;/code&gt; states in the &lt;code&gt;XR Interactor Line Visual&lt;/code&gt;. This modification will change the line's color based on interaction: it will display one color when hovering over a valid target (in our scenario, detected planes) and another color when no valid target is hovered over (anything other than planes). This visual cue enhances the user's understanding of interaction possibilities within the AR environment.&lt;/p&gt;

&lt;p&gt;You can use the following color gradients as seen in the upcoming screenshots or use your own custom gradients.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8tiwztmvcavtrdlctmlm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8tiwztmvcavtrdlctmlm.png" alt="XR Interactor Line Visual with updated color gradients" width="418" height="863"&gt;&lt;/a&gt;&lt;/p&gt;
XR Interactor Line Visual with updated color gradients






&lt;p&gt;The &lt;code&gt;Valid&lt;/code&gt; color gradients with a starting color of &lt;code&gt;#00A0FF&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foe5bm3wuz8e7votjlkqu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foe5bm3wuz8e7votjlkqu.png" alt="Valid Color Gradient" width="362" height="309"&gt;&lt;/a&gt;&lt;/p&gt;
Valid Color Gradient






&lt;p&gt;The &lt;code&gt;Invalid&lt;/code&gt; color gradients with a starting color of &lt;code&gt;#FFFFFF&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9edo7hqd0p42rwd8h2fq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9edo7hqd0p42rwd8h2fq.png" alt="Invalid Color Gradient" width="362" height="309"&gt;&lt;/a&gt;&lt;/p&gt;
Invalid Color Gradient






&lt;p&gt;The &lt;code&gt;Blocked&lt;/code&gt; color gradients with a starting color of &lt;code&gt;#FFEB04&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn0wc3tci5x7ssk84pxxq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn0wc3tci5x7ssk84pxxq.png" alt="Blocked Color Gradient" width="362" height="309"&gt;&lt;/a&gt;&lt;/p&gt;
Blocked Color Gradient






&lt;p&gt;Ensure that you also apply the same values to the &lt;code&gt;Right Controller&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;That concludes the adjustments to the color gradients of the &lt;code&gt;XR Interactor Line Visual&lt;/code&gt;. We'll examine the outcome of these changes at the end of this article, providing a comprehensive view of how these modifications enhance the visual feedback in our application.&lt;/p&gt;




&lt;h2&gt;
  
  
  Improve appearance of the Reticle
&lt;/h2&gt;

&lt;p&gt;For the final visual enhancement, let's create a new Material for the custom &lt;code&gt;Reticle&lt;/code&gt;. Go ahead and make a new Material in your &lt;strong&gt;Assets/Materials&lt;/strong&gt; folder and name it ‘Reticle’. You can either use the following suggested values or select your own based on your specific needs. This step will ensure that the custom &lt;code&gt;Reticle&lt;/code&gt; has a distinctive and appropriate appearance in your application.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv0hxdslgtcicr88cag9b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv0hxdslgtcicr88cag9b.png" alt="The new Reticle Material" width="505" height="577"&gt;&lt;/a&gt;&lt;/p&gt;
The new Reticle Material






&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fydwe1bphodv8i3kxx92c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fydwe1bphodv8i3kxx92c.png" alt="Base Map color for the Reticle Material" width="235" height="508"&gt;&lt;/a&gt;&lt;/p&gt;
Base Map color for the Reticle Material






&lt;p&gt;Edit the &lt;code&gt;Reticle&lt;/code&gt; Prefab by double-clicking it in &lt;strong&gt;Assets/Prefabs&lt;/strong&gt;. Now, drag and drop the new Material onto both meshes within the &lt;code&gt;Reticle&lt;/code&gt; Prefab (Cone and Cylinder). Once you've done this, your &lt;code&gt;Reticle&lt;/code&gt; Prefab should resemble the appearance shown in the upcoming screenshot.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu2ks4rha5m0a25ut2scp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu2ks4rha5m0a25ut2scp.png" alt="Retacle Prefab with the updated Material" width="800" height="519"&gt;&lt;/a&gt;&lt;/p&gt;
Retacle Prefab with the updated Material






&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw6kdv7nl5d2232gg389w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw6kdv7nl5d2232gg389w.png" alt="Retacle Prefab with the updated Material in our app" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;
Retacle Prefab with the updated Material in our app






&lt;h2&gt;
  
  
  Reacting to a OnButtonPressed Event and check if the Ray hits a Plane
&lt;/h2&gt;

&lt;p&gt;For the final step in this article we dive a bit into code. Create a Script named &lt;code&gt;MRArticleSeriesController.cs&lt;/code&gt; in your &lt;strong&gt;Assets/Scripts&lt;/strong&gt; folder and use the following code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Collections&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Collections.Generic&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;UnityEngine&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;UnityEngine.InputSystem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;UnityEngine.XR.Interaction.Toolkit&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;Taikonauten.Unity.ArticleSeries&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MRArticleSeriesController&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;MonoBehaviour&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;ActionBasedController&lt;/span&gt; &lt;span class="n"&gt;controller&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;InputActionReference&lt;/span&gt; &lt;span class="n"&gt;buttonAction&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;XRRayInteractor&lt;/span&gt; &lt;span class="n"&gt;rayInteractor&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;OnEnable&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;Debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"MRArticleSeriesController -&amp;gt; OnEnable()"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;buttonAction&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;performed&lt;/span&gt; &lt;span class="p"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;OnButtonPressed&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;OnDisable&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;Debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"MRArticleSeriesController -&amp;gt; OnDisable()"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;buttonAction&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;performed&lt;/span&gt; &lt;span class="p"&gt;-=&lt;/span&gt; &lt;span class="n"&gt;OnButtonPressed&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;OnButtonPressed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;InputAction&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CallbackContext&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;Debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"MRArticleSeriesController -&amp;gt; OnButtonPressed()"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rayInteractor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;TryGetCurrent3DRaycastHit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;out&lt;/span&gt; &lt;span class="n"&gt;RaycastHit&lt;/span&gt; &lt;span class="n"&gt;hit&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;Debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hit&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Drag and drop the script onto your &lt;code&gt;XR Origin (XR Rig)&lt;/code&gt;. Then, as shown in the upcoming screenshot, select an &lt;code&gt;ActionBasedController&lt;/code&gt;, &lt;code&gt;InputActionReference&lt;/code&gt;, and &lt;code&gt;XRRayInteractor&lt;/code&gt;. This step integrates the script with the XR Rig, ensuring that the controller, input actions, and ray interactions are properly configured.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg69iutxmlf0aqxwqm09q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg69iutxmlf0aqxwqm09q.png" alt="Adding the MRArticleSeriesController script to our XR Origin (XR Rig) GameObject" width="508" height="348"&gt;&lt;/a&gt;&lt;/p&gt;
Adding the MRArticleSeriesController script to our XR Origin (XR Rig) GameObject






&lt;p&gt;Let's proceed to build and deploy the app onto our headset to see the results. Navigate to &lt;strong&gt;File → Build Settings&lt;/strong&gt; and, as depicted in the upcoming screenshot, enable the &lt;code&gt;Development Build&lt;/code&gt; option under the &lt;code&gt;Android&lt;/code&gt; section.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjcryfro3avg4bhu5js7l.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjcryfro3avg4bhu5js7l.png" alt="Enable Development Build in Build Settings" width="800" height="505"&gt;&lt;/a&gt;&lt;/p&gt;
Enable Development Build in Build Settings






&lt;p&gt;To ensure proper functionality, it's necessary to disable &lt;code&gt;Vulkan&lt;/code&gt; in the &lt;code&gt;Graphics APIs&lt;/code&gt; in the Player section. Navigate to &lt;strong&gt;Edit -&amp;gt; Project Settings&lt;/strong&gt;, and as illustrated in the following screenshot, remove &lt;code&gt;Vulkan&lt;/code&gt; from the list of enabled Graphics APIs. This adjustment is crucial for compatibility.&lt;/p&gt;

&lt;p&gt;As of Unity version &lt;code&gt;2023.2.3f&lt;/code&gt; and &lt;code&gt;Unity OpenXR: Meta 1.0.1&lt;/code&gt;, creating a development build with Vulkan enabled leads to crashes. This known issue highlights the importance of avoiding Vulkan in your development builds with these specific versions to ensure stability and prevent unexpected crashes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F11h5m44gf8lu2o94irjc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F11h5m44gf8lu2o94irjc.png" alt="Removing the Vulkan Graphics API from Graphics APIs" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;
Removing the Vulkan Graphics API from Graphics APIs






&lt;p&gt;Select &lt;code&gt;Build and Run&lt;/code&gt; to test the application. Since we have configured only the Right Controller, which suffices for our purposes, you should observe the following console output when the &lt;code&gt;Trigger&lt;/code&gt; button is pressed.&lt;/p&gt;

&lt;p&gt;To view the output from the build on your headset, you need to choose the connected Oculus Quest in your Console window.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb10exali4zh4kmzizpsy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb10exali4zh4kmzizpsy.png" alt="Selecting the Meta Quest 3 in Console" width="800" height="342"&gt;&lt;/a&gt;&lt;/p&gt;
Selecting the Meta Quest 3 in Console






&lt;p&gt;As demonstrated in the upcoming screenshot, the &lt;code&gt;Debug.Log&lt;/code&gt; statement generates the expected output. This visual confirmation in the screenshot effectively showcases that the application is functioning as intended, aligning with our anticipated results.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; AndroidPlayer "Oculus_Quest" Player -&amp;gt; OnButtonPressed()&lt;/li&gt;
&lt;li&gt; AndroidPlayer "Oculus_Quest" UnityEngine.RaycastHit&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffcr50yefkiqbi7pu4ol2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffcr50yefkiqbi7pu4ol2.png" alt="The debug logs after pressing the Trigger button of the right controller" width="784" height="190"&gt;&lt;/a&gt;&lt;/p&gt;
The debug logs after pressing the Trigger button of the right controller






&lt;h2&gt;
  
  
  Next article
&lt;/h2&gt;

&lt;p&gt;In our next article, we'll be focusing on an essential aspect of AR development: &lt;code&gt;Planes&lt;/code&gt; and the &lt;code&gt;AR Plane Manager&lt;/code&gt; in Unity. Planes are fundamental to understanding and interacting with the real world in AR applications. We will explore how the &lt;code&gt;AR Plane Manager&lt;/code&gt; detects and manages these planes, allowing for the placement of virtual objects on flat surfaces like floors, tables, or walls.&lt;/p&gt;

</description>
      <category>unity3d</category>
      <category>mixedreality</category>
      <category>tutorial</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Unity MR Part 6: Planes</title>
      <dc:creator>tststs</dc:creator>
      <pubDate>Thu, 11 Jan 2024 08:50:58 +0000</pubDate>
      <link>https://dev.to/taikonauten/part-6-planes-3jhb</link>
      <guid>https://dev.to/taikonauten/part-6-planes-3jhb</guid>
      <description>&lt;p&gt;👀 Stumbled here on accident? Start with the &lt;a href="https://dev.to/taikonauten/part-0-introduction-56fl"&gt;introduction&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;📚 In this article, we'll focus on rendering a GameObject for every detected horizontal plane obtained from the Space Setup. Additionally, we will create a Material specifically for each of these GameObjects. This process is integral to visualizing spatial data and enhancing the interactive elements of our project.&lt;/p&gt;




&lt;p&gt;ℹ️ If you find yourself facing any difficulties, remember that you can always refer to or download the code from our accompanying &lt;a href="https://github.com/taikonauten/unity-mr-article-series/tree/main/06_Planes"&gt;GitHub repository&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;ℹ️ Before beginning, it's necessary to execute the Space Setup on your Meta Quest, found under &lt;strong&gt;Physical Space → Space Setup&lt;/strong&gt;. This process enables mapping of various objects like doors, walls, tables, couches, and more. The Meta Quest memorizes these details, allowing for an enhanced virtual reality experience that fully utilizes your area's boundaries.&lt;/p&gt;




&lt;h2&gt;
  
  
  Adding the AR Plane Manager
&lt;/h2&gt;

&lt;p&gt;Add the &lt;code&gt;AR Plane Manager&lt;/code&gt; to our existing &lt;code&gt;XR Origin (XR Rig)&lt;/code&gt; GameObject by using &lt;code&gt;Add Component&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzd89rut5i0oks84dscs2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzd89rut5i0oks84dscs2.png" alt="The XR Origin (XR Rig) GameObject with the added AR Plane Manager" width="506" height="390"&gt;&lt;/a&gt;&lt;/p&gt;
The XR Origin (XR Rig) GameObject with the added AR Plane Manager






&lt;h2&gt;
  
  
  Creating a Prefab for our detected planes
&lt;/h2&gt;

&lt;p&gt;As illustrated in the screenshot, it's necessary to define a Plane Prefab, which we will create in the following steps. To do this, go to your project's hierarchy and create an AR Default Plane by right-clicking and navigating to &lt;strong&gt;XR → AR Default Plane&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;ℹ️ The &lt;code&gt;AR Default Plane&lt;/code&gt; in Unity is a preset GameObject used to visually represent detected planes in an AR environment. It's often used as a default visual marker for floors, walls, or other flat surfaces that the AR system identifies in the real world, providing a reference point for placing virtual objects in relation to these physical surfaces.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx3qrjqqmxnonn6x2vrzn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx3qrjqqmxnonn6x2vrzn.png" alt="Hierarchy with the added AR Default Plane" width="279" height="187"&gt;&lt;/a&gt;&lt;/p&gt;
Hierarchy with the added AR Default Plane






&lt;p&gt;Create a new folder named &lt;code&gt;Prefabs&lt;/code&gt; in your &lt;code&gt;Assets&lt;/code&gt; folder.&lt;/p&gt;

&lt;p&gt;Then, create a Prefab by dragging the &lt;code&gt;AR Default Plane&lt;/code&gt; GameObject from your hierarchy into your &lt;strong&gt;Assets/Prefabs&lt;/strong&gt; folder. For those unfamiliar with the concept of Prefabs, it's advisable to refer to Unity's official documentation on Prefabs &lt;a href="https://docs.unity3d.com/2023.2/Documentation/Manual/Prefabs.html"&gt;Unity - Manual: Prefabs&lt;/a&gt; for a thorough understanding.&lt;/p&gt;

&lt;p&gt;By dragging and dropping the GameObject into the Prefabs folder, you create a reusable Prefab. After you have created this Prefab, remove the &lt;code&gt;AR Default Plane&lt;/code&gt; GameObject from your hierarchy.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F88kugr1ze00n00ofjc0f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F88kugr1ze00n00ofjc0f.png" alt="Creating the AR Default Plane Prefab" width="479" height="300"&gt;&lt;/a&gt;&lt;/p&gt;
Creating the AR Default Plane Prefab






&lt;p&gt;Next, select your &lt;code&gt;XR Origin (XR Rig)&lt;/code&gt; in the hierarchy and assign the &lt;code&gt;AR Default Plane&lt;/code&gt; Prefab to the &lt;code&gt;AR Plane Manager&lt;/code&gt;. The AR Plane Manager will instantiate an &lt;code&gt;AR Default Plane&lt;/code&gt; GameObject at each plane's position based on spatial data.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6anl5npj4kidh1a26vex.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6anl5npj4kidh1a26vex.png" alt="Selecting the AR Default Plane for the AR Plane Manager&amp;lt;br&amp;gt;
" width="502" height="872"&gt;&lt;/a&gt;&lt;/p&gt;
Selecting the AR Default Plane for the AR Plane Manager







&lt;p&gt;For the purposes of this article series, we only require horizontal planes. As shown in the upcoming screenshot, select &lt;code&gt;Horizontal&lt;/code&gt; as the Detection Mode, preparing the system to specifically detect and interact with horizontal surfaces in the environment.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fttvw7e821cjcjnjwv07g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fttvw7e821cjcjnjwv07g.png" alt="Setting the Detection Mode for the AR Plane Manager" width="508" height="371"&gt;&lt;/a&gt;&lt;/p&gt;
Setting the Detection Mode for the AR Plane Manager






&lt;h2&gt;
  
  
  Setup the default plane Prefab
&lt;/h2&gt;

&lt;p&gt;Finally, we need to modify the &lt;code&gt;AR Default Plane&lt;/code&gt; Prefab. Open it in the Prefab Editor by double-clicking on it in your Project window. The primary adjustment involves assigning an appropriate material to the mesh.&lt;/p&gt;

&lt;p&gt;ℹ️ For those unfamiliar with creating materials in Unity, more information can be found in the &lt;a href="https://docs.unity3d.com/Manual/materials-introduction.html"&gt;Unity documentation&lt;/a&gt;, which provides comprehensive guidance on material creation and customization in Unity environments.&lt;/p&gt;

&lt;p&gt;Create a new Material in your &lt;strong&gt;Assets/Materials&lt;/strong&gt; folder and name it &lt;code&gt;PlaneMaterial&lt;/code&gt;. You’ll find the Assets folder under &lt;code&gt;Project&lt;/code&gt;. Create an empty folder Materials if not already done. As this material is intended for debugging purposes, we'll construct a basic one. This straightforward approach streamlines the process, ensuring that the material effectively serves its debugging function without the need for complex configurations or properties. You can choose the values as in the next screenshot or choose your own Material.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5zw5cc0yd9e1w0dc8vgn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5zw5cc0yd9e1w0dc8vgn.png" alt="PlaneMaterial Surface Options/Inputs (Example)" width="385" height="594"&gt;&lt;/a&gt;&lt;/p&gt;
PlaneMaterial Surface Options/Inputs (Example)






&lt;p&gt;Also update the &lt;code&gt;Base Map&lt;/code&gt; color under &lt;code&gt;Surface Inputs&lt;/code&gt;. Choose &lt;code&gt;FFFFFFF&lt;/code&gt; and for Alpha &lt;code&gt;0&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fahmlb3lqerloun66ovdx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fahmlb3lqerloun66ovdx.png" alt="Base Map color for PlaneMaterial" width="235" height="508"&gt;&lt;/a&gt;&lt;/p&gt;
Base Map color for PlaneMaterial






&lt;p&gt;Now that we've created the material, it's time to assign it to the &lt;code&gt;Mesh Renderer&lt;/code&gt; of your newly created &lt;code&gt;AR Default Plane&lt;/code&gt; prefab. Edit the Prefab by double-clicking the &lt;code&gt;Ar Default Plane&lt;/code&gt; under &lt;strong&gt;Assets/Prefabs/AR Default Plane&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3hfgr9miybxmuhjt7d3d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3hfgr9miybxmuhjt7d3d.png" alt="Assigning the PlaneMaterial to the Mesh Renderer" width="386" height="415"&gt;&lt;/a&gt;&lt;/p&gt;
Assigning the PlaneMaterial to the Mesh Renderer






&lt;p&gt;If there's an existing entry in the Mesh Renderer, remove it first. Then, add &lt;code&gt;PlaneMaterial&lt;/code&gt; as &lt;code&gt;Element 0&lt;/code&gt;. This step ensures that our custom material is properly applied, allowing for the intended visual representation and debugging functionality within the AR environment.&lt;/p&gt;

&lt;p&gt;The second and final modification for our &lt;code&gt;AR Default Plane&lt;/code&gt; involves turning off the &lt;code&gt;Cast Shadows&lt;/code&gt; option. We don't want planes casting shadows on each other in our space, as this would appear unrealistic. The real environment already casts shadows, so disabling this feature ensures a more natural and coherent visual experience in our AR setup.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdnhee7izv8goh1cryhy0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdnhee7izv8goh1cryhy0.png" alt="Disable Cast Shadows on our AR Default Plane" width="389" height="598"&gt;&lt;/a&gt;&lt;/p&gt;
Disable Cast Shadows on our AR Default Plane






&lt;h2&gt;
  
  
  Testing the app
&lt;/h2&gt;

&lt;p&gt;That's all for now. We're ready to test our application. Simply hit &lt;code&gt;Build And Run&lt;/code&gt; in the Unity Editor as explained in the last articles.&lt;/p&gt;

&lt;p&gt;As shown in the upcoming screenshot, you'll see planes like the floor the couch are now rendered. Additionally, notice that raycasting is operational. In the next article about &lt;code&gt;Anchors&lt;/code&gt;, we'll focus on enhancing the color of the raycast when a hit test is successful, further refining our application.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fok84gatbp1ve4ii70rnv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fok84gatbp1ve4ii70rnv.png" alt="The app after adding planes to the scene" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;
The app after adding planes to the scene






&lt;h2&gt;
  
  
  Next article
&lt;/h2&gt;

&lt;p&gt;In our upcoming article, we will explore the critical role of Raycasts in MR environments. Raycasts are fundamental in MR for detecting and interacting with objects in a virtual space. We will cover how Raycasts work, their applications in our scenario, and how to effectively implement them in Unity.&lt;/p&gt;

</description>
      <category>unity3d</category>
      <category>mixedreality</category>
      <category>tutorial</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Unity MR Part 5: Left and Right Controllers</title>
      <dc:creator>tststs</dc:creator>
      <pubDate>Thu, 11 Jan 2024 08:50:53 +0000</pubDate>
      <link>https://dev.to/taikonauten/part-5-left-and-right-controllers-2hno</link>
      <guid>https://dev.to/taikonauten/part-5-left-and-right-controllers-2hno</guid>
      <description>&lt;p&gt;👀 Stumbled here on accident? Start with the &lt;a href="https://dev.to/taikonauten/part-0-introduction-56fl"&gt;introduction&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;📚 This article will teach you how to set up the left and right controllers for the Meta Quest 3 in Unity. This setup is essential for enabling interaction with various elements within your Unity project, enhancing the user experience on the Meta Quest 3 platform.&lt;/p&gt;




&lt;p&gt;ℹ️ If you find yourself facing any difficulties, remember that you can always refer to or download the code from our accompanying &lt;a href="https://github.com/taikonauten/unity-mr-article-series/tree/main/05_LeftAndRightControllers"&gt;GitHub repository&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;To keep the process straightforward, we'll use the starter assets from the &lt;code&gt;XR Interaction Toolkit&lt;/code&gt; plugin. This approach simplifies the setup process, focusing on achieving a practical outcome quickly and efficiently.&lt;/p&gt;




&lt;h2&gt;
  
  
  Import XR Interaction Toolkit Starter Assets
&lt;/h2&gt;

&lt;p&gt;We will utilize some of the &lt;code&gt;XR Interaction Toolkit&lt;/code&gt; starter assets in this article. Go to the &lt;code&gt;Package Manager&lt;/code&gt; via &lt;strong&gt;Window → Package Manager&lt;/strong&gt; and import &lt;code&gt;Starter Assets&lt;/code&gt; which are located in the tab &lt;code&gt;Samples&lt;/code&gt; as seen in the next screenshot.&lt;/p&gt;

&lt;p&gt;You can locate the XR Interaction Toolkit in the &lt;code&gt;Package Manager&lt;/code&gt; by accessing &lt;code&gt;Unity Registry&lt;/code&gt; and searching for 'interact'.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw6tcoux8w24pndhe0abo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw6tcoux8w24pndhe0abo.png" alt="Importing Starter Assets for the XR Interaction Toolkit" width="800" height="460"&gt;&lt;/a&gt;&lt;/p&gt;
Importing Starter Assets for the XR Interaction Toolkit






&lt;h2&gt;
  
  
  Enable the new Input System
&lt;/h2&gt;

&lt;p&gt;ℹ️ The New Input System in Unity is a flexible and extensible system designed to replace the older input methods. It provides a more unified and consistent way to handle different input devices like keyboards, mice, gamepads, and touchscreens. This system allows for more customized and complex input configurations, making it easier to develop games and applications that can be controlled across various platforms and devices.&lt;/p&gt;

&lt;p&gt;Go to your &lt;code&gt;Project Settings&lt;/code&gt; and enable the new input system. You’ll find it under &lt;code&gt;Active Input Handling&lt;/code&gt; under the section &lt;code&gt;Player&lt;/code&gt; and the tab &lt;code&gt;Other Settings&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3eav59hs34kqv50tlzdk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3eav59hs34kqv50tlzdk.png" alt="" width="800" height="551"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After selecting the new input system you will be asked to restart the Unity editor.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9dazsmopigejqkutm9rx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9dazsmopigejqkutm9rx.png" alt="" width="391" height="157"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After restarting, the new input is now active. No additional steps required for now.&lt;/p&gt;




&lt;h2&gt;
  
  
  Adding the AR Input Manager
&lt;/h2&gt;

&lt;p&gt;ℹ️ The AR Input Manager in Unity's AR Foundation is a component that manages input in AR applications. It serves as a central point for handling AR-specific input data, such as touch gestures, camera movement, and device orientation. This manager is essential for creating interactive and user-responsive AR experiences, as it efficiently processes and translates real-world user interactions into actions within the AR environment.&lt;/p&gt;

&lt;p&gt;Select the &lt;code&gt;Session&lt;/code&gt; GameObject in your hierarchy and add the &lt;code&gt;AR Input Manager&lt;/code&gt; via &lt;code&gt;Add Component&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F59ocb5vvrcm02w0p6nq7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F59ocb5vvrcm02w0p6nq7.png" alt="Our Session GameObject with the added AR Input Manager" width="505" height="504"&gt;&lt;/a&gt;&lt;/p&gt;
Our Session GameObject with the added AR Input Manager






&lt;h2&gt;
  
  
  The Input Action Manager
&lt;/h2&gt;

&lt;p&gt;The Input Action Manager in Unity is a component that handles input actions within the New Input System. It allows developers to define and manage complex input actions like button presses, gestures, or movement inputs. This manager makes it easier to organize and respond to various user inputs in a structured and efficient manner, crucial for creating responsive and interactive gaming or application experiences.&lt;/p&gt;

&lt;p&gt;ℹ️ For those interested in exploring the Input Manager in greater detail, additional information is available in the provided reference. This resource offers a comprehensive look into the functionalities and applications of the Input Manager, enhancing your understanding and proficiency in utilizing this component in your projects. &lt;a href="https://docs.unity3d.com/Packages/com.unity.inputsystem@1.7/manual/index.html"&gt;Input System | Input System | 1.7.0&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Select the &lt;code&gt;XR Origin (XR Rig)&lt;/code&gt; GameObject in your hierarchy.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyhx1h9i9znot2as9tngk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyhx1h9i9znot2as9tngk.png" alt="Add XRI Default Input Actions to the list of Action Assets&amp;lt;br&amp;gt;
" width="507" height="498"&gt;&lt;/a&gt;&lt;/p&gt;
Add XRI Default Input Actions to the list of Action Assets







&lt;p&gt;In the screenshot provided, you'll notice that we've added &lt;code&gt;XRI Default Input Actions&lt;/code&gt; to the list of &lt;code&gt;Action Assets&lt;/code&gt;. These assets were included as part of the &lt;code&gt;Starter Assets&lt;/code&gt; from the &lt;code&gt;XR Interaction Toolkit&lt;/code&gt; plugin, highlighting how the toolkit simplifies the integration of default input actions into your project.&lt;/p&gt;

&lt;p&gt;If you're curious about the specific Input Actions included in the Action Asset, simply double-click on the selected action asset. This action will reveal the details and configurations of the Input Actions, providing a clear understanding of the functionalities they encompass.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Filf3z2nlj6tb5gv44y4c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Filf3z2nlj6tb5gv44y4c.png" alt="XRI Default Input Actions in detail" width="800" height="439"&gt;&lt;/a&gt;&lt;/p&gt;
XRI Default Input Actions in detail






&lt;h2&gt;
  
  
  Adding XR Input Modality Manager
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;XR Input Modality Manager&lt;/code&gt; in Unity dynamically switches between hands and controllers during runtime, depending on their tracking status.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;if hands start being tracked, it switches to hand interactors.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;if motion controllers are activated, it switches to controller interactors once they're tracked.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;📚 This component is valuable even without hand tracking, as it deactivates controller GameObjects until they are tracked, preventing them from appearing by default.&lt;/p&gt;

&lt;p&gt;Select the &lt;code&gt;XR Origin (XR Rig)&lt;/code&gt; GameObject in your hierarchy and add the &lt;code&gt;XR Input Modality Manager&lt;/code&gt; via &lt;code&gt;Add Component&lt;/code&gt;. Select &lt;code&gt;Left Controller&lt;/code&gt; and &lt;code&gt;Right Controller&lt;/code&gt; as seen in the screenshot.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdr6nf750b8b5jcnlxm49.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdr6nf750b8b5jcnlxm49.png" alt="Selecting the left and right controller for the XR Input Modality Manager" width="366" height="775"&gt;&lt;/a&gt;&lt;/p&gt;
Selecting the left and right controller for the XR Input Modality Manager






&lt;h2&gt;
  
  
  Choose a controller preset
&lt;/h2&gt;

&lt;p&gt;For configuring the left and right controllers, we choose a controller preset imported through the starter assets. In your hierarchy select the GameObject &lt;code&gt;Left Controller&lt;/code&gt;. To select a preset, click on the two sliders as depicted in the accompanying screenshot. This step is essential for customizing the controller settings in your project, ensuring they align with the imported presets for optimal functionality and user experience.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fva3ny8u8nv2jfxdsxq0p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fva3ny8u8nv2jfxdsxq0p.png" alt="Open the preset window for the left controller" width="576" height="335"&gt;&lt;/a&gt;&lt;/p&gt;
Open the preset window for the left controller






&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp12qtuox5r41odoqzjzm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp12qtuox5r41odoqzjzm.png" alt="Selecting a preset for the left controller" width="738" height="582"&gt;&lt;/a&gt;&lt;/p&gt;
Selecting a preset for the left controller






&lt;p&gt;Similarly, for the Right Controller GameObject, follow the same process and select the corresponding preset for the right controller. This ensures that both controllers are appropriately configured with their respective presets, maintaining consistency and functionality in your setup.&lt;/p&gt;




&lt;h2&gt;
  
  
  Choose an Interaction Manager
&lt;/h2&gt;

&lt;p&gt;For the final step in setting up our controllers, we need to assign the Interaction Manager to both the left and right controllers. As shown in the forthcoming screenshot, select &lt;code&gt;XR Interaction Manager&lt;/code&gt; as the &lt;code&gt;Interaction Manager&lt;/code&gt;. This action links the controllers to the central system that manages interactions, ensuring they function correctly within the XR environment.&lt;/p&gt;

&lt;p&gt;ℹ️ &lt;code&gt;Interaction Manager&lt;/code&gt;: The XR Interaction Manager that this interactor will communicate with.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz8iqdqz7e3gg5a8443z4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz8iqdqz7e3gg5a8443z4.png" alt="Selecting the XR Interaction Manager as the Interaction Manager" width="370" height="776"&gt;&lt;/a&gt;&lt;/p&gt;
Selecting the XR Interaction Manager as the Interaction Manager






&lt;p&gt;Similarly, for the Right Controller GameObject, follow the same process and select &lt;code&gt;XR Interaction Manager&lt;/code&gt; as the &lt;code&gt;Interaction Manager&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Testing the app
&lt;/h2&gt;

&lt;p&gt;Run your Unity project via &lt;code&gt;Build And Run&lt;/code&gt; as explained in the last article. You should now see the Unity project running in your headset as seen in the next screenshot. Move your Meta Quest 3 controllers to verify if everything is working as expected.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F38kvujag1jqfdrx9g1c5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F38kvujag1jqfdrx9g1c5.png" alt="Testing the app if our controllers work" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;
Testing the app if our controllers work






&lt;h2&gt;
  
  
  Next article
&lt;/h2&gt;

&lt;p&gt;In our next article, we will delve into the aspect of detecting planes in MR environments. Plane detection is a cornerstone of MR, allowing virtual content to be realistically placed and interacted with in the physical world. We will explore how this technology works and the ways you can implement plane detection in your projects using Unity.&lt;/p&gt;

</description>
      <category>unity3d</category>
      <category>mixedreality</category>
      <category>tutorial</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Unity MR Part 4: Enter MR</title>
      <dc:creator>tststs</dc:creator>
      <pubDate>Thu, 11 Jan 2024 08:50:48 +0000</pubDate>
      <link>https://dev.to/taikonauten/part-4-enter-mr-1ie4</link>
      <guid>https://dev.to/taikonauten/part-4-enter-mr-1ie4</guid>
      <description>&lt;p&gt;👀 Stumbled here on accident? Start with the &lt;a href="https://dev.to/taikonauten/part-0-introduction-56fl"&gt;introduction&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;📚 In this article, you will learn the setup process for URP (Universal Render Pipeline) and the camera configuration necessary to enable passthrough functionality. This guide will provide step-by-step instructions to ensure that passthrough operates effectively in your project, essential for creating immersive augmented reality experiences.&lt;/p&gt;




&lt;p&gt;ℹ️ If you find yourself facing any difficulties, remember that you can always refer to or download the code from our accompanying &lt;a href="https://github.com/taikonauten/unity-mr-article-series/tree/main/04_EnterMR"&gt;GitHub repository&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;To activate passthrough in our Android build, adjustments are required for the camera and URP asset. The camera's &lt;code&gt;Background Type&lt;/code&gt; should be set to solid color, but to enable passthrough, modify the &lt;code&gt;Background&lt;/code&gt; color's alpha value to 0. This can be done by clicking on the black bar to access the color picker, as demonstrated in the following two screenshots.&lt;/p&gt;

&lt;p&gt;ℹ️ &lt;code&gt;Background&lt;/code&gt;: the Camera clears its color buffer to this color before rendering.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F62fbymvxb6ktd0rlvkiw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F62fbymvxb6ktd0rlvkiw.png" alt="Camera component in the Environment section" width="403" height="530"&gt;&lt;/a&gt;&lt;/p&gt;
Camera component in the Environment section






&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffg51ilt2jhj4yvde13o0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffg51ilt2jhj4yvde13o0.png" alt="Color picker for the Background clear color" width="235" height="508"&gt;&lt;/a&gt;&lt;/p&gt;
Color picker for the Background clear color






&lt;p&gt;Close the color picker, access the Project Settings by navigating to &lt;strong&gt;Edit → Project Settings&lt;/strong&gt;, then proceed to the Quality section. You will notice that the Balanced level is set as the standard quality for our Android build.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F00okdqtnqjpsjgznw4ao.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F00okdqtnqjpsjgznw4ao.png" alt="Project Settings Quality" width="800" height="562"&gt;&lt;/a&gt;&lt;/p&gt;
Project Settings Quality






&lt;p&gt;The Balanced URP Asset features an HDR (High Dynamic Range) option that is unsupported and results in passthrough being unavailable. To rectify this, disable HDR in your URP-Balanced asset, located under &lt;strong&gt;Assets/Settings&lt;/strong&gt; under &lt;code&gt;Project&lt;/code&gt;. This adjustment is crucial for ensuring that passthrough functionality is enabled correctly in your project.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F04y364lqeli9480u0yhk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F04y364lqeli9480u0yhk.png" alt="Disable HDR in URP-Balanced" width="403" height="350"&gt;&lt;/a&gt;&lt;/p&gt;
Disable HDR in URP-Balanced






&lt;h2&gt;
  
  
  Testing the app
&lt;/h2&gt;

&lt;p&gt;That's all for now. We're ready to test our application. From now on we need to build the application and deploy it to the Meta Quest 3 since Passthrough is not available via hitting Play.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsfrlxcf0y80t7s93wo1g.png" alt="" width="800" height="505"&gt;
&lt;/h2&gt;

&lt;p&gt;Ensure that all configurations are correctly set by navigating to &lt;strong&gt;File → Build Settings&lt;/strong&gt;. Once you've verified these settings, simply click on &lt;code&gt;Build And Run&lt;/code&gt; to proceed.&lt;/p&gt;

&lt;p&gt;You should now see the Unity project running in your headset as seen in the next screenshot.&lt;/p&gt;

&lt;p&gt;Passthrough is now successfully enabled in our Android build, as evidenced by the recent adjustments. This achievement marks a significant step in ensuring that the application functions with the desired augmented reality capabilities on Android devices.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbpl9r5o9u1poxunu9fh8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbpl9r5o9u1poxunu9fh8.png" alt="Entering MR in our office" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;
Entering MR in our office






&lt;h2&gt;
  
  
  Next article
&lt;/h2&gt;

&lt;p&gt;In our upcoming article, we will focus on configuring the left and right controllers for the Meta Quest 3. This step is crucial for creating a responsive and intuitive user experience in virtual reality. We'll guide you through the process of setting up these controllers in Unity, discussing how to map their buttons.&lt;/p&gt;

</description>
      <category>unity3d</category>
      <category>mixedreality</category>
      <category>tutorial</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Unity MR Part 3: Camera Component</title>
      <dc:creator>tststs</dc:creator>
      <pubDate>Wed, 10 Jan 2024 17:21:31 +0000</pubDate>
      <link>https://dev.to/taikonauten/part-3-camera-component-1gfc</link>
      <guid>https://dev.to/taikonauten/part-3-camera-component-1gfc</guid>
      <description>&lt;p&gt;👀 Stumbled here on accident? Start with the &lt;a href="https://dev.to/taikonauten/part-0-introduction-56fl"&gt;introduction&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;📚 This article will guide you through understanding cameras in the context of MR and their implementation in Unity. It covers adding the camera to a scene and examines the &lt;code&gt;XR Origin (AR)&lt;/code&gt; Prefab, providing essential insights for integrating cameras effectively in MR environments using Unity.&lt;/p&gt;




&lt;p&gt;ℹ️ If you find yourself facing any difficulties, remember that you can always refer to or download the code from our accompanying &lt;a href="https://github.com/taikonauten/unity-mr-article-series/tree/main/03_CameraComponent" rel="noopener noreferrer"&gt;GitHub repository&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;In Unity, the camera is a crucial component for creating visual experiences in both traditional game development and MR. It acts as the viewer's eye, determining what is seen on the screen. In MR, the camera not only renders the virtual environment but is often integrated with real-world inputs, allowing for a seamless blend of physical and digital elements.&lt;/p&gt;

&lt;p&gt;The camera in AR Foundation for Unity is crucial for AR applications, offering features like camera components, image capture, and accessing EXIF data from device cameras​​. The Unity OpenXR Meta plugin supplements this by focusing on Meta Quest devices.&lt;/p&gt;

&lt;p&gt;On Meta Quest devices, AR Foundation's Camera subsystem controls &lt;code&gt;Meta Passthrough&lt;/code&gt;. Enable the &lt;code&gt;AR Camera Manager&lt;/code&gt; component to enable Passthrough, and disable it to disable Passthrough.&lt;/p&gt;




&lt;h2&gt;
  
  
  Adding a Camera to the Scene
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt; Remove the default &lt;code&gt;Main Camera&lt;/code&gt; from the hierarchy.&lt;/li&gt;
&lt;li&gt; Create an empty GameObject &lt;code&gt;MR&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt; Move the &lt;code&gt;Session&lt;/code&gt; GameObject into the newly created &lt;code&gt;MR&lt;/code&gt; GameObject&lt;/li&gt;
&lt;li&gt; In the hierarchy view right click the &lt;code&gt;MR&lt;/code&gt; GameObject and select &lt;strong&gt;XR → XR Origin (AR)&lt;/strong&gt;. After adding the XR Origin your scene should look like as follows:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F21oskpbwwz302vja2fy3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F21oskpbwwz302vja2fy3.png" alt="Scene after adding the XR Origin (XR Rig)"&gt;&lt;/a&gt;&lt;/p&gt;
Scene after adding the XR Origin (XR Rig)






&lt;p&gt;The &lt;code&gt;XR Origin (XR Rig)&lt;/code&gt; Prefab is composed of a &lt;code&gt;Camera Offset&lt;/code&gt;, &lt;code&gt;Main Camera&lt;/code&gt;, and two GameObjects for the left and right controllers. We will delve into the &lt;code&gt;XR Origin (XR Rig)&lt;/code&gt; Prefab in this article, and the subsequent article in this series will cover the setup of both controllers in more detail.&lt;/p&gt;

&lt;p&gt;You'll observe that an &lt;code&gt;XR Interaction Manager&lt;/code&gt; has been automatically generated in your scene.&lt;/p&gt;

&lt;p&gt;ℹ️ The XR Interaction Manager in Unity is a central component that manages interactive elements in XR (Extended Reality) environments. It handles the interactions between the user and virtual objects, including input from controllers and headsets. This manager coordinates actions like grabbing, touching, or selecting objects, ensuring smooth and intuitive interaction within the virtual world, which is essential for creating immersive and responsive XR experiences.&lt;/p&gt;

&lt;p&gt;We’ll get back to the &lt;code&gt;XR Interaction Manager&lt;/code&gt; in the next article.&lt;/p&gt;




&lt;h2&gt;
  
  
  Exploring the XR Origin (AR) Prefab
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh3qs9rr1emrkkm8j5xzg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh3qs9rr1emrkkm8j5xzg.png" alt="The XR Origin (XR Rig) GameObject in the inspector"&gt;&lt;/a&gt;&lt;/p&gt;
The XR Origin (XR Rig) GameObject in the inspector






&lt;h3&gt;
  
  
  XR Origin (XR Rig)
&lt;/h3&gt;

&lt;p&gt;The XR Origin represents the &lt;code&gt;session-space origin&lt;/code&gt; (0, 0, 0) in an XR scene.&lt;/p&gt;

&lt;p&gt;ℹ️ &lt;code&gt;session-space origin&lt;/code&gt; refers to the reference point or coordinate system that is established when an XR session starts. This origin is used to define the positions and orientations of objects and users within the virtual environment. It's crucial for accurately placing and moving virtual elements in relation to the real world or the user's environment, ensuring a coherent and immersive experience in XR applications.&lt;/p&gt;

&lt;p&gt;The XR Origin component is typically attached to the base object of the XR Origin, and stores the GameObject that will be manipulated via &lt;code&gt;locomotion&lt;/code&gt;. It is also used for offsetting the camera.&lt;/p&gt;

&lt;p&gt;ℹ️ &lt;code&gt;Locomotion&lt;/code&gt; refers to the methods by which a user moves within a virtual environment. This can include physical movements, like walking or turning, which are tracked and translated into movement within the virtual space. Alternatively, it can involve virtual movement methods such as teleportation, sliding, or using a controller to navigate. Effective locomotion techniques are key to creating a comfortable and immersive XR experience.&lt;/p&gt;




&lt;h3&gt;
  
  
  XROrigin Script fields
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Field&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Description&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Origin Base GameObject&lt;/td&gt;
&lt;td&gt;The &lt;code&gt;Origin&lt;/code&gt; GameObject is used to refer to the base of the XR Origin, by default it is this GameObject. This is the GameObject that will be manipulated via locomotion.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Camera Floor Offset Object&lt;/td&gt;
&lt;td&gt;The GameObject to move to desired height off the floor (defaults to this object if none provided). This is used to transform the XR device from camera space to XR Origin space.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Camera&lt;/td&gt;
&lt;td&gt;The Camera used to render the scene from the point of view of the XR device. Must be a child of the GameObject containing this XROrigin component.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tracking Origin Mode&lt;/td&gt;
&lt;td&gt;Sets which Tracking Origin Mode to use when initializing the input device.&lt;br&gt;&lt;br&gt;&lt;code&gt;NotSpecified&lt;/code&gt;: Uses the default Tracking Origin Mode of the input device.&lt;br&gt;&lt;br&gt;&lt;code&gt;Device&lt;/code&gt;: Input devices will be tracked relative to the first known location.&lt;br&gt;&lt;br&gt;&lt;code&gt;Floor&lt;/code&gt;: Input devices will be tracked relative to a location on the floor&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Camera Y Offset&lt;/td&gt;
&lt;td&gt;Camera height to be used when in &lt;code&gt;Device&lt;/code&gt; Tracking Origin Mode to define the height of the user from the floor.&lt;br&gt;&lt;br&gt;This is the amount that the camera is offset from the floor when moving the &lt;code&gt;CameraFloorOffsetObject&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Main Camera
&lt;/h3&gt;

&lt;p&gt;Let's examine the Main Camera component, focusing specifically on the additional scripts and systems essential for creating a MR experience. This article will not cover the basic aspects of Unity's Camera component. Instead, it will delve into the &lt;code&gt;AR Camera Manager&lt;/code&gt;, &lt;code&gt;AR Camera Background&lt;/code&gt; and &lt;code&gt;Tracked Pose Driver&lt;/code&gt;, which are crucial for implementing an MR experience.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Febuaxr2xi7fpe6lpac4z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Febuaxr2xi7fpe6lpac4z.png" alt="The Main Camera in the inspector"&gt;&lt;/a&gt;&lt;/p&gt;
The Main Camera in the inspector






&lt;h4&gt;
  
  
  AR Camera Manager
&lt;/h4&gt;

&lt;p&gt;This component controls &lt;code&gt;Passthrough&lt;/code&gt; on Meta Quest devices. Enable this component to enable &lt;code&gt;Passthrough&lt;/code&gt;, and disable it to disable &lt;code&gt;Passthrough&lt;/code&gt;. Properties such as Auto Focus and Facing Direction have no effect on Meta Quest devices.&lt;/p&gt;

&lt;p&gt;ℹ️ &lt;code&gt;Passthrough&lt;/code&gt; refers to a technology that allows users to see the real world through their headset's cameras while still being in a virtual or augmented environment. This blending of real-world visuals with virtual elements helps create a mixed reality experience, enabling users to interact with both physical and digital objects, enhancing safety and immersion.&lt;/p&gt;




&lt;h4&gt;
  
  
  AR Camera Background
&lt;/h4&gt;

&lt;p&gt;This component has no effect on Meta Quest devices, so we disable it as seen in the above screenshot (checkmark next to &lt;code&gt;AR Camera Background)&lt;/code&gt;.&lt;/p&gt;




&lt;h4&gt;
  
  
  Tracked Pose Driver (Input System)
&lt;/h4&gt;

&lt;p&gt;The &lt;code&gt;Tracked Pose Driver&lt;/code&gt; is a component used in XR development. It tracks the position and rotation of the headset or controller, and applies these transformations to a GameObject in Unity. This allows the GameObject to mirror the real-world movements of the device.&lt;/p&gt;

&lt;p&gt;In our scenario, the current pose value of the tracked device is applied to the Transform of the &lt;code&gt;Main Camera&lt;/code&gt;. This ensures that the camera's position and orientation in the virtual environment accurately reflect the real-world movements of the tracked device, enhancing the realism and interactivity of the experience.&lt;/p&gt;




&lt;h2&gt;
  
  
  Testing the app
&lt;/h2&gt;

&lt;p&gt;Run your Unity project as explained in the last article &lt;code&gt;Session Component&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You should now see the Unity project running in your headset as seen in the next screenshot.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fazcdol3poumg8a2gmhf2.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fazcdol3poumg8a2gmhf2.jpeg" alt="Result after adding the XR Origin (XR Rig) to our scene"&gt;&lt;/a&gt;&lt;/p&gt;
Result after adding the XR Origin (XR Rig) to our scene






&lt;p&gt;Since we're utilizing Meta Quest Link, passthrough functionality is not available, when running the app from within the Unity Editor. The red lines represent the left and right controllers, automatically integrated via the XR Origin Prefab.&lt;/p&gt;

&lt;p&gt;Additionally, the black background is a consequence of the solid color setting, configured through the Environment section of our camera component, resulting in this specific visual effect.&lt;/p&gt;




&lt;h2&gt;
  
  
  Next article
&lt;/h2&gt;

&lt;p&gt;In our next article, we're excited to introduce the concept of Passthrough technology, a pivotal feature for entering the realm of MR. Passthrough acts as a bridge between the virtual and real worlds, allowing users to see their physical environment through a digital lens.&lt;/p&gt;

</description>
      <category>unity3d</category>
      <category>mixedreality</category>
      <category>tutorial</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Unity MR Part 2: Session Component</title>
      <dc:creator>tststs</dc:creator>
      <pubDate>Wed, 10 Jan 2024 17:12:24 +0000</pubDate>
      <link>https://dev.to/taikonauten/part-2-session-component-1pko</link>
      <guid>https://dev.to/taikonauten/part-2-session-component-1pko</guid>
      <description>&lt;p&gt;👀 Stumbled here on accident? Start with the &lt;a href="https://dev.to/taikonauten/part-0-introduction-56fl"&gt;introduction&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;📚 In this article, you'll discover the concept of a session in MR and how to apply it in Unity. We'll discuss differences in sessions in ARFoundation and OpenXR: Meta, set up our Session GameObject, and conduct tests on the Meta Quest 3. This exploration will provide a comprehensive understanding of session management in Unity for MR applications, especially for the Meta Quest 3 platform.&lt;/p&gt;




&lt;p&gt;ℹ️ If you find yourself facing any difficulties, remember that you can always refer to or download the code from our accompanying &lt;a href="https://github.com/taikonauten/unity-mr-article-series/tree/main/02_SessionComponent" rel="noopener noreferrer"&gt;GitHub repository&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;A session refers to the period during which the app is actively tracking and integrating real-world and virtual environments, handling user interactions, and maintaining continuity in the mixed reality experience.&lt;/p&gt;




&lt;h2&gt;
  
  
  About Session in ARFoundation
&lt;/h2&gt;

&lt;p&gt;In AR Foundation, the AR Session component is crucial for controlling the lifecycle of an AR experience on the target platform. It represents an instance of AR, and other features like plane detection can be independently enabled or disabled within this framework. The AR Session component is responsible for tracking features in the environment. When this component is disabled, the system stops tracking these features, but if re-enabled later, it attempts to recover and maintain the previously detected features. It's important to note that multiple AR Session components in the same scene can conflict with each other, so it's recommended to add at most one AR Session component to a scene.&lt;/p&gt;

&lt;p&gt;The AR Session component also checks for device support. Since some platforms have built-in AR capabilities, while others may require on-demand installation of AR software or might not support AR at all, it's vital for applications to detect support for AR Foundation to provide alternative experiences when AR is not supported. This might involve checking a remote server for software availability.&lt;/p&gt;

&lt;p&gt;The AR Session state can be monitored using &lt;code&gt;ARSession.state&lt;/code&gt;, and you can subscribe to the &lt;code&gt;ARSession.stateChanged&lt;/code&gt; event to receive callbacks when the state changes. This state includes various statuses like &lt;code&gt;None&lt;/code&gt;, &lt;code&gt;Unsupported&lt;/code&gt;, &lt;code&gt;CheckingAvailability&lt;/code&gt;, &lt;code&gt;NeedsInstall&lt;/code&gt;, &lt;code&gt;Installing&lt;/code&gt;, &lt;code&gt;Ready&lt;/code&gt;, &lt;code&gt;SessionInitializing&lt;/code&gt;, and &lt;code&gt;SessionTracking&lt;/code&gt;, each indicating different stages of AR session readiness and functionality.&lt;/p&gt;




&lt;h2&gt;
  
  
  About Session in OpenXR: Meta
&lt;/h2&gt;

&lt;p&gt;In the context of OpenXR: Meta, the Session is a supplement to the AR Foundation Session manual, focusing on the unique platform-specific behavior of the Meta Quest. This includes a feature called &lt;code&gt;Scene Capture&lt;/code&gt;, where, unlike other AR platforms, OpenXR: Meta does not dynamically detect trackables at runtime. Instead, it queries the device's Room Setup data and returns information stored in the Scene Model. During scene capture, users can label surfaces and objects in their environment, like walls and furniture. Once the scene capture is complete, the Scene Model is saved to the device and persists across applications and sessions.&lt;/p&gt;

&lt;p&gt;The lifecycle of scene capture in OpenXR: Meta involves several phases: initiating scene capture, suspension of the app during capture, completion of scene capture by the user, and resumption of the app post-capture.&lt;/p&gt;

&lt;p&gt;These features highlight the comprehensive nature of AR Session components in managing and maintaining AR experiences in Unity's AR Foundation and OpenXR: Meta, showcasing the advancements and unique aspects of AR technology in different platforms.&lt;/p&gt;




&lt;h2&gt;
  
  
  Adding the Session component to the scene
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Create an Empty GameObject
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt; First, open your Unity project.&lt;/li&gt;
&lt;li&gt; In the Unity editor, go to the Hierarchy panel.&lt;/li&gt;
&lt;li&gt; Right-click in the Hierarchy panel and select "Create Empty" to create a new GameObject and name it &lt;code&gt;Session&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt; This GameObject will act as a container for your AR components.&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  Add the AR Session Script
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt; With the new GameObject selected, go to the Inspector panel.&lt;/li&gt;
&lt;li&gt; Click on "Add Component".&lt;/li&gt;
&lt;li&gt; Search for “AR Session” and add it to your GameObject.&lt;/li&gt;
&lt;li&gt; The AR Session component is essential for managing the AR experience, including tracking and session management.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Initially, you'll be using the default settings of the AR Session component. These defaults are usually sufficient for basic AR experiences.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fac6j0r2t1yzioayhap8u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fac6j0r2t1yzioayhap8u.png" alt="The hierarchy after adding the Session Component"&gt;&lt;/a&gt;&lt;/p&gt;
The hierarchy after adding the Session Component






&lt;p&gt;ℹ️ You might observe that we are using a custom layout in the Unity Editor, which means that the screenshots provided may not exactly match the appearance of your Editor. Keep in mind that while the visual layout may vary, the fundamental features and functions of Unity remain consistent across different customizations.&lt;/p&gt;




&lt;h2&gt;
  
  
  Check for device support
&lt;/h2&gt;

&lt;p&gt;Select the &lt;code&gt;Session&lt;/code&gt; GameObject in your hierarchy. Create a new script &lt;code&gt;DeviceSupport&lt;/code&gt; via &lt;code&gt;Add Component&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Let's verify if the connected device is AR-capable. As this course focuses on the Meta Quest 3, AR support is typically guaranteed. By setting &lt;code&gt;attemptUpdate = true&lt;/code&gt;, the device will attempt to install AR software if feasible. However, the availability of this feature is dependent on the platform.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;DeviceSupport&lt;/code&gt; looks as follows:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;

&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Collections&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Collections.Generic&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;UnityEngine&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;UnityEngine.XR.ARFoundation&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;Taikonauten.Unity.ArticleSeries&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DeviceSupport&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;MonoBehaviour&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;SerializeField&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="n"&gt;ARSession&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="n"&gt;IEnumerator&lt;/span&gt; &lt;span class="nf"&gt;Start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;attemptUpdate&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;Debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;LogError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"DeviceSupport -&amp;gt; Start(): session is null"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

                &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;

            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;ARSession&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;ARSessionState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;None&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;||&lt;/span&gt;
                &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ARSession&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;ARSessionState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CheckingAvailability&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;Debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"DeviceSupport -&amp;gt; Start(): check availability"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

                &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;ARSession&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CheckAvailability&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;

            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ARSession&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;ARSessionState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Unsupported&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="c1"&gt;// Start some fallback experience for unsupported devices&lt;/span&gt;
                &lt;span class="n"&gt;Debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"DeviceSupport -&amp;gt; Start(): unsupported device"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="k"&gt;else&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="c1"&gt;// Start the AR session&lt;/span&gt;
                &lt;span class="n"&gt;Debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"DeviceSupport -&amp;gt; Start(): start AR session"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

                &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;enabled&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;



&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;To prevent any potential naming conflicts, we will adopt the namespace &lt;code&gt;Taikonauten.Unity.ArticleSeries&lt;/code&gt; for all our scripts moving forward.&lt;/p&gt;

&lt;p&gt;ℹ️ This practice will ensure a clear and organized code structure, helping to distinguish our script elements effectively within the project. Using a specific namespace like &lt;code&gt;Taikonauten.Unity.ArticleSeries&lt;/code&gt; is a best practice in software development for maintaining code clarity and avoiding clashes with other code entities.&lt;/p&gt;

&lt;p&gt;In the Unity Editor, choose &lt;code&gt;Session (AR Session)&lt;/code&gt; as the value for the &lt;code&gt;Session&lt;/code&gt; field for your newly created script. Your &lt;code&gt;Session&lt;/code&gt; GameObject should now resemble the appearance shown in the following screenshot.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgbrygqrkb3540ji8i7ru.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgbrygqrkb3540ji8i7ru.png" alt="Inspector window of the Session GameObject"&gt;&lt;/a&gt;&lt;/p&gt;
Inspector window of the Session GameObject






&lt;p&gt;To maintain an organized project structure, create a &lt;code&gt;Scripts&lt;/code&gt; folder within the Assets directory in the Project window. Then, move the &lt;code&gt;DeviceSupport&lt;/code&gt; Script into this new folder. This approach helps in keeping your project tidy and ensures that all scripts are conveniently located in a dedicated folder.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp957q7rdhys0f6c5epgq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp957q7rdhys0f6c5epgq.png" alt="Moving the DeviceSupport script into the Scripts folder"&gt;&lt;/a&gt;&lt;/p&gt;
Moving the DeviceSupport script into the Scripts folder






&lt;h2&gt;
  
  
  Testing the app
&lt;/h2&gt;

&lt;p&gt;To run a Unity project on your Meta Quest 3 using the Link Cable, follow these steps:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Connect the Meta Quest 3 to Your PC&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Use the Link Cable to connect your Meta Quest 3 headset to your computer.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;2. Enable Oculus Link on Your Headset&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Put on your Meta Quest 3 headset and enable Oculus Link when prompted. This will connect your headset to the Unity Editor running on your PC.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;3. Press the Play Button in Unity&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Go back to the Unity Editor on your PC and press the 'Play' button. This will start running your Unity project directly in your Meta Quest 3 headset.&lt;/p&gt;

&lt;p&gt;ℹ️ If you're using a Mac, the standard approach might not work. Instead, use &lt;strong&gt;File → Build and Run&lt;/strong&gt; while the Meta Quest 3 is connected to your computer. We cover this process in the article &lt;code&gt;Enter MR&lt;/code&gt;, specifically in the &lt;code&gt;Testing the App&lt;/code&gt; section&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;4. View the Output in Your Headset&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You should now see the Unity project running in your headset as seen in the next screenshot.&lt;/p&gt;

&lt;p&gt;If you encounter any issues, ensure that your Meta Quest 3 is set up correctly with your PC, the Oculus software is installed and up to date, and your Unity project is configured for Oculus VR development.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fstpq2co2p1udettdkhvp.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fstpq2co2p1udettdkhvp.jpeg"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;⚠️ &lt;code&gt;No active UnityEngine.XR.ARSubsystems.XRSessionSubsystem is available. This feature is either not supported on the current platform, or you may need to enable a provider in Project Settings &amp;gt; XR Plug-in Management.  &lt;br&gt;
UnityEngine.XR.ARFoundation.ARSession:OnEnable () (at ./Library/PackageCache/com.unity.xr.arfoundation@6.0.0-pre.4/Runtime/ARFoundation/ARSession.cs:331)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The message you're seeing in the Unity Editor Console is a warning that can be safely ignored. It's indicating that the &lt;code&gt;XRSessionSubsystem&lt;/code&gt; is only available in built applications for their specific build targets, which is Android in this case. This means that the &lt;code&gt;XRSessionSubsystem&lt;/code&gt;, a component used for handling XR (Extended Reality) sessions, won't be available or functional within the Unity Editor itself, but it will work as expected once the application is built and deployed to the Meta Quest 3.&lt;/p&gt;




&lt;h2&gt;
  
  
  Next article
&lt;/h2&gt;

&lt;p&gt;In our upcoming article, we will delve into the integral aspects of the Camera Component in Unity, especially in the context of AR and VR development. The Camera Component is a fundamental part of any immersive experience, acting as the eyes of the user in the virtual world. We'll explore its capabilities, how it can be configured and manipulated to suit our needs.&lt;/p&gt;

</description>
      <category>unity3d</category>
      <category>mixedreality</category>
      <category>tutorial</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Unity MR Part 1: Setting up Unity</title>
      <dc:creator>tststs</dc:creator>
      <pubDate>Wed, 10 Jan 2024 10:11:57 +0000</pubDate>
      <link>https://dev.to/taikonauten/part-1-setting-up-unity-2h83</link>
      <guid>https://dev.to/taikonauten/part-1-setting-up-unity-2h83</guid>
      <description>&lt;p&gt;👀 Stumbled here on accident? Start with the &lt;a href="https://dev.to/taikonauten/part-0-introduction-56fl"&gt;introduction&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;📚 This article provides a comprehensive guide on setting up Unity for MR development with the Meta Quest 3. It covers the installation of Unity, creation of a new 3D project, installation of necessary packages, and configuration of the XR-Plug-in, equipping you with the foundational steps needed to begin developing MR applications on the Meta Quest 3 platform using Unity.&lt;/p&gt;




&lt;p&gt;ℹ️ If you find yourself facing any difficulties, remember that you can always refer to or download the code from our accompanying &lt;a href="https://github.com/taikonauten/unity-mr-article-series/tree/main/01_SettingUpUnity" rel="noopener noreferrer"&gt;GitHub repository&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  About Unity
&lt;/h2&gt;

&lt;p&gt;Unity offers a robust and flexible development platform for MR applications, providing extensive support for immersive experiences with its advanced rendering capabilities, comprehensive asset library, and wide-ranging compatibility with various MR hardware.&lt;/p&gt;




&lt;h2&gt;
  
  
  Install Unity Editor via Unity Hub
&lt;/h2&gt;

&lt;p&gt;Install &lt;a href="https://unity.com/unity-hub" rel="noopener noreferrer"&gt;Unity Hub&lt;/a&gt;, create an account and get Unity &lt;code&gt;2023.2.3f1&lt;/code&gt; with &lt;code&gt;Android Build Support&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;ℹ️ If you're wondering why Android build support is necessary, it's because the Meta Quest 3 operates on a modified version of Android 12.&lt;/p&gt;

&lt;p&gt;We are using the latest &lt;code&gt;2023.2.3f1&lt;/code&gt; build to have access to &lt;code&gt;ARFoundation 6.0&lt;/code&gt;. You can read more about the topic here: &lt;a href="https://docs.unity3d.com/Packages/com.unity.xr.arfoundation@6.0/manual/project-setup/edit-your-project-manifest.html" rel="noopener noreferrer"&gt;Access AR Foundation 6.0 in Unity 2023.2 | AR Foundation | 6.0.0-pre.5&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj4he424gwsljzkj0bxiu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj4he424gwsljzkj0bxiu.png" alt="Install the Unity Editor and choosing Android build support&amp;lt;br&amp;gt;
"&gt;&lt;/a&gt;&lt;/p&gt;
Install the Unity Editor and choosing Android build support






&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwgnebrv7td5eprkerf2f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwgnebrv7td5eprkerf2f.png" alt="Installs tab after successful installation of the Unity Editor&amp;lt;br&amp;gt;
"&gt;&lt;/a&gt;&lt;/p&gt;
Installs tab after successful installation of the Unity Editor






&lt;h2&gt;
  
  
  Create a new Unity 3D (URP) project
&lt;/h2&gt;

&lt;p&gt;This series of articles will utilize the &lt;code&gt;Universal Render Pipeline (URP)&lt;/code&gt; instead of the default render pipeline.&lt;/p&gt;

&lt;p&gt;ℹ️ If you're unfamiliar with URP, or the Universal Render Pipeline in Unity, you can gain a thorough overview by following this link: &lt;a href="https://unity.com/srp/universal-render-pipeline" rel="noopener noreferrer"&gt;Universal Render Pipeline (URP) | Unity&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Create a new project &lt;code&gt;3D (URP)&lt;/code&gt; within the Projects tab. Make sure you select the Editor Version &lt;code&gt;2023.2.3f1&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8l00j5xnzittoom7cjp0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8l00j5xnzittoom7cjp0.png" alt="Creating an new project using the 3D (URP) template"&gt;&lt;/a&gt;&lt;/p&gt;
Creating an new project using the 3D (URP) template






&lt;h2&gt;
  
  
  Install required packages
&lt;/h2&gt;

&lt;p&gt;Open your projects &lt;code&gt;manifest.json&lt;/code&gt; file and append the following required packages.&lt;/p&gt;

&lt;p&gt;ℹ️ To find the &lt;code&gt;manifest.json&lt;/code&gt; file in Unity, you need to navigate to your Unity project's directory on your computer. Inside the project folder, look for the &lt;code&gt;Packages&lt;/code&gt; folder. The &lt;code&gt;manifest.json&lt;/code&gt; file will be located within this folder. This file is used to manage project dependencies and Unity package versions, making it a critical part of Unity project configuration.&lt;/p&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"com.unity.xr.arfoundation": "6.0.0-pre.4",
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;    "com.unity.xr.interaction.toolkit": "2.5.2",&lt;br&gt;
    "com.unity.xr.meta-openxr": "1.0.1",&lt;br&gt;
    "com.unity.xr.openxr": "1.9.1"&lt;/p&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F43dpl38xhxq0vqveudxl.png"&gt;&lt;br&gt;
&lt;/h2&gt;

&lt;p&gt;Save the file and return to the Unity Editor. If you get the following warning choose ‘yes’.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9zlwglcurfz1su0ztiem.png"&gt;
&lt;/h2&gt;

&lt;h2&gt;
  
  
  Configure the XR-Plug-in
&lt;/h2&gt;

&lt;p&gt;Find the &lt;code&gt;XR Plug-in Management&lt;/code&gt; settings via &lt;strong&gt;Edit → Project Settings&lt;/strong&gt;. Make sure to edit both &lt;code&gt;Windows, Mac, Linux (Desktop)&lt;/code&gt; settings and &lt;code&gt;Android&lt;/code&gt; settings.&lt;/p&gt;

&lt;p&gt;First configure &lt;code&gt;Desktop&lt;/code&gt; by enabling &lt;code&gt;OpenXR&lt;/code&gt; as seen in the next screenshot.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F314vvu091vm40m7xzc1u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F314vvu091vm40m7xzc1u.png" alt="Enabling OpenXR in XR Plug-in Management for Desktop"&gt;&lt;/a&gt;&lt;/p&gt;
Enabling OpenXR in XR Plug-in Management for Desktop






&lt;p&gt;Then, switch to &lt;code&gt;Android&lt;/code&gt; and also enable &lt;code&gt;OpenXR&lt;/code&gt; and the &lt;code&gt;Meta Quest feature group&lt;/code&gt; as seen n the next screenshot.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgqw2bscmgr1ts5gdm8sm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgqw2bscmgr1ts5gdm8sm.png" alt="Enabling OpenXR in XR Plug-in Management for Android"&gt;&lt;/a&gt;&lt;/p&gt;
Enabling OpenXR in XR Plug-in Management for Android






&lt;p&gt;Add the &lt;code&gt;Meta Quest Touch Pro Controller Profile&lt;/code&gt; to the list of &lt;code&gt;Enabled Interaction Profiles&lt;/code&gt; for Desktop and Android build. For details on the available controls, refer to the &lt;a href="https://docs.unity3d.com/Packages/com.unity.xr.openxr@1.9/manual/features/metaquesttouchprocontrollerprofile.html" rel="noopener noreferrer"&gt;Meta Quest Pro Touch Controller Profile | OpenXR Plugin | 1.9.1&lt;/a&gt; documentation.&lt;/p&gt;

&lt;p&gt;For desktop we only need to add the controller profile as seen in the next screenshot.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd34tjnjnk2whhx6oyr5h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd34tjnjnk2whhx6oyr5h.png" alt="Adding the Meta Quest Touch Pro Controller Profile for Desktop"&gt;&lt;/a&gt;&lt;/p&gt;
Adding the Meta Quest Touch Pro Controller Profile for Desktop






&lt;p&gt;Switch to the &lt;code&gt;Android&lt;/code&gt; tab, add the controller profile and enable all features in the &lt;code&gt;Meta Quest&lt;/code&gt; feature group. The features are most likely already enabled.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkuah7nlzsm857v0z9f10.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkuah7nlzsm857v0z9f10.png" alt="Adding the Meta Quest Touch Pro Controller Profile for Android"&gt;&lt;/a&gt;&lt;/p&gt;
Adding the Meta Quest Touch Pro Controller Profile for Android






&lt;p&gt;At present, you might come across one or more issues during the Project Validation process. To address these, use the &lt;code&gt;Fix All&lt;/code&gt; option. However, be aware that &lt;code&gt;Fix All&lt;/code&gt; won't resolve all warnings in your project, as depicted in the forthcoming screenshots. This situation is acceptable, as we will be addressing and resolving these warnings manually throughout the course of our article series.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyt5ptlo4x66eh93bsigz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyt5ptlo4x66eh93bsigz.png" alt="Issues Desktop tab"&gt;&lt;/a&gt;&lt;/p&gt;
Issues Desktop tab






&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc3iwobiwiuwnhi9gn7e2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc3iwobiwiuwnhi9gn7e2.png" alt="Issues Android tab"&gt;&lt;/a&gt;&lt;/p&gt;
Issues Android tab






&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1hnn53wz0hd9hwk9ii2w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1hnn53wz0hd9hwk9ii2w.png" alt="Remaining issues after Fix All"&gt;&lt;/a&gt;&lt;/p&gt;
Remaining issues after Fix All






&lt;h2&gt;
  
  
  Using the Meta Quest Link Cable
&lt;/h2&gt;

&lt;p&gt;Meta Quest Link provides a simplified method for skipping the Android build process in Unity. However, it lacks critical features such as Plane Detection and Passthrough, rendering it ineffective for real-world mixed reality application testing. Presently, there is no indication as to whether or when these capabilities might be implemented.&lt;/p&gt;

&lt;p&gt;Alternatively, you can switch to Android within the &lt;code&gt;Build Settings&lt;/code&gt; in Unity. Follow these steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Access the &lt;code&gt;Build Settings&lt;/code&gt; by navigating to &lt;strong&gt;File → Build Settings&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Make sure to add the &lt;code&gt;SampleScene&lt;/code&gt; via &lt;code&gt;Add Open Scene&lt;/code&gt; to &lt;code&gt;Scenes in Build&lt;/code&gt;. Normally the &lt;code&gt;SampleScene&lt;/code&gt; is already included so you can properly skip this step.&lt;/li&gt;
&lt;li&gt;Select &lt;code&gt;Android&lt;/code&gt; as a Platform and press the &lt;code&gt;Switch platform&lt;/code&gt; button at the bottom right.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnoo9uxu0sp9dx6p11bvn.png"&gt;
&lt;/h2&gt;

&lt;p&gt;With this setup, we now have two methods to launch apps on the Meta Quest 3: without passthrough directly from the Unity editor, and with passthrough using the &lt;code&gt;Build and Run&lt;/code&gt; feature. The build and run process deploys the app as an Android app to your Meta Quest 3, but it takes significantly longer than simply pressing the play button in Unity. We’ll start by using the the first method and later switch to &lt;code&gt;Build and Run&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Next article
&lt;/h2&gt;

&lt;p&gt;In our next article, we will introduce a key component in MR development: the Session Component. This feature plays a crucial role in managing the MR session, effectively serving as the backbone of any mixed reality application.&lt;/p&gt;

</description>
      <category>unity3d</category>
      <category>mixedreality</category>
      <category>tutorial</category>
      <category>beginners</category>
    </item>
  </channel>
</rss>
