]> git.tdb.fi Git - libs/vr.git/blobdiff - source/oculusriftcombiner.cpp
Add support for time warp on Oculus Rift
[libs/vr.git] / source / oculusriftcombiner.cpp
index 5e76cc8305a21ee6c3594ee666d9d50076016ade..0cfd4ae1c6398701350c0a3c00114a0435447b8e 100644 (file)
@@ -11,16 +11,26 @@ using namespace std;
 namespace {
 
 const char vs_source[] =
+       "uniform mat4 timewarp[2];\n"
+       "uniform vec2 uv_scale;\n"
+       "uniform vec2 uv_offset;\n"
        "varying vec2 texcoord_r;\n"
        "varying vec2 texcoord_g;\n"
        "varying vec2 texcoord_b;\n"
        "varying float vignette;\n"
+       "vec2 apply_timewarp(vec2 coords, float factor)\n"
+       "{\n"
+       "       vec4 coords4 = vec4(coords, 1.0, 1.0);\n"
+       "       vec4 warped = mix(timewarp[0]*coords4, timewarp[1]*coords4, factor);\n"
+       "       return (warped.xy/warped.z)*uv_scale+uv_offset;\n"
+       "}\n"
        "void main()\n"
        "{\n"
        "       gl_Position = vec4(gl_Vertex.xy, 0.5, 1.0);\n"
-       "       texcoord_r = gl_MultiTexCoord0.xy;\n"
-       "       texcoord_g = gl_MultiTexCoord1.xy;\n"
-       "       texcoord_b = gl_MultiTexCoord2.xy;\n"
+       "       float tw_factor = gl_MultiTexCoord3.y;\n"
+       "       texcoord_r = apply_timewarp(gl_MultiTexCoord0.xy, tw_factor);\n"
+       "       texcoord_g = apply_timewarp(gl_MultiTexCoord1.xy, tw_factor);\n"
+       "       texcoord_b = apply_timewarp(gl_MultiTexCoord2.xy, tw_factor);\n"
        "       vignette = gl_MultiTexCoord3.x;\n"
        "}\n";
 
@@ -41,26 +51,16 @@ const char fs_source[] =
 void create_distortion_mesh(Msp::GL::Mesh &mesh, ovrHmd hmd, ovrEyeType eye, const ovrFovPort &fov)
 {
        ovrDistortionMesh ovr_mesh;
-       ovrHmd_CreateDistortionMesh(hmd, eye, fov, ovrDistortionCap_Chromatic|ovrDistortionCap_Vignette, &ovr_mesh);
-
-       ovrSizei tex_size = ovrHmd_GetFovTextureSize(hmd, eye, fov, 1.0);
-       ovrRecti view_rect;
-       view_rect.Pos.x = 0;
-       view_rect.Pos.y = 0;
-       view_rect.Size = tex_size;
-       ovrVector2f uv_scale_offset[2];
-       ovrHmd_GetRenderScaleAndOffset(fov, tex_size, view_rect, uv_scale_offset);
-       ovrVector2f &scale = uv_scale_offset[0];
-       ovrVector2f &offset = uv_scale_offset[1];
+       ovrHmd_CreateDistortionMesh(hmd, eye, fov, ovrDistortionCap_Chromatic|ovrDistortionCap_Vignette|ovrDistortionCap_TimeWarp, &ovr_mesh);
 
        Msp::GL::MeshBuilder bld(mesh);
        for(unsigned i=0; i<ovr_mesh.VertexCount; ++i)
        {
                ovrDistortionVertex &v = ovr_mesh.pVertexData[i];
-               bld.multitexcoord(0, v.TanEyeAnglesR.x*scale.x+offset.x, 1.0f-(v.TanEyeAnglesR.y*scale.y+offset.y));
-               bld.multitexcoord(1, v.TanEyeAnglesG.x*scale.x+offset.x, 1.0f-(v.TanEyeAnglesG.y*scale.y+offset.y));
-               bld.multitexcoord(2, v.TanEyeAnglesB.x*scale.x+offset.x, 1.0f-(v.TanEyeAnglesB.y*scale.y+offset.y));
-               bld.multitexcoord(3, v.VignetteFactor);
+               bld.multitexcoord(0, v.TanEyeAnglesR.x, v.TanEyeAnglesR.y);
+               bld.multitexcoord(1, v.TanEyeAnglesG.x, v.TanEyeAnglesG.y);
+               bld.multitexcoord(2, v.TanEyeAnglesB.x, v.TanEyeAnglesB.y);
+               bld.multitexcoord(3, v.VignetteFactor, v.TimeWarpFactor);
                bld.vertex(v.ScreenPosNDC.x, v.ScreenPosNDC.y);
        }
 
@@ -78,8 +78,8 @@ namespace VR {
 
 OculusRiftCombiner::OculusRiftCombiner(const OculusRiftDevice &d):
        device(d),
-       left_mesh((GL::VERTEX2, GL::TEXCOORD2,0, GL::TEXCOORD2,1, GL::TEXCOORD2,2, GL::TEXCOORD1,3)),
-       right_mesh((GL::VERTEX2, GL::TEXCOORD2,0, GL::TEXCOORD2,1, GL::TEXCOORD2,2, GL::TEXCOORD1,3)),
+       left_mesh((GL::VERTEX2, GL::TEXCOORD2,0, GL::TEXCOORD2,1, GL::TEXCOORD2,2, GL::TEXCOORD2,3)),
+       right_mesh((GL::VERTEX2, GL::TEXCOORD2,0, GL::TEXCOORD2,1, GL::TEXCOORD2,2, GL::TEXCOORD2,3)),
        shprog(vs_source, fs_source)
 {
        ovrHmd hmd = device.get_private().ovr_hmd;
@@ -107,19 +107,53 @@ OculusRiftCombiner::OculusRiftCombiner(const OculusRiftDevice &d):
        float aspect = (inner+outer)/(vertical*2);
        aspect_factor = aspect*hmd->Resolution.h/hmd->Resolution.w;
 
-       shdata.uniform("texture", 0);
+       left_shdata.uniform("texture", 0);
+       right_shdata.uniform("texture", 0);
 
+       ovrRecti view_rect;
+       view_rect.Pos.x = 0;
+       view_rect.Pos.y = 0;
+       view_rect.Size = tex_size;
+       ovrVector2f uv_scale_offset[2];
+       ovrHmd_GetRenderScaleAndOffset(left_fov, tex_size, view_rect, uv_scale_offset);
+       left_shdata.uniform("uv_scale", uv_scale_offset[0].x, -uv_scale_offset[0].y);
+       left_shdata.uniform("uv_offset", uv_scale_offset[1].x, 1-uv_scale_offset[1].y);
+       ovrHmd_GetRenderScaleAndOffset(right_fov, tex_size, view_rect, uv_scale_offset);
+       right_shdata.uniform("uv_scale", uv_scale_offset[0].x, -uv_scale_offset[0].y);
+       right_shdata.uniform("uv_offset", uv_scale_offset[1].x, 1-uv_scale_offset[1].y);
 }
 
 void OculusRiftCombiner::render(const GL::Texture2D &left, const GL::Texture2D &right) const
 {
        GL::Bind bind_shprog(shprog);
-       shdata.apply();
+
+       ovrHmd hmd = device.get_private().ovr_hmd;
+
+       if(device.is_timing_active())
+       {
+               ovr_WaitTillTime(device.get_timewarp_time());
+               ovrTrackingState state = ovrHmd_GetTrackingState(hmd, device.get_tracking_time());
+
+               ovrMatrix4f matrices[2];
+               ovrHmd_GetEyeTimewarpMatrices(hmd, ovrEye_Left, state.HeadPose.ThePose, matrices);
+               left_shdata.uniform_matrix4_array("timewarp", 2, &matrices[0].M[0][0]);
+
+               ovrHmd_GetEyeTimewarpMatrices(hmd, ovrEye_Right, state.HeadPose.ThePose, matrices);
+               right_shdata.uniform_matrix4_array("timewarp", 2, &matrices[0].M[0][0]);
+       }
+       else
+       {
+               GL::Matrix matrices[2];
+               left_shdata.uniform_matrix4_array("timewarp", 2, matrices[0].data());
+               right_shdata.uniform_matrix4_array("timewarp", 2, matrices[0].data());
+       }
 
        GL::Bind bind_tex(left);
+       left_shdata.apply();
        left_mesh.draw();
 
        right.bind();
+       right_shdata.apply();
        right_mesh.draw();
 }