Oculus VR template: /project.lua — code sample - Stingray Lua API Reference

Oculus VR template: /project.lua — code sample

Code

-----------------------------------------------------------------------------------
-- This implementation uses the default SimpleProject and the Project extensions are
-- used to extend the SimpleProject behavior.

-- This is the global table name used by Appkit Basic project to extend behavior
Project = Project or {}

require 'script/lua/flow_callbacks'
require 'vr_oculus/script/lua/oculus_vr_flow_callbacks'

Project.level_names = {
    floorplan = "content/levels/vr_learning"
}

require 'core/appkit/lua/simple_project'
SimpleProject = SimpleProject or {}

-- Oculus device
require 'vr_oculus/script/lua/oculus_vr'
OculusVRSystem = OculusVRSystem or {}

-- Oculus input mapper
require 'vr_oculus/script/lua/oculus_input_mapper'
OculusInputMapper = OculusInputMapper or {}

local vr_system = nil
local vr_input_mapper = nil
local vr_player_height = 1.778
local vr_eye_height = 1.675

-- Can provide a config for the basic project, or it will use a default if not.
SimpleProject.config = {
    standalone_init_level_name = Project.level_names.floorplan,
    camera_unit = "core/appkit/units/camera/camera",
    camera_index = 1,
    shading_environment = nil, -- Will override levels that have env set in editor.
    create_free_cam_player = false, -- Project will provide its own player.
    exit_standalone_with_esc_key = true
    -- Loading screen disabled until 2D gui VR is fully supported.
    -- loading_screen_materials = {"core/appkit/materials/loading_screen"},
    -- loading_screen_start_package = "loading_screen",
    -- loading_screen_end_package = "main",
    -- loading_screen_shading_env = "core/stingray_renderer/environments/midday/midday" -- Controls the shading environment used by default by the loading screen.
}

-- check to see if there are player starts in the level, if not return world 0
local function get_player_start_pose()
    local player_starts = stingray.World.units_by_resource(SimpleProject.world, "tools/player_start")
    if #player_starts > 0 then
        local index = stingray.Math.random(1, #player_starts)
        local pose = stingray.Unit.world_pose(player_starts[index], 1)
        local scale = stingray.Unit.local_scale(player_starts[index], 1)
        stingray.Matrix4x4.set_scale(pose, scale)
        return pose
    else
        return stingray.Matrix4x4.identity()
    end
end

-- return a new quaternion containing only euler z-axis rotation
local function get_rotation_z(rotation)
    local _, _, euler_z = stingray.Quaternion.to_euler_angles_xyz(rotation)
    return stingray.Quaternion(stingray.Vector3.up(), math.rad(euler_z))
end


-- This optional function is called by SimpleProject after level, world and player is loaded
-- but before lua trigger level loaded node is activated.
function Project.on_level_load_pre_flow()
    -- Spawn the player for all non-menu levels.
    -- level_name will be nil if this
    -- is an unsaved Test Level.
    local level_name = SimpleProject.level_name
    local managed_world = Appkit.managed_world;

    -- Create and setup an Oculus device for project
    local managed_world = Appkit.managed_world
    vr_system = OculusVRSystem(managed_world.world)
    Project.vr_system = vr_system
    OculusVRSystem.initialize(vr_system, 0.01, 1000.0, "vr_target", "vr_hud")
    OculusVRSystem.enable(vr_system)

    vr_input_mapper = OculusInputMapper(vr_system)

    local view_position = Appkit.get_editor_view_position() or stingray.Vector3(10, 1, vr_player_height)
    local view_rotation = Appkit.get_editor_view_rotation() or stingray.Quaternion.identity()
    local view_scale = stingray.Vector3(1,1,1)


    -- If an Oculus profile is found use it's data to initialize local values
    local vr_profile = OculusVRSystem.profile(vr_system)
    if vr_profile then
        vr_player_height = vr_profile.player_height
        vr_eye_height = vr_profile.eye_height
    end
    -- Fixes Oculus tracking origin
    vr_player_height = vr_player_height / 2
    vr_eye_height = vr_eye_height / 2
    Project.vr_eye_height = vr_eye_height

    if OculusVRSystem.is_enabled(vr_system) then
        if LEVEL_EDITOR_TEST then
            OculusVRSystem.set_tracking_space(vr_system, stingray.Matrix4x4.from_quaternion_position(get_rotation_z(view_rotation), view_position, view_scale))
        else
            local player_start_pose = get_player_start_pose()
            local player_start_position = stingray.Matrix4x4.transform(player_start_pose, stingray.Vector3(0, 0, vr_player_height))
            stingray.Matrix4x4.set_translation(player_start_pose, player_start_position)

            OculusVRSystem.set_tracking_space(vr_system, stingray.Matrix4x4.translation(player_start_pose), stingray.Matrix4x4.rotation(player_start_pose), stingray.Matrix4x4.scale(player_start_pose))
        end
    else
        if not LEVEL_EDITOR_TEST then
            local player_start_pose = get_player_start_pose()
            local player_start_position = stingray.Matrix4x4.transform(player_start_pose, stingray.Vector3(0, 0, vr_player_height))
            stingray.Matrix4x4.set_translation(player_start_pose, player_start_position)
            view_position = stingray.Matrix4x4.translation(player_start_pose)
            view_rotation = stingray.Matrix4x4.rotation(player_start_pose)
        end

        local Player = require 'script/lua/player'
        Player.set_default_character_eye_height(vr_eye_height)
        Player.spawn_player(SimpleProject.level, view_position, view_rotation, vr_input_mapper)
    end
end

function Project.on_level_shutdown_post_flow()
end

-- Optional function called by SimpleProject after world update (we will probably want to split to pre/post appkit calls)
function Project.update(dt)
    if not vr_system then return end

    -- Update Oculus tracking space pose
    local managed_world = Appkit.managed_world;

    -- Update input
    OculusInputMapper.update(vr_input_mapper, dt)

    if not OculusVRSystem.is_enabled(vr_system) then return end

    -- Press 'r' key to recenter Oculus pose
    if stingray.Keyboard.pressed(stingray.Keyboard.button_id('r')) then
        OculusVRSystem.recenter(vr_system)
    end

    -- Update the Wwise Listener to include the Oculus device pose
    if stingray.Wwise then
        local eye_poses = OculusInputMapper.get_eye_poses(vr_input_mapper)
        stingray.WwiseWorld.set_listener(
            stingray.Wwise.wwise_world(managed_world.world),
            stingray.Wwise.LISTENER_0,
            eye_poses.left_eye
            )
    end
end

-- Optional function called by SimpleProject *before* appkit/level/player/world shutdown
function Project.shutdown()
    OculusVRSystem.shutdown(vr_system)
end

function Project.render()
    if OculusVRSystem.is_enabled(vr_system) then
        local managed_world = Appkit.managed_world
        OculusVRSystem.render(vr_system, managed_world.shading_env)
        return true -- Override the regular SimpleProject rendering with VR rendering
    end
end

return Project