Developing a Virtual Drone App on Google Daydream VR using Unity

One of my early to-do projects on VR was the development a virtual quadcopter drone on a 3rd person view to train users on basic flight control mechanics.

Here’s a WebGL demo using the Xbox Game Controller and a Quad-Engine Drone with flight stabilization code.

Drone Flight Control Demo (Please wait a while the App loads on your browser Edge/Chrome suggested)

With the Daydream View paired Google Pixel XL Phone I opted to give it a try with the no-frills, less clunky quick setup I experience with Daydream compared to Gear VR or having to connect my cables and clear-up wire paths with Oculus and Vive.

While developer tools and documentation is pretty decent, it always irks me that new hardware gets released to the market paired with a custom “technical preview” version of Unity instead of an add-on/SDK that works with the latest released version. The usual rationale is to get it as soon as possible to developers and users but it stops being amusing when you have multiple side-by-side different versions on Unity installed. Daydream (along with HoloLens) as of writing require a specific Unity Technical Preview for Daydream for developing apps. The full developer workstation setup details are posted at https://developers.google.com/vr/unity/

The 3 main setup components are:

The Google VR SDK contains a sample Daydream Controller demo scene (GoogleVR\DemoScenes\ControllerDemo) that works with the controller emulator. The Emulator is packaged as an APK that is side loaded on a development enabled Android Phone.  I use a USB cable connection to simplify my setup or you can do it over WiFi but requires changing the project configuration and updating the IP Address.  I will use the Daydream Controller for flying the drone (I prefer a gamepad with dual-sticks which I’ll discuss in the future).

The controller has a clickable touchpad, app button, accelerometer, gyroscope and position tracking available for use with the SDK. The additional controller home and volume control buttons are directly managed by the system. I decided to use the controller turned on its side as tilt controls for the drone pitch/roll/yaw and the touchpad to control the throttle/engine. Imagine controlling an old-school puppet with strings.

Setting up the Unity Project Quick Notes:

  1. Create a New Unity Project
  2. Create a New Scene
  3. Change the Build Settings to Android
  4. On Player Settings, update the Bundle Identifier to your web domain
  5. Add the Google VR SDK Prefabs GvrViewerMain and GvrControllerMain
  6. Create a Plane scale it to around 10,10,10 (add grid texture from Unity Standard Assets)
  7. Move the Camera to 0,2,0 (world center at near human height)
  8. Add a Drone Model (Use a Cube, your own 3D model or some nice free model from the Unity Asset Store)
  9. Add a RigidBody Component to the Drone Model (Drag = 1, Angular Drag = 2, Use Gravity = Checked)
  10. Make sure the Drone Model has a Convex Collider when using a Mesh Collider
  11. Add a new script to the Drone GameObject (DroneControl.cs)

Since the plan is to eventually use a dual-stick gamepad, I’m using a RigidBody and Force to  simulate the flight behavior. Drag and Angular Drag are used to counter the force to mimic a flight gyroscope or reaction control system and simplify flight controls for the user.

daydreamdrone

DroneControl.cs

The bulk of the complexity in development from Physics computation, 3D display and Input controller management are handled by Unity and the Google VR SDK.


using UnityEngine;
using System.Collections;

public class DroneControl : MonoBehaviour
{
    private float upForce = 0f;
    private Rigidbody rigidbody;

    // Options for Dual-Stick Controls
    private float mx;
    private float my;
    private float mz;
    private float rx;
    private float ry;
    private float rz;

    void Start()
    {
        rigidbody = GetComponent<Rigidbody>();
    }

    void Update()
    {
        if (GvrController.IsTouching)
        {
            mx = 0;
            my = GvrController.TouchPos.x - 0.5f;              // Touch Position is 0,0 to 1,1
            mz = 0;
        }
        else
        {
            mx = 0;
            my = 0;
            mz = 0;
        }

        var rot = GvrController.Orientation.eulerAngles;
        // Controller is on its side - touchpad on LEFT
        rx = -rot.z;
        ry = rot.y;
        rz = rot.x;

        if (GvrController.AppButtonDown)
        {
            // Negate Gravity to Hover
            upForce = -Physics.gravity.y;
        }
    }

    void FixedUpdate()
    {
        upForce += my * 0.5f;  // Throttle to Force Conversion
        rigidbody.AddRelativeForce(Vector3.up * upForce);
        transform.rotation = Quaternion.Euler(rx, ry, rz);
    }
}