re-making a classic in vr
DESCRIPTION
Re-making a Classic in VR. Chris Zaharia. @ chrisjz # SydVR. Project. Engine - Unity 3D (v4.5) View + head tracking - Oculus Rift DK1 Hand tracking - Razer Hydra C# Language Re-create game up to first mission in first world. To Do. Integrate Rift with player - PowerPoint PPT PresentationTRANSCRIPT
![Page 1: Re-making a Classic in VR](https://reader034.vdocuments.mx/reader034/viewer/2022051003/568166ed550346895ddb3ac8/html5/thumbnails/1.jpg)
Re-making a Classic in VR
Chris Zaharia
@chrisjz#SydVR
![Page 2: Re-making a Classic in VR](https://reader034.vdocuments.mx/reader034/viewer/2022051003/568166ed550346895ddb3ac8/html5/thumbnails/2.jpg)
Project• Engine - Unity 3D (v4.5)• View + head tracking - Oculus Rift DK1• Hand tracking - Razer Hydra• C# Language• Re-create game up to first mission in
first world
![Page 3: Re-making a Classic in VR](https://reader034.vdocuments.mx/reader034/viewer/2022051003/568166ed550346895ddb3ac8/html5/thumbnails/3.jpg)
To Do• Integrate Rift with player• Integrate Razer Hydra with player’s
hands• Player avatar• Player movement• Hand interaction with objects
![Page 4: Re-making a Classic in VR](https://reader034.vdocuments.mx/reader034/viewer/2022051003/568166ed550346895ddb3ac8/html5/thumbnails/4.jpg)
Setup World• Start a new project• Create a scene• Import or create an environment• Create a Directional Light to light up the
environment
![Page 5: Re-making a Classic in VR](https://reader034.vdocuments.mx/reader034/viewer/2022051003/568166ed550346895ddb3ac8/html5/thumbnails/5.jpg)
Create Player & Integrate Rift• Create a GameObject called Player• Attach the component Character Controller• Attach the scripts Character Motor and FPSInput
Controller• Attach OVRCameraController prefab as child of
Player GameObject• In script FPSInput Controller set “Ovr Camera”
variable as CameraRight• Drag OVRCameraController behind player
![Page 6: Re-making a Classic in VR](https://reader034.vdocuments.mx/reader034/viewer/2022051003/568166ed550346895ddb3ac8/html5/thumbnails/6.jpg)
FPSInputController.csusing UnityEngine;using System.Collections;
// Require a character controller to be attached to the same game object[RequireComponent(typeof(CharacterMotor))][AddComponentMenu("Character/FPS Input Controller")]
public class FPSInputController : MonoBehaviour {public GameObject ovrCamera;
private CharacterMotor motor; private bool inputEnabled; // If input is enabled/disabled
// Use this for initializationvoid Awake (){
motor = GetComponent<CharacterMotor>();}
void Start() {inputEnabled = true;
}
![Page 7: Re-making a Classic in VR](https://reader034.vdocuments.mx/reader034/viewer/2022051003/568166ed550346895ddb3ac8/html5/thumbnails/7.jpg)
FPSInputController.cs (2)// Update is called once per framevoid Update (){
// Get the input vector from keyboard or analog stickVector3 directionVector= new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"));
motor.inputJump = Input.GetButton ("Jump");
// Play jumping audio clipsif (initialJumpAudioClips.Length > 0 && motor.inputJump && motor.grounded && !audio.isPlaying) {
audio.clip = initialJumpAudioClips[Random.Range(0, initialJumpAudioClips.Length)];audio.Play();
}
if (directionVector != Vector3.zero) {// Get the length of the directon vector and then normalize it// Dividing by the length is cheaper than normalizing when we already have the length anywayfloat directionLength= directionVector.magnitude;directionVector = directionVector / directionLength;
![Page 8: Re-making a Classic in VR](https://reader034.vdocuments.mx/reader034/viewer/2022051003/568166ed550346895ddb3ac8/html5/thumbnails/8.jpg)
FPSInputController.cs (3)// Make sure the length is no bigger than 1directionLength = Mathf.Min(1, directionLength);
// Make the input vector more sensitive towards the extremes and less sensitive in the middle// This makes it easier to control slow speeds when using analog sticksdirectionLength = directionLength * directionLength;
// Multiply the normalized direction vector by the modified lengthdirectionVector = directionVector * directionLength;
}
// Apply the direction to the CharacterMotormotor.inputMoveDirection = ovrCamera.transform.rotation * directionVector;
}
public void SetInputEnabled (bool status) {inputEnabled = status;
}}
![Page 9: Re-making a Classic in VR](https://reader034.vdocuments.mx/reader034/viewer/2022051003/568166ed550346895ddb3ac8/html5/thumbnails/9.jpg)
Attach avatar to player
• Place player 3D model as child of Player object and name it “Avatar”
• Move the OVR camera object behind the model
• Make the model’s head rotate with the Rift’s head tracker by moving the head model inside the CameraRight object
![Page 10: Re-making a Classic in VR](https://reader034.vdocuments.mx/reader034/viewer/2022051003/568166ed550346895ddb3ac8/html5/thumbnails/10.jpg)
Hydra Integration for Hands• Import Sixense Unity plugin for Razer
integration• Create GameObject “Hands” as child of
OVRCameraController• Place SixenseInput prefab as child of
OVRCamera Controller
![Page 11: Re-making a Classic in VR](https://reader034.vdocuments.mx/reader034/viewer/2022051003/568166ed550346895ddb3ac8/html5/thumbnails/11.jpg)
Hydra Integration for Hands• Create GameObjects “Left Hand” + “Right
Hand” as children of “Hands”• Place the player’s hand models within each
of those 2 hand objects respectively• Attach script SixenseHandController to each
hand GameObject• Set the “Hand” variable to either LEFT or
RIGHT, as appropriate
![Page 12: Re-making a Classic in VR](https://reader034.vdocuments.mx/reader034/viewer/2022051003/568166ed550346895ddb3ac8/html5/thumbnails/12.jpg)
Control Player using Hydra• Modify FPSInputController script to map
Hydra’s left joystick and a button to moving and jumping
• Create PlayerLook script in project to handle looking in environment
• Create HydraLook script to map Hydra’s right joystick to looking, inheriting PlayerLook class in its script
![Page 13: Re-making a Classic in VR](https://reader034.vdocuments.mx/reader034/viewer/2022051003/568166ed550346895ddb3ac8/html5/thumbnails/13.jpg)
FPSInputController.csvoid Start() {
IgnorePlayerColliders ();inputEnabled = true;
}
// Update is called once per framevoid Update (){
// Get the input vector from keyboard or analog stickVector3 directionVector= new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"));
// Get the input vector from hydraSixenseInput.Controller hydraLeftController = SixenseInput.GetController (SixenseHands.LEFT);SixenseInput.Controller hydraRightController = SixenseInput.GetController (SixenseHands.RIGHT);
if (hydraLeftController != null) {directionVector= new Vector3(hydraLeftController.JoystickX, 0, hydraLeftController.JoystickY);
}
if (hydraRightController != null) {motor.inputJump = hydraRightController.GetButton (SixenseButtons.BUMPER);
} else {motor.inputJump = Input.GetButton ("Jump");
}
![Page 14: Re-making a Classic in VR](https://reader034.vdocuments.mx/reader034/viewer/2022051003/568166ed550346895ddb3ac8/html5/thumbnails/14.jpg)
FPSInputController.cs (2)…
}
…
// Prevent colliders on player from colliding with each other i.e. hand colliders with body collidervoid IgnorePlayerColliders () {
Collider[] cols = GetComponentsInChildren<Collider>();
foreach (Collider col in cols) {if (col != collider) {
Physics.IgnoreCollision(col, collider);}
}}
}
![Page 15: Re-making a Classic in VR](https://reader034.vdocuments.mx/reader034/viewer/2022051003/568166ed550346895ddb3ac8/html5/thumbnails/15.jpg)
PlayerLook.csusing UnityEngine;using System.Collections;
/// PlayerLook rotates the transform based on the input device's delta./// Minimum and Maximum values can be used to constrain the possible rotation.
/// Based on Unity's MouseLook script.
[AddComponentMenu("Camera-Control/Player Look")]public class PlayerLook : MonoBehaviour {
public enum RotationAxes { XAndY = 0, X = 1, Y = 2 }public RotationAxes axes = RotationAxes.XAndY;public float sensitivityX = 15F;public float sensitivityY = 15F;
public float minimumX = -360F;public float maximumX = 360F;
public float minimumY = -60F;public float maximumY = 60F;
protected float rotationY = 0F;
![Page 16: Re-making a Classic in VR](https://reader034.vdocuments.mx/reader034/viewer/2022051003/568166ed550346895ddb3ac8/html5/thumbnails/16.jpg)
PlayerLook.cs (2)protected float axisX, axisY;
void Start () {// Make the rigid body not change rotationif (rigidbody)
rigidbody.freezeRotation = true;}
protected virtual void Update () {
if (axes == RotationAxes.XAndY){
float rotationX = transform.localEulerAngles.y + axisX * sensitivityX;
rotationY += axisY * sensitivityY;rotationY = Mathf.Clamp (rotationY, minimumY, maximumY);
transform.localEulerAngles = new Vector3(-rotationY, rotationX, 0);}else if (axes == RotationAxes.X){
transform.Rotate(0, axisX * sensitivityX, 0);}
![Page 17: Re-making a Classic in VR](https://reader034.vdocuments.mx/reader034/viewer/2022051003/568166ed550346895ddb3ac8/html5/thumbnails/17.jpg)
PlayerLook.cs (3)else{
rotationY += axisY * sensitivityY;rotationY = Mathf.Clamp (rotationY, minimumY, maximumY);
transform.localEulerAngles = new Vector3(-rotationY, transform.localEulerAngles.y, 0);}
}}
![Page 18: Re-making a Classic in VR](https://reader034.vdocuments.mx/reader034/viewer/2022051003/568166ed550346895ddb3ac8/html5/thumbnails/18.jpg)
HydraLook.csusing UnityEngine;using System.Collections;
public class HydraLook : PlayerLook {
protected override void Update () {// Get the input vector from hydraSixenseInput.Controller hydraRightController = SixenseInput.GetController (SixenseHands.RIGHT);
if (hydraRightController != null) {axisX = hydraRightController.JoystickX;axisY = hydraRightController.JoystickY;
}
base.Update ();}
}
![Page 19: Re-making a Classic in VR](https://reader034.vdocuments.mx/reader034/viewer/2022051003/568166ed550346895ddb3ac8/html5/thumbnails/19.jpg)
Hand Interactions using Hydra• Attach invisible rectangles to each hand to use
as colliders for hands• Name the objects LeftHandCollider and
RightHandCollider respectively• Modify the SixenseHandController with
functions to grab objects and throw based on hand velocity
• Tag any grabbable objects with “Grabbable” and give them a rigidbody for physics
![Page 20: Re-making a Classic in VR](https://reader034.vdocuments.mx/reader034/viewer/2022051003/568166ed550346895ddb3ac8/html5/thumbnails/20.jpg)
SixenseHandController.cspublic class SixenseHandController : SixenseObjectController{
public float minGrabDistance = 1.0f;// Grabbable object must be within this distance from hand colliders to be picked uppublic float throwForce = 30.0f;
// Force multiplyer for throwing objects
private bool isHoldingObject = false;private GameObject closestObject = null;private GrabObject grabObject;
// Script attached to grabbed object with grappling data on that objectprivate float handVelocity;private Vector3 handVector;private Vector3 handPrevious;
…
![Page 21: Re-making a Classic in VR](https://reader034.vdocuments.mx/reader034/viewer/2022051003/568166ed550346895ddb3ac8/html5/thumbnails/21.jpg)
SixenseHandController.cs (2)protected override void UpdateObject( SixenseInput.Controller controller ){
…
if ( controller.Enabled ) {
// Animation updateUpdateAnimationInput( controller );
// Action updateUpdateActionInput ( controller );
}
base.UpdateObject(controller);}
…
![Page 22: Re-making a Classic in VR](https://reader034.vdocuments.mx/reader034/viewer/2022051003/568166ed550346895ddb3ac8/html5/thumbnails/22.jpg)
SixenseHandController.cs (3)protected void UpdateActionInput( SixenseInput.Controller controller) {
Vector3 currentPosition = new Vector3();Quaternion currentRotation = new Quaternion();
Velocity();
if (isHoldingObject && !controller.GetButton(SixenseButtons.TRIGGER)) {Throw();
isHoldingObject = false;}
if (Hand == SixenseHands.LEFT) {currentPosition = GameObject.Find("LeftHandCollider").transform.position;currentRotation = GameObject.Find("LeftHandCollider").transform.rotation;
}if (Hand == SixenseHands.RIGHT) {
currentPosition = GameObject.Find("RightHandCollider").transform.position;currentRotation = GameObject.Find("RightHandCollider").transform.rotation;
}
![Page 23: Re-making a Classic in VR](https://reader034.vdocuments.mx/reader034/viewer/2022051003/568166ed550346895ddb3ac8/html5/thumbnails/23.jpg)
SixenseHandController.cs (4)if (!isHoldingObject) {
foreach (GameObject o in GameObject.FindGameObjectsWithTag ("Grabbable"))
{float dist = Vector3.Distance(o.transform.position, currentPosition);if (dist < minGrabDistance) {
closestObject = o;}
}}
![Page 24: Re-making a Classic in VR](https://reader034.vdocuments.mx/reader034/viewer/2022051003/568166ed550346895ddb3ac8/html5/thumbnails/24.jpg)
SixenseHandController.cs (5)if (closestObject != null && Vector3.Distance(closestObject.transform.position, currentPosition) < minGrabDistance && controller.GetButton(SixenseButtons.TRIGGER)) {
if (closestObject.rigidbody && closestObject.rigidbody.isKinematic) {return;
}
grabObject = closestObject.GetComponent<GrabObject>();if (grabObject && grabObject.isEnabled) {
closestObject.transform.position = currentPosition + grabObject.GetPosition(Hand);
closestObject.transform.rotation = currentRotation * Quaternion.Euler(grabObject.GetRotation(Hand));
} else {closestObject.transform.position = currentPosition;closestObject.transform.rotation = currentRotation;
}
isHoldingObject = true;}
}
![Page 25: Re-making a Classic in VR](https://reader034.vdocuments.mx/reader034/viewer/2022051003/568166ed550346895ddb3ac8/html5/thumbnails/25.jpg)
SixenseHandController.cs (6)// Calculate velocity of handprotected void Velocity () {
if (Time.deltaTime != 0){
handVector = (transform.position - handPrevious) / Time.deltaTime;handPrevious = transform.position;
}
handVelocity = Vector3.Magnitude(handVector);}
// Throw the held object once player lets go based on hand velocityprotected void Throw () {
if (closestObject.rigidbody) {Vector3 dir = (closestObject.transform.position - transform.position).normalized;
closestObject.rigidbody.AddForce(dir * handVelocity * throwForce);}
}
![Page 26: Re-making a Classic in VR](https://reader034.vdocuments.mx/reader034/viewer/2022051003/568166ed550346895ddb3ac8/html5/thumbnails/26.jpg)
Next• Presentation slides will be up online• Project will be open sourced once beta is
completed• YouTube video showing a play through
![Page 27: Re-making a Classic in VR](https://reader034.vdocuments.mx/reader034/viewer/2022051003/568166ed550346895ddb3ac8/html5/thumbnails/27.jpg)
Future• Integrate alternative and supporting devices
i.e. STEM, Leap Motion, MYO, Omni +• Re-make further (complete?)• Boilerplate?• Re-create other classics (Super Smash Bros?)
![Page 28: Re-making a Classic in VR](https://reader034.vdocuments.mx/reader034/viewer/2022051003/568166ed550346895ddb3ac8/html5/thumbnails/28.jpg)