Virtual reality under Unity

# Virtual reality under Unity
## Example project: W.A.L.L.
[Demo video](http://youtu.be/fEHD2LGCzdE)
W.A.L.L. is a two-player game. Player 1 has the ability to build structures, while player 2 is a knight who can walk around the world and shot with his crossbow in virtual reality.

## Equipment used
### Oculus rift
![Oculus rift](https://www.oculus.com/wp-content/themes/oculus/img/rift/oculusRift_hero.png)
The oculus rift is a popular virtual reality device with two essential features:

* Display: The screen, placed just in front of the user's eyes, displays images using stereoscopy to add a 3D effect. It also uses lenses to give an impression of depth.
* Motion sensor: The rift is equipped with sensors that allows it to track the motions of the user's head. This information can be used to update the camera, so that the users feels like he is actually in the game.

### Razer hydra
![Razer hydra](http://www.materiel.net/live/146479.jpg)
The razer hydra is a gaming device which is made of an emitter and two controllers. It uses a magnetic field to track the position and rotation of the controllers. Each one of them also have several buttons and a joystick.
In W.A.L.L., the controllers are used to move around, jump, open doors, aim and shot with the crossbow.

## Implementation
[GitHub repository](https://github.com/paillardf/RV01_WALL)

### Oculus rift
Using oculus rift in Unity is very straightforward. An integration package exists, so downloading it and replace the game camera by the Unity prefab it contains is all it takes to get started.
An extra effort was necessary to make the model's head follow the camera though, as their orientation were different.

```HeadBehaviour.cs
public class HeadBehaviour : MonoBehaviour {

	public Camera playerCamera;
	
	void LateUpdate () {
		transform.localRotation = playerCamera.transform.localRotation;
		// Fixes the head orientation
		transform.localRotation = new Quaternion(-transform.localRotation.y, transform.localRotation.z, -transform.localRotation.x, transform.localRotation.w);
	}
}
```

### Razer hydra
A Unity package exists for the hydra too, and comes with an API which is easy to use.

```SixenseInput.cs
    ...

		/// <summary>
		/// Value of trigger from released (0.0) to pressed (1.0).
		/// </summary>
		public float Trigger { get { return m_Trigger; } }
		
		/// <summary>
		/// Value of joystick X axis from left (-1.0) to right (1.0).
		/// </summary>
		public float JoystickX { get { return m_JoystickX; } }
		
		/// <summary>
		/// Value of joystick Y axis from bottom (-1.0) to top (1.0).
		/// </summary>
		public float JoystickY { get { return m_JoystickY; } }
		
		/// <summary>
		/// The controller position in Unity coordinates.
		/// </summary>
		public Vector3 Position { get { return new Vector3( m_Position.x, m_Position.y, -m_Position.z ); } }

    ...
```
Those methods are called in the knight controller scripts.

Moving and jumping:

```FPSInputController.cs
		SixenseInput.Controller controller = SixenseInput.GetController(SixenseHands.LEFT);
		if(controller != null) {
			// Get the input vector from Razer Hydra
			directionVector = new Vector3(controller.JoystickX, 0, controller.JoystickY);
			motor.inputJump = controller.GetButton(SixenseButtons.BUMPER);
		}

		...

		// Apply the direction to the CharacterMotor
		motor.inputMoveDirection = transform.rotation * directionVector;
```

Opening doors:

```Player.cs
		if((controller != null && controller.GetButtonDown(SixenseButtons.TRIGGER))
		|| Input.GetButton("Door")) {
			RaycastHit hit = new RaycastHit();
			if(Physics.Raycast(playerCamera.position, playerCamera.forward, out hit, 500)) {
				if(hit.collider.gameObject.CompareTag("door") && hit.distance <= maxDoorDistance) {
					GameObject test = hit.collider.gameObject;
						hit.collider.gameObject.SendMessageUpwards("interact");
				}
			}
		}
```

Shooting:

```CrossBow.cs
		SixenseInput.Controller controller = SixenseInput.GetController(SixenseHands.RIGHT);
		if(controller != null && controller.GetButtonDown(SixenseButtons.TRIGGER)
		|| Input.GetKeyDown(KeyCode.Mouse0)) {
			fire();
			audio.Play();
		}
```

The user also needs to do a calibration with each end at the beginning of the game.