Zonen Wang - Home
Contact
A visitor paddling a real kayak in VR, beside the headset view of the river

VR Kayaking

A real kayak and paddle as the VR controller

Role
Developer
Date
Nov 2019
While at
RIOS
Built with
Unity, C#

Overview

Visitors sit in a real kayak and use a real paddle to travel along Austin's Colorado River in VR.

RIOS was designing Drake Bridge Commons, a proposed public space under a bridge on the river, and this ride let people experience it from the water. VR controllers on the paddle track every stroke, and the kayak responds. I built the paddling interaction in Unity, and the setup was exhibited in Austin.

Demo

Left: the paddler in the room. Right: the view in the headset.

Real world, virtual world

What the visitor does in the room, and what happens on the river.

Flow chart: real-world actions mapped to the virtual kayak

Paddle logic

A stroke counts only when the blade is under the waterline. Pulling it back moves the kayak forward, a sweep to the side turns it, and when both blades are out the boat glides to a stop.

// Left blade under water and moving: one stroke
if (paddleLeft.localPosition.y < -0.3f && paddleLeft.localPosition != leftPaddlePos)
{
    // Blade travel in the kayak's frame: sideways (x), along the hull (z)
    leftPaddleDisonX = transform.InverseTransformPoint(paddleLeft.position).x
                     - transform.InverseTransformPoint(leftPaddleUniPos).x;
    leftPaddleDisonZ = transform.InverseTransformPoint(paddleLeft.position).z
                     - transform.InverseTransformPoint(leftPaddleUniPos).z;

    // Sweep out to the side: turn
    if (leftPaddleDisonX < 0)
        transform.localEulerAngles += new Vector3(0f, -leftPaddleDisonX * 15f, 0f);
    // Pull back: move forward by the stroke length
    transform.Translate(Vector3.forward * -leftPaddleDisonZ * 2f, Space.Self);
    if (Mathf.Abs(leftPaddleDisonZ) > 0.1f) Speed = 10F;
}

// Both blades out of the water: glide, slowing down
if (paddleRight.localPosition.y >= -0.3f && paddleLeft.localPosition.y >= -0.3f)
{
    if (Speed > Deceleration * Time.deltaTime)
        Speed = Speed - Deceleration * Time.deltaTime;
    else
        Speed = 0;
    if (forward) transform.position += transform.forward * Speed * Time.deltaTime;
    if (forward == false) transform.position -= transform.forward * Speed * Time.deltaTime;
}

Master plan

Drake Bridge Commons: the riverfront space the ride passes through.

Master plan of Drake Bridge Commons along the Colorado River
Zonen Wang - Home
A visitor paddling a real kayak in VR, beside the headset view of the river

VR Kayaking

A real kayak and paddle as the VR controller

Role
Developer
Date
Nov 2019
While at
RIOS
Built with
Unity, C#

Overview

Visitors sit in a real kayak and use a real paddle to travel along Austin's Colorado River in VR.

RIOS was designing Drake Bridge Commons, a proposed public space under a bridge on the river, and this ride let people experience it from the water. VR controllers on the paddle track every stroke, and the kayak responds. I built the paddling interaction in Unity, and the setup was exhibited in Austin.

Demo

Left: the paddler in the room. Right: the view in the headset.

Real world, virtual world

What the visitor does in the room, and what happens on the river.

Flow chart: real-world actions mapped to the virtual kayak

Paddle logic

A stroke counts only when the blade is under the waterline. Pulling it back moves the kayak forward, a sweep to the side turns it, and when both blades are out the boat glides to a stop.

// Left blade under water and moving: one stroke
if (paddleLeft.localPosition.y < -0.3f && paddleLeft.localPosition != leftPaddlePos)
{
    // Blade travel in the kayak's frame: sideways (x), along the hull (z)
    leftPaddleDisonX = transform.InverseTransformPoint(paddleLeft.position).x
                     - transform.InverseTransformPoint(leftPaddleUniPos).x;
    leftPaddleDisonZ = transform.InverseTransformPoint(paddleLeft.position).z
                     - transform.InverseTransformPoint(leftPaddleUniPos).z;

    // Sweep out to the side: turn
    if (leftPaddleDisonX < 0)
        transform.localEulerAngles += new Vector3(0f, -leftPaddleDisonX * 15f, 0f);
    // Pull back: move forward by the stroke length
    transform.Translate(Vector3.forward * -leftPaddleDisonZ * 2f, Space.Self);
    if (Mathf.Abs(leftPaddleDisonZ) > 0.1f) Speed = 10F;
}

// Both blades out of the water: glide, slowing down
if (paddleRight.localPosition.y >= -0.3f && paddleLeft.localPosition.y >= -0.3f)
{
    if (Speed > Deceleration * Time.deltaTime)
        Speed = Speed - Deceleration * Time.deltaTime;
    else
        Speed = 0;
    if (forward) transform.position += transform.forward * Speed * Time.deltaTime;
    if (forward == false) transform.position -= transform.forward * Speed * Time.deltaTime;
}

Master plan

Drake Bridge Commons: the riverfront space the ride passes through.

Master plan of Drake Bridge Commons along the Colorado River