Search code examples
game-enginevirtual-reality

Turning a C++ Application into VR


I have a working c++ application using openGL and Cuda, and want to convert it to a VR application. I searched the internet and it seems that the standard way to develop VR apps is to use a game engine (unity or unreal). Is there any other possible ways to avoid using one of these, and just convert my already existing application into VR?


Solution

  • The usual approach is, that at the start of render of a frame, you're polling the VR API for each eye's projection and "camera" translation matrix, then use that, to render into textures using an FBO, and at the end pass the IDs of those textures back to the API. With OpenVR:

    Initialize the FBO

    vr::EVRInitError err_hmd = vr::VRInitError_None;
    m_hmd = vr::VR_Init(&err_hmd, vr::VRApplication_Scene);
    if( err_hmd != vr::VRInitError_None ){
        m_hmd = nullptr;
    }
    if( m_hmd ){
        m_hmd->GetRecommendedRenderTargetSize(&m_hmd_width, &m_hmd_height);
        mat44_from_hmd44(m_prj_l, m_hmd->GetProjectionMatrix(vr::Eye_Left,  0.01f, 10.f) );
        mat44_from_hmd44(m_prj_r, m_hmd->GetProjectionMatrix(vr::Eye_Right, 0.01f, 10.f) );
    
        mat44_from_hmd34(m_eye_l, m_hmd->GetEyeToHeadTransform(vr::Eye_Left)  );
        mat44_from_hmd34(m_eye_r, m_hmd->GetEyeToHeadTransform(vr::Eye_Right) );
    
        if( !vr::VRCompositor() ){
            vr::VR_Shutdown();
            m_hmd = nullptr;
        }
    
        m_timer_vr = startTimer(1000/50);
    } else {
    }
    
    if( m_hmd_width && m_hmd_height ){
        qDebug() << "resize to" << m_hmd_width << m_hmd_height;
        eye_target_textures.create(m_hmd_width, m_hmd_height);
    }
    

    Update the HMD pose:

    vr::VREvent_t vrev;
    while( m_hmd->PollNextEvent(&vrev, sizeof(vrev)) );
    
    // Process SteamVR action state
    // UpdateActionState is called each frame to update the state of the actions themselves. The application
    // controls which action sets are active with the provided array of VRActiveActionSet_t structs.
    vr::VRActiveActionSet_t actionSet = { 0 };
    vr::VRInput()->UpdateActionState( &actionSet, sizeof(actionSet), 1 );
    
    vr::TrackedDevicePose_t tdp[ vr::k_unMaxTrackedDeviceCount ];
    vr::VRCompositor()->WaitGetPoses(tdp, vr::k_unMaxTrackedDeviceCount, NULL, 0);
    
    mat4x4_translate(m_pose, 0, 0, -1);
    
    for( int i = 0; i < vr::k_unMaxTrackedDeviceCount; ++i ){
        if( !tdp[i].bPoseIsValid ){ continue; }
    
        switch( m_hmd->GetTrackedDeviceClass(i) ){
        case vr::TrackedDeviceClass_HMD:
            mat44_from_hmd34(m_pose, tdp[i].mDeviceToAbsoluteTracking );
            break;
        }
    }
    

    Then when rendering you use m_pose and the m_eye… matrices.