Continuing our series on building a dynamic user interface for the HoloLens, this guide will show how to rotate the objects that we already created and moved and scaled in previous lessons.
So far, we've built a system that incorporates the user's gaze and what the user is looking at to determine the UI elements they're seeing. This type of context-dependent UI is all about streamlining the way we work in augmented reality. My hopes for this series is that people will use it as a jumping-off point. Although we're currently adding objects and transforming them around the space, this system could be far more elaborate, having many other ways to interact with objects.
Alright, with that out of the way, let's get into the heart of this lesson: rotating our object. Now that we've gotten our Move and Scale tools working and in place, we need to get our Rotate tool to work alongside them. Fortunately, after the work of the last two lessons, this is a pretty simple thing to accomplish.
Since there's only a slight difference in the code to move our objects versus rotating our objects, we will once again use the MoveTool.cs from lesson 9 in this series as the template for our RotationToolInteraction class. So, as we have done a number of times before, select the "Rotate" subobject of the TransformUITool, and click the"Add Component" button.
Click on the "New Script" option at the bottom of the components list, and when the New Script box appears, type RotateToolInteraction into the Name field. Next, click on "Create and Add."
Once it finishes its creation and compiling process, double-click the "RotateToolInteraction.cs" script file to open it in Visual Studio. It will load Visual Studio if you don't already have it opened.
Now, double-click on the "MoveTool.cs" file to make sure it's opened up in Visual Studio as well.
Once Visual Studio is opened, look for the "MoveTool.cs" tab, and click on it to bring it forward. Select all the code by using the keyboard shortcut Ctrl + A, then hit Ctrl + C to copy the entire class.
Now, in Visual Studio, select the "RotateToolInteraction.cs" tab to make it the active class. Again, use the keyboard command Ctrl + A to select everything in the class, then use Ctrl + V to paste the contents we have in the clipboard to the new class.
Finally, on line 6, replace the class name declaration "MoveTool" with "RotateToolInteraction," and click on "File," then "Save." With class creation out of the way, next up we have the code changes we need to make.
In Unity, object manipulation that involves rotation, position, and scale is handled in the Transform component. With quick and easy access to these elements of our transform, using data structures like Vector3s and Quaternions (more about those two terms shortly), we can make sweeping changes, often with a single line of code.
As we have talked about previously, the data type that we use for position and scale is known as a Vector3. This data type is made up of three float values: X, Y, and Z. While we often end up using high-level Vector3s for rotations, under-the-hood rotations use something quite different, which we will address in a moment. First, here's a quick refresher on the main line of code we're working with.
Since we just copied and pasted our move code in, the following line of code (line 57 if you have been following along) is the line that handles our movement updates every frame.
HostTransform.position = Vector3.Lerp (HostTransform.position, HostTransform.position + manipulationDelta, PositionLerpSpeed);
Here we are updating the position of the HostTransform object's transform using Linear interpolation, or Lerp, for short. Linear interpolation is a way to smooth out the movement from frame to frame. In the Lerp process, we are adding the current position of the object (HostTransform.position) to the manipulationDelta (or the distance that our hand has moved between frames).
If we move our hand in one direction, we add a positive number. Moving in the other direction adds a negative number, or, if you remember your math, that's subtracting. Finally, if we don't move our hand at all, we are adding zero, and therefore causing no change.
A quaternion is a complex, four-element structure that does not suffer the trappings that come with using Vector3s and Euler angles (a structure that's interchangeable with a Vector3 in Unity) for rotations like gimbal lock. While the math behind a quaternion is complex, as we do not have to change them directly or internally, they are not so bad. On a top level, quaternions are very simple to work with. In many cases, we will use Euler angles, which also use a Vector3 data structure, but we are converting the Vector3 to a quaternion as needed.
To see that in action, change line 57 we were just talking about with this line:
HostTransform.rotation = Quaternion.Lerp(currentRot ,currentRot * Quaternion.Euler(manipulationDelta * DistanceScale), RotationLerpSpeed);
If you look at the code, you may notice how similar it looks to the Move code. Again, we are using the current rotation of the object and, in this case, multiplying it by a quaternion. As manipulationDelta is a Vector 3 and DistanceScale is a float (a high precision floating point number), we cannot directly multiply them to a quaternion. Instead, we use the Quaternion.Euler method, which takes the product of multiplying manipulationDelta and DistanceScale and returns a quaternion, converting our Vector3 to the output we need.
In case you are wondering, both quaternion and Vector3 contain a method for Lerp.
And with that change, we now have the ability to rotate our objects with our UI system. As we have done many times before, build and compile the app and give it a run on your HoloLens.
Look at one of the objects, and then rotate it using our newest tool. If it spins uncontrollably, you can easily adjust the rotation speed by moving the Rotation Lerp Speed slider in the "RotationToolInteraction" component.
Congrats, this is a major milestone. While I'm not calling this the end, because there are some obvious things still missing, we do need to take a breath. I'm going to go play with my dog.
See you in the next lesson, where we make it easy to tell which of the tools are being selected by having a highlight color — but we aren't going to cheat by making it a texture swap. After that, we will make our Scale modes selectable in the app itself.