Google VR template: /google_vr.lua — code sample - Stingray Lua API Reference

Google VR template: /google_vr.lua — code sample

Code

require 'core/appkit/lua/class'

GoogleVRSystem = Appkit.class(GoogleVRSystem)

local Application = stingray.Application
local Viewport = stingray.Viewport
local World = stingray.World
local Unit = stingray.Unit
local Vector2 = stingray.Vector2
local Vector2Box = stingray.Vector2Box
local Vector3 = stingray.Vector3
local Vector3Box = stingray.Vector3Box
local Quaternion = stingray.Quaternion
local QuaternionBox = stingray.QuaternionBox
local Camera = stingray.Camera
local GoogleVR = stingray.GoogleVR
local Sensor = stingray.Sensor

function GoogleVRSystem:init(world)
    if not GoogleVR then return end
    self._world = world
    self._is_initialized = false

    self._controller_api_status = 0
    self._controller_connection_status = 0
    self._controller_button_state = {}
    for i=0,6 do
        self._controller_button_state[i] = false
    end
    self._controller_touch_position = Vector2Box(0, 0)
    self._controller_orientation = QuaternionBox(0, 0, 0, 0)
    self._controller_gyroscope = Vector3Box(0, 0, 0)
    self._controller_acceleration = Vector3Box(0, 0, 0)
end

function GoogleVRSystem:initialize(near, far)
    if not GoogleVR then return end
    if not self then return end

    -- Intialize VR system
    self._is_initialized = GoogleVR.initialize()

    -- Bail if there was an error on initialization
    if not self._is_initialized then return end

    self._left_eye_fov  = GoogleVR.eye_fov(GoogleVR.LEFT_EYE)
    self._right_eye_fov = GoogleVR.eye_fov(GoogleVR.RIGHT_EYE)

    -- Create left, right and blit cameras
    self._left_camera_unit = World.spawn_unit(self._world, "core/units/camera")
    self._right_camera_unit = World.spawn_unit(self._world, "core/units/camera")
    self._left_camera = Unit.camera(self._left_camera_unit , "camera")
    self._right_camera = Unit.camera(self._right_camera_unit, "camera")

    -- Create left, right and blit viewports
    if Appkit.Util.is_ios() then
        -- On iOS Metal we use a single viewport for both eyes
        self._viewport_left  = Application.create_viewport(self._world, "vr_main")
        self._viewport_right = Application.create_viewport(self._world, "vr_main")
    else
        -- On Android and iOS OpenGL we use one viewport per eye
        self._viewport_left  = Application.create_viewport(self._world, "vr_left")
        self._viewport_right = Application.create_viewport(self._world, "vr_right")
    end

    -- Create VR working window
    local size_x, size_y = Application.render_setting("vr_hmd_eye_resolution")
    local scale = Application.render_setting("vr_target_scale")

    Sensor.set_performance_hint("fast")
    Sensor.set_magnetometer_frequency(60)

    -- Setup Render Targets
    GoogleVR.setup_render_targets("vr_left_target", "vr_right_target")

    -- Initialize cameras
    Camera.set_projection_type(self._left_camera, Camera.PERSPECTIVE)
    Camera.set_projection_type(self._right_camera, Camera.PERSPECTIVE)

    Camera.set_near_range(self._left_camera, near)
    Camera.set_near_range(self._right_camera, near)
    Camera.set_far_range(self._left_camera, far)
    Camera.set_far_range(self._right_camera, far)

    Camera.set_frustum_half_angles(
        self._left_camera,
        self._left_eye_fov.left,
        self._left_eye_fov.right,
        self._left_eye_fov.down,
        self._left_eye_fov.up)

    Camera.set_frustum_half_angles(
        self._right_camera,
        self._right_eye_fov.left,
        self._right_eye_fov.right,
        self._right_eye_fov.down,
        self._right_eye_fov.up)

    GoogleVR.link_node_to_eye(
        self._left_camera_unit,
        Unit.node(self._left_camera_unit, "rp_root"),
        GoogleVR.LEFT_EYE,
        self._world)

    GoogleVR.link_node_to_eye(
        self._right_camera_unit,
        Unit.node(self._right_camera_unit, "rp_root"),
        GoogleVR.RIGHT_EYE,
        self._world)

    Application.set_render_setting("vr_enabled", "true")

    GoogleVR.show_ui_overlay()

    self.mag_i = 0
    self.mag_buffer = {}
    self.mag_buffer_l = 8
    self.mag_down = false
    self.mag_click = false

    for i=0,self.mag_buffer_l do
        self.mag_buffer[i] = Vector3Box(Vector3(0, 0, 0))
    end
end


function GoogleVRSystem:shutdown()
    if not GoogleVR then return end
    if not self or not self._is_initialized then return end

    GoogleVR.unlink_eye(GoogleVR.LEFT_EYE)
    GoogleVR.unlink_eye(GoogleVR.RIGHT_EYE)

    GoogleVR.hide_ui_overlay()

    GoogleVR.shutdown()
    Application.set_render_setting("vr_enabled", "false")

    if self._left_camera_unit then
        self._left_camera = nil
        World.destroy_unit(self._world, self._left_camera_unit)
        self._left_camera_unit = nil
    end

    if self._right_camera_unit then
        self._right_camera = nil
        World.destroy_unit(self._world, self._right_camera_unit)
        self._right_camera_unit = nil
    end

    if self._viewport_left then
        Application.destroy_viewport(self._world, self._viewport_left)
        self._viewport_left = nil
    end

    if self._viewport_right then
        Application.destroy_viewport(self._world, self._viewport_right)
        self._viewport_right = nil
    end
end

function GoogleVRSystem:check_controller_status()
    if not Appkit.Util.is_android() then return end
    if not GoogleVR then return end
    if not self or not self._is_initialized then return end

    local new_api_status = GoogleVR.controller_api_status()
    if new_api_status ~= self._controller_api_status then
        print(GoogleVR.controller_api_status_string(new_api_status))
        self._controller_api_status = new_api_status
    end

    local new_connection_status = GoogleVR.controller_connection_status()
    if new_connection_status ~= self._controller_connection_status then
        print(GoogleVR.controller_connection_status_string(new_connection_status))
        self._controller_connection_status = new_connection_status
    end

    return (self._controller_api_status == GoogleVR.STATUS_API_OK) and (self._controller_connection_status == GoogleVR.STATUS_CONNECTED)
end

function GoogleVRSystem:print_button_state(button)
    if not GoogleVR then return end
    if not self or not self._is_initialized then return end

    local new_button_state = GoogleVR.controller_held(button)
    if new_button_state ~= self._controller_button_state[button] then
        if new_button_state then
            print("Button ", button, " Pressed")
        else
            print("Button ", button, " Released")
        end
        self._controller_button_state[button] = new_button_state
    end
end

function GoogleVRSystem:print_buttons_state()
    if not GoogleVR then return end
    if not self or not self._is_initialized then return end

    self.print_button_state(self, GoogleVR.BUTTON_CLICK)
    self.print_button_state(self, GoogleVR.BUTTON_APP)
    self.print_button_state(self, GoogleVR.BUTTON_HOME)
    self.print_button_state(self, GoogleVR.BUTTON_VOLUME_UP)
    self.print_button_state(self, GoogleVR.BUTTON_VOLUME_DOWN)
end

function GoogleVRSystem:print_touch_position()
    if not GoogleVR then return end
    if not self or not self._is_initialized then return end

    local new_touch_position = GoogleVR.controller_touch_position()
    local old_touch_position = Vector2Box.unbox(self._controller_touch_position)
    if not Vector2.equal(new_touch_position, old_touch_position) then
        print("Touch Position: ", new_touch_position)
        Vector2Box.store(self._controller_touch_position, new_touch_position)
    end
end

function GoogleVRSystem:print_orientation()
    if not GoogleVR then return end
    if not self or not self._is_initialized then return end

    local new_orientation = GoogleVR.controller_orientation()
    local old_orientation = QuaternionBox.unbox(self._controller_orientation)
    if not Quaternion.equal(new_orientation, old_orientation) then
        print("Orientation: ", new_orientation)
        QuaternionBox.store(self._controller_orientation, new_orientation)
    end
end

function GoogleVRSystem:print_gyroscope()
    if not GoogleVR then return end
    if not self or not self._is_initialized then return end

    local new_gyroscope = GoogleVR.controller_gyroscope()
    local old_gyroscope = Vector3Box.unbox(self._controller_gyroscope)
    if not Vector3.equal(new_gyroscope, old_gyroscope) then
        print("Gyroscope: ", new_gyroscope)
        Vector3Box.store(self._controller_gyroscope, new_gyroscope)
    end
end

function GoogleVRSystem:print_acceleration()
    if not GoogleVR then return end
    if not self or not self._is_initialized then return end

    local new_acceleration = GoogleVR.controller_acceleration()
    local old_acceleration = Vector3Box.unbox(self._controller_acceleration)
    if not Vector3.equal(new_acceleration, old_acceleration) then
        print("Acceleration: ", new_acceleration)
        Vector3Box.store(self._controller_acceleration, new_acceleration)
    end
end

function GoogleVRSystem:update_magnet_clicker()
    if not GoogleVR then return end
    if not self or not self._is_initialized then return end

    local v = Sensor.magnetometer_magnetic_field()
    Vector3Box.store(self.mag_buffer[self.mag_i % self.mag_buffer_l], v)
    self.mag_i = self.mag_i+1
    local old = Vector3Box.unbox(self.mag_buffer[self.mag_i % self.mag_buffer_l])
    local new_mag_down = self.mag_down;
    if self.mag_i > self.mag_buffer_l+2 then
        local diff = old-v;
        local thres = 10

        local x = 0
        local y = 0
        local z = 0

        if diff.x < -thres then
            x = 1
        elseif diff.x > thres then
            x = -1
        end

        if diff.y < -thres then
            y = -1
        elseif diff.y > thres then
            y = 1
        end

        if diff.z < -thres then
            z = 1
        elseif diff.z > thres then
            z = -1
        end

        local total = x+y+z

        if total >= 2 then
            new_mag_down = true
        elseif total <= -2 then
            new_mag_down = false
        end
    end

    self.mag_click = new_mag_down and self.mag_down ~= new_mag_down
    self.mag_down = new_mag_down
    return self.mag_click
end

function GoogleVRSystem:magnet_clicker()
    return self.mag_click
end

function GoogleVRSystem:set_tracking_space_pose(pose)
    if not GoogleVR then return end
    if not self or not self._is_initialized then return end
    GoogleVR.set_tracking_space_pose(pose)
end

function GoogleVRSystem:render(shading_environment)
    if not GoogleVR then return end
    if not self or not self._is_initialized then return end
    Application.set_render_setting("vr_eye", "left")
    Application.render_world(self._world, self._left_camera, self._viewport_left, shading_environment)
    Application.set_render_setting("vr_eye", "right")
    Application.render_world(self._world, self._right_camera, self._viewport_right, shading_environment)
    Application.set_render_setting("vr_eye", "unknown")
end

return GoogleVRSystem