Search Unity

  1. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Making my first Tool

Discussion in 'EditorXR' started by Paul-van-der-Laan, Oct 27, 2019.

  1. Paul-van-der-Laan


    Oct 12, 2013
    Hey all,

    I'm planning to use EditorXR as a level design tool for VR apps and games and as such I would like to create some extra functionalities which I can use for making levels.

    I read the Extending EditorXR document and watched the youtube video's about EditorXR but I still struggle making my own custom tool.

    Let's start simple. I want to make a custom tool which finds a certain object in the scene and follows the position and rotation of one of the controllers. I made this script:

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEditor.Experimental.EditorVR;
    4. using UnityEngine;
    5. using UnityEngine.InputNew;
    7. [MainMenuItem("MAIN PaulVRTool", "Tools", "MAIN A custom tool made by Paul")]
    8. [SpatialMenuItem("SPATIAL PaulVRTool", "Tools", "SPATIALA custom tool made by Paul")]
    9. public class PaulVRTool : MonoBehaviour, ITool, IUsesRayOrigin, IProcessInput
    10. {
    11.     public Transform rayOrigin { get; set; }
    13.     public GameObject prefabToCreate;
    15.     GameObject createdPrefab;
    19.     public void ProcessInput(ActionMapInput input, ConsumeControlDelegate consumeControl)
    20.     {
    21.         if(createdPrefab == null)
    22.         {
    23.             createdPrefab = GameObject.FindGameObjectWithTag("Arrow");
    24.         }
    26.         createdPrefab.transform.position = rayOrigin.forward;
    27.         createdPrefab.transform.rotation = rayOrigin.rotation;
    28.     }
    29. }
    When I run EditorXR and select my tool and also select other tools back and forth, I get these errors:

    Anything I'm doing wrong in my script causing these errors?

    I'm using Oculus Rift, Unity 2018.4.2f1 and EditorXR-0.2.1.unitypackage in a very barebones scene.
  2. amirebrahimi_unity


    Aug 12, 2015
    Do you get any errors the first time you launch your tool?
  3. Paul-van-der-Laan


    Oct 12, 2013
    No, only when switching between my tool and other tools (like the select tool).
  4. amirebrahimi_unity


    Aug 12, 2015
    Hmm. Can you try simplifying the tool to only be an ITool and nothing else and let me know if you get the same errors?
  5. Paul-van-der-Laan


    Oct 12, 2013
    Yes I get the same errors with a completely empty class which inherits only from Monobehavior and ITool.

    Small side note, I also noticed the ' Tool' suffix of my class PaulVRTool gets removed in the main menu. When I rename my class to PaulVRThing for example, i can see the full name of my class in the menu. But I guess this is unrelated.
  6. amirebrahimi_unity


    Aug 12, 2015
    Do you have a project on github you'd be willing to share and/or a copy of your project that I could take a look at?
  7. Paul-van-der-Laan


    Oct 12, 2013
    I downloaded the exact recommended Unity version, started a clean project, imported the EditorXR package and created an empty class inheriting from ITool. Issue still exists. I uploaded this project here:
  8. amirebrahimi_unity


    Aug 12, 2015
    This is a bug.
    For now, you can workaround this by adding IStandardActionMap to your tools.
  9. Paul-van-der-Laan


    Oct 12, 2013
    Thanks for your reply, that has solved the error.

    I dived a bit more into EditorXR and it's quite complex for me as a beginner programmer but little by little I understand the system better.

    I have formulated some questions which I hope you can answer so I better understand EditorXR.

    First off, I find this bit of code in the Start function of the CreatePrimitivesTool and I dont understand what it does:

    Code (CSharp):
    1. var controls = new BindingDictionary();
    2. InputUtils.GetBindingDictionaryFromActionMap(standardActionMap, controls);
    4. foreach (var control in controls)
    5.             {
    6.                 foreach (var id in control.Value)
    7.                 {
    8.                     var request = (ProxyFeedbackRequest)this.GetFeedbackRequestObject(typeof(ProxyFeedbackRequest));
    9.                     request.node = node;
    10.                     request.control = id;
    11.                     request.tooltipText = "Draw";
    12.                     this.AddFeedbackRequest(request);
    13.                 }
    14.             }
    1. what is a ' Feedback ' in ProxyFeedbackRequest (controller rumble? UI feedback?) ?
    2. what does ' action' refer to in the ProxyFeedbackRequest comments (like in C# action or user action?)
    3. What is a ' affordance' ?
    4. what does proxy in ' ProxyFeedbackRequest' mean in this context?
    5. What is this system used for and should I care?
    6. I pressed clear data in proxyfeedback editor menu and everything that was there, was gone. Is this bad?

    1. What does IConnectInterfaces do? How does it work?
    2. what does 'connecting interfaces' mean?
    Custom ActionMap
    1. Is there a table which shows which VRInputDevice action (1 to 5) binds to which button on Oculus Rift (and also other VR devices)? I noticed Action 1 is "A" button and Action 2 is "B" button on Touch Controller. Is there an overview table for this?
    2. Why is there only ' left stick button/x/y' actions and not right stick?

    Other feedback:
    • The Radial tool menu is frustrating to use due to changing position of buttons when hovering over it.
    • If I understand the tool system correctly, a iTool can be assigned to a specific controller? So 2 different iTool can be assigned to the right and left hand controller. But only one of the tools is active or are both active? Overall, I find this whole setup a bit confusing but maybe I need to get used to it a bit more. Might give more detailed feedback later.
    • Would be nice to have some more examples of simple custom made iTools. Is there a source of community made tools I can look at? The currently implemented tools (transform tool, selection tool) are a bit complex for me so it takes quite some time to study and understand.
  10. amirebrahimi_unity


    Aug 12, 2015
    1. It is only UI feedback (tooltips and controller outlining)
    2. Action is a poor term because it's not just a single action. In terms of the comments an action would be whatever happens when the affordance (see #3) is used (not C# action); The FeedbackRequestObject will be in the list of feedback requests until it is no longer applicable (e.g. context has changed and that affordance will no longer perform the same action)
    3. An "affordance" is a part of the controller that is interactable (e.g. buttons, thumbstick, triggers)
    4. Proxy effectively means controller, but originally we used the term to mean anything that can be a "proxy" to a physical thing (e.g. controller or hand)
    5. Tooltips and controller affordance outlines to educate users to what your affordances do
    6. That might be a bug. It's supposed to reset the number of times you had seen the feedback.

    1. It connects objects to the rest of the system based on the interfaces that are added to a class
    2. This unfortunately isn't a one-liner, but you can listen to part of it described in this talk:

    1. Unfortunately, no.
    2. Because those are set up for a gamepad, but VR controllers only have a single thumbstick / buttons, so that is treated as the "left"

    1. You might be experiencing that when the controller that is showing the radial menu has a ray hovering over an object and that ray goes off the object, then the radial menu changes.
    2. Your understanding is correct. The idea was that you could have different tool "stacks" for each controller/proxy or you could have two-handed tools in some case. This is to allow more flexibility with creation.
    3. Our hope was that more EditorXR tools would be open source, but I think most custom tools are likely closed source. It's understandable that the current implemented tools are complex because they lay the foundations for EditorXR. Custom tools are likely to be "lighter weight" than these. One talk that might help is one where a custom tool is used for building up a longbow game:
    Paul-van-der-Laan likes this.
  11. Paul-van-der-Laan


    Oct 12, 2013
    Thanks for your detailed answers! They help me to understand the system better.

    I have successfully made my first usable ITool. Currently, it can snap selected objects position and rotation by a button press. Ideally I would like to have this done in real-time when using the move tool, but that will be for another day ;)

    I have added all needed scripts as a package to this post. Here is the ITools script for a quick preview:

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEditor;
    4. using UnityEditor.Experimental.EditorVR;
    5. using UnityEngine;
    6. using UnityEngine.InputNew;
    7. using PaulUtils;
    9. [MainMenuItem("Snap objects", "Edit", "snap objects to grid and discreet angles")]
    10. public class SnapTool : MonoBehaviour, ITool, ICustomActionMap, IUsesRayOrigin, ISelectTool
    11. {
    13.     public ActionMap standardActionMap { get;set; }
    15.     public Transform rayOrigin { get; set; }
    17.     [SerializeField] public float gridSize = 0.05f;
    19.     public ActionMap actionMap { get { return m_ActionMap; } }
    20.     public bool ignoreActionMapInputLocking { get { return false; } }
    22.     [SerializeField]
    23.     ActionMap m_ActionMap;
    25.     private void Start()
    26.     {
    27.         // Clear selection so we can't manipulate things
    28.         Selection.activeGameObject = null;
    29.     }
    31.     public void ProcessInput(ActionMapInput input, ConsumeControlDelegate consumeControl)
    32.     {
    33.         var standardInput = (SnapToolActionMap)input;
    36.         // snapping object to grid
    37.         if(standardInput.action.wasJustPressed)
    38.         {
    39.             consumeControl(standardInput.action);
    40.             foreach(var selectedObject in Selection.transforms)
    41.             {
    42.                 selectedObject.position = selectedObject.position.Round(gridSize);
    43.             }
    45.         }
    47.         // snapping rotation to 90 degrees
    48.         if(standardInput.action2.wasJustPressed)
    49.         {
    50.             foreach(var selectedObject in Selection.transforms)
    51.             {
    52.                 consumeControl(standardInput.action2);
    53.                 int degrees = 90;
    54.                 selectedObject.rotation = selectedObject.rotation.Round(degrees);
    55.             }
    56.         }
    58.     }
    60. }
    Thanks for all your help so far!

    Attached Files:

    amirebrahimi_unity likes this.