Last Updated: Jul 3, 2017
- Add a Character with a Rigidbody
- Animate the Character
- Add Character Movement
This is the final section of this tutorial. This pulls in the last fundamental features for a HoloLens application, physics and collision detection. The completed application has been published to the Windows Store with some additional polish, but essentially every step of its creation has been documented in this tutorial. Let’s wrap this tutorial up!
Colliders in Unity are exactly what they sound like, they are used to detect collisions. In the case of this tutorial we are going to have a character with a Rigidbody and allow the Unity physics engine to detect collisions sot that we can respond accordingly. We have already added colliders, but lets review where we added them and why. The first place we have colliders is on the Spatial Understanding Mesh:
This checkbox tells spatial understanding to add a collider to the mesh as it is being created. We want a collider on the mesh for multiple reasons. The first reason is to make sure the character has something to walk on. Because we are using the physics engine to move the character if there was no collider on the floor, gravity would pull the character down and he would fall infinitely. We also want the objects in the room to have colliders so that if the character runs into these objects he can stop instead of running through them.
The trees and building also get colliders. These were a bit more difficult to implement and you can see them in ObjectCollectionManager.cs. In CreateTree there is a line that adds a mesh collider to the object as it is instantiated:
In Create Building there is a line that calls a method that adds colliders to all of the children of the GameObject:
This is required because the buildings are made up of nested GameObjects and each GameObject must get its own collider. We are adding these colliders to the buildings and trees so that the Character can not run through them but instead hits them and stops. A key point is that we are applying colliders to the real world objects and the holographic objects for the exact same reason. This is Mixed Reality so we want the interaction between a hologram and the real world to be the same as a hologram and a hologram!
We already have all of this in place so no need to make any changes, we were planning this all along…
NOTE: The colliders I’ve used in this tutorial are detailed and expensive (mesh colliders), for a real world application you would want to use box or sphere colliders to improve application performance. That would be a lot more busy work and not the point of the tutorial, so for the sake of the tutorial we took the quickest route. There are many good resources available on optimizing colliders for unity, any of them would be applicable to HoloLens development as well.
Add a Character with a Rigidbody
I’m going to use a free character from the Unity 3D Asset Store. If you want to follow along exactly I recommend using the same character. I’m using the Low Poly Cowboy available here:
This is a nice looking character that is low poly and is easily handled by the HoloLens. Import the asset into your application including everything:
You now have a Cowboy folder in your assets. We are going to want to make some changes to the Cowboy.prefab later on, so for now let’s make a copy named Movable Cowboy. Drag the cowboy.prefab into your hierarchy. Rename the “Cowboy” gameobject in the Hierarchy to “Movable Cowboy”. Drag the Movable Cowboy from the hierarchy back to your Project pane. Delete the Movable Cowboy from the Hierarchy. Your project should now look like this:
Next we will add some code that knows how to instantiate the cowboy. Edit ObjectCollectionManager.cs to contain the following code:
I’ve added two new properties to ObjectCollectionManager, one to specify the model to use for the cowboy and the other to specify the desired size for the cowboy. I’ve also added a CreateCowboy method, which works exactly the same as the other Create methods, except that it adds a script called “Cowboy” to the gameobject as it is spawned. This doesn’t exist yet, so create a new script called Cowboy.cs in the scripts folder.
Open the project in Unity and select Placement in the Hierarchy. The ObjectCollectionManager component now shows the two new properties that we added. Navigate to Assets > Cowboy > Prefabs in the Project pane. Drag Movable Cowboy into the Cowboy property of the visible component. Modify Cowboy size to contain .15 for X, Y, and Z. Your properties should now look like this in the inspector:
Now let’s make updates to spawn the cowboy during world generation. Start by updating PlacementQuery.cs to add Cowboy to the Enum:
Next Update ObjectPlacer.cs:
These changes are consistent with the already established patterns. The first addition is a boolean that allows us to turn the cowboy on and off, we default this to true. Next in CreateScene we add a check to see if this is true and if it is, we add a request for a place to put the Cowboy. We add an AddCowboy method which is called by CreateScene to create the correct query for the Cowboy. Then we updated ProcessPlacementResults to add a case for ObjectType.Cowboy that calls the ObjectCollectionManager code from above to instantiate the Cowboy. Finally we add some logic to CreateLocationQueriesForSolver to notice when it is placing a cowboy and add a special constraint to add him near the middle of the room, which will also be near the middle of the scene, where the user will naturally look.
Build and Deploy your application. Notice that the cowboy is instantiated in the center of your room and he is standing in the T pose.
Animate the Character
Next we will add animation to the character to get him out of the T pose. To do this we will use one of the animations that is a part of the Unity Standard assets. Open your project in unity. Select from the menu Assets > Import Package > Characters. Uncheck the root node to deselect everything, we only want a small part of this asset pack. Find the third person character part of the tree. Check Animation and Animator so that your import dialog looks like this:
Click import and wait for the assets to be imported. Find the Standard Assets folder in your project pane. Drill down to Assets > Standard Assets > Characters > ThirdPersonCharacter > Animator. This is the standard animator provided for use in third person games. This will be used to animate your character, double click on it to see how it works. In particular pay attention to the parameters, this is what we will use to trigger animations for our character:
Navigate in the project pane to the Assets > Cowboy > Prefabs folder and select the Movable Cowboy. In the inspector select the Controller property and Assign ThirdPartyAnimatorController.
Build and Deploy your application. Notice that the cowboy is now performing the idle animation which is more natural than the T pose.
Add Character Movement
We need the Cowboy to listen to the HoloLens Select gesture so we know when and were the user wants to move them. Edit the file Cowboy.cs and add the following content:
This code implements the IInputClickHandler similar to what we did in a previous tutorial. When the user performs the select gesture, MoveCharacterToPoint is called and passed the location that the user had the cursor on when they performed the select gesture. We then set the Animator component Forward variable to 1, which causes the character to animate forward.
Build and Deploy your application. Perform the select gesture in the world. The cowboy animates forward! The provided run animation looks pretty good, but the cowboy just runs forward in the direction he was facing and runs forever.
Now we will make the character move to the actual location that the user selected. Edit Cowboy.cs again with the following contents:
We’ve added a ton of the logic necessary for movement into this script. In Start we grab a handle to the Cowboy’s Rigidbody and make a note of where the ground is. For this app we don’t ever want the cowboy to leave the ground so we store the ground value for use when calculating where the cowboy should move to. In MoveChracaterToPoint we set the private destination variable to the value the user selected and also set the Y value to the location of the ground. This makes sure no matter where the user selects, that the cowboy stays on the ground. This method calls the new StartWalking method which keeps track of the starting position, when we started moving the character from the start position to the destination, and how long it should take the character to walk there based on the desired walking speed. We start the walking animation and set the walking state to true. LateUpdate picks up from here and does two things, if we are walking it calls MoveForFrame and it checks to see if we are at our destination. If we are at our destination it calls StopWalking. MoveForFrame uses the information saved during start walking to determine where the character should be for this frame and lerp them there. It also lets the caller know if we are finished moving. StopWalking stops the walking animation and sets the walking state to false.
Before this code will work we need to give the Cowboy a RigidBody. Open Unity and select the Movable Cowboy in the project pane. Click add component and select Rigidbody. Click add component and select Capsule Collider. Set the properties to the following settings:
The Rigidbody is used by the physics engine to give the character realistic interaction with the environment. We freeze the rotation in the X and Z direction so that the cowboy doesn’t fall over since he is top heavy. (Remember gravity is being applied once we add the Rigidbody). We also configure Continuous Dynamic collision detection to improve the accuracy of collision detection. Rgidbody’s also require a properly configured collider. We are not allowed to use a mesh collider like we do in the rest of the tutorial so we added a Capsule collider. The properties are configured to cause the capsule to encompass the majority of the character. This is closer to the correct way to optimize colliders, but for a real world project I would recommend multiple colliders for a character so that the entire model is covered.
Build and Deploy your application. Perform the select gesture in the world. The cowboy now moves to the selected location and stops when he gets there! A huge improvement but we still have a couple problems. The cowboy runs sideways or backwards because we haven’t turned him to face the correct direction. He also runs through objects, where is the collision detection I promised?
Let’s fix the turning problem first. Make the following changes to Cowboy.cs:
We’ve updated MoveCharacterToPoint to call StartTurning instead of StartWalking. StartTurning stores the starting rotation and the destination location, it also stores the time we started turning the character, and enables the turn animation. Finally it sets the turning state to true. LateUpdate now also checks to see if we are turning, and if we are it calls TurnForFrame as well as calling StopTurning and StartWalking once we have reached our target rotation. TurnForFrame works just like walk for frame figuring out based on the time elapsed where we should be in rotating and rotating the character that direction.
Fixing collision detection is very easy because the collision detection is already taking place and we are ignoring it currently. Edit Cowboy.cs to contain the following changes:
OnCollisionEnter is called anytime the physics engine detects that the cowboy’s rigidbody has hit a collider. We examine all of the collisions and ignores any collision with the ground. We call stop walking if we hit something that isn’t the ground. We also freeze rotation to eliminate the occasional spin in place the cowboy will do when he hits some invisible part of the mesh.
Build and Deploy your application. Perform the select gesture in the world. The cowboy now turns to face the direction he is going before walking there, he no longer spins in place when stopping, and he stops when he runs into something. We’ve used the unity physics engine and animation engine to create a character that moves realistically through the world.
This is the end of this tutorial series, I will work on getting the complete code published. Please let me know what you would like to see next!
Tutorial IndexVersions: Unity 2017.1.0p5 | MixedRealityToolkit-Unity v1.2017.1.0 | Visual Studio 2017 15.3.2
|Unity 3D Project Creation||How to create a HoloLens project in Unity 3D|
|Source Control||Configure git for HoloLens / Unity work|
|Spatial Mapping||How to spatial map a Room|
|Object Surface Observer||Set up fake spatial map data for the Unity editor|
|TagAlongs and Billboarding||Tag along instructions to the user to force text on screen|
|Spatial Understanding||Add spatial understanding to get play space detail|
|Finalizing Spatial Understanding||Complete Spatial Understanding and Input Manager|
|Object Placement and Scaling||Find valid locations for holograms in the play space|
|Hologram Management||Manage the holograms you want to place in the world|
|Cursor and Voice||Add a cursor and voice commands|
|Occlusion||Add occlusion with the real world to your scene|
|Colliders and Rigidbodys||Add Colliders and RigidBodys to your holograms|