Render eye view with off-center projection to better match visible area
authorMikko Rasa <tdb@tdb.fi>
Sat, 21 Sep 2013 17:10:19 +0000 (20:10 +0300)
committerMikko Rasa <tdb@tdb.fi>
Sat, 21 Sep 2013 17:10:19 +0000 (20:10 +0300)
source/oculusriftcombiner.cpp
source/stereocombiner.cpp
source/stereocombiner.h
source/stereoview.cpp
source/stereoview.h

index b15c86be54a41e6e3d54b82702bd945b605e1bf3..3ebbcc88914aea5d070bf265c5cd27556cf5274c 100644 (file)
@@ -22,6 +22,7 @@ const char fs_source[] =
        "uniform sampler2D texture;\n"
        "uniform vec4 distortion;\n"
        "uniform vec4 chromatic;\n"
+       "uniform vec2 lens_center;\n"
        "uniform vec2 eye_center;\n"
        "uniform vec3 scale;\n"
        "varying vec2 texcoord;\n"
@@ -29,13 +30,13 @@ const char fs_source[] =
        "{\n"
        "       float r_sq = dot(texcoord, texcoord);\n"
        "       float f = dot(distortion, vec4(1.0, r_sq, r_sq*r_sq, r_sq*r_sq*r_sq));\n"
-       "       vec2 dtc = (texcoord*f-eye_center)/(scale.xy*scale.z)+0.5;\n"
+       "       vec2 dtc = (texcoord*f-eye_center)/(scale.xy*scale.z)+lens_center;\n"
        "       if(dtc.x<0.0 || dtc.y<0.0 || dtc.x>1.0 || dtc.y>1.0)\n"
        "               gl_FragColor = vec4(0.0);\n"
        "       else\n"
        "       {\n"
-       "               vec2 red_dtc = (texcoord*f*(chromatic[0]+chromatic[1]*r_sq)-eye_center)/(scale.xy*scale.z)+0.5;\n"
-       "               vec2 blue_dtc = (texcoord*f*(chromatic[2]+chromatic[3]*r_sq)-eye_center)/(scale.xy*scale.z)+0.5;\n"
+       "               vec2 red_dtc = (texcoord*f*(chromatic[0]+chromatic[1]*r_sq)-eye_center)/(scale.xy*scale.z)+lens_center;\n"
+       "               vec2 blue_dtc = (texcoord*f*(chromatic[2]+chromatic[3]*r_sq)-eye_center)/(scale.xy*scale.z)+lens_center;\n"
        "               gl_FragColor = vec4(texture2D(texture, red_dtc).r, texture2D(texture, dtc).g, texture2D(texture, blue_dtc).b, 1.0);\n"
        "       }\n"
        "}\n";
@@ -155,6 +156,7 @@ void OculusRiftCombiner::update_parameters()
        right_shdata.uniform("scale", 2.0f, 2.5f, oversize);
 
        fov = Geometry::atan(oversize*0.625f/view_distance)*2.0f;
+       frustum_skew = lens_separation*2-1;
 }
 
 float OculusRiftCombiner::distort(float r) const
index 54ab3e3218e7e265d4e9c88b72163ca0cca9d321..a276c3bc3c677ad2ba24f49df1b435e572842156 100644 (file)
@@ -7,7 +7,8 @@ StereoCombiner::StereoCombiner():
        width_div(1),
        height_div(1),
        keep_aspect(false),
-       oversize(1.0f)
+       oversize(1.0f),
+       frustum_skew(0.0f)
 { }
 
 } // namespace VR
index f078df773592531fe9b8ad79b3aa74d6321b5bc2..23d482267e0ad706a1575a70657d4dbd1725d7da 100644 (file)
@@ -15,6 +15,7 @@ protected:
        bool keep_aspect;
        Geometry::Angle<float> fov;
        float oversize;
+       float frustum_skew;
 
        StereoCombiner();
 public:
@@ -25,6 +26,7 @@ public:
        bool is_aspect_kept() const { return keep_aspect; }
        const Geometry::Angle<float> &get_field_of_view() const { return fov; }
        float get_oversize() const { return oversize; }
+       float get_frustum_skew() const { return frustum_skew; }
 
        virtual void render(const GL::Texture2D &, const GL::Texture2D &) const = 0;
 };
index c52802309ef5119677e2451ddc81c9a63717a1cb..08949e653599509021f24eb29b2f9b37f41a6826 100644 (file)
@@ -49,8 +49,10 @@ void StereoView::setup_frame() const
        params.near_clip = base_camera.get_near_clip();
        params.far_clip = base_camera.get_far_clip();
 
-       left.setup_frame(base_camera, offset_axis*-eye_spacing, params);
-       right.setup_frame(base_camera, offset_axis*eye_spacing, params);
+       float frustum_skew = combiner->get_frustum_skew();
+
+       left.setup_frame(base_camera, offset_axis*-eye_spacing, frustum_skew, params);
+       right.setup_frame(base_camera, offset_axis*eye_spacing, -frustum_skew, params);
 
        renderable.setup_frame();
 }
@@ -98,7 +100,7 @@ void StereoView::Eye::create_target(unsigned w, unsigned h)
        target = new RenderTarget(w, h);
 }
 
-void StereoView::Eye::setup_frame(const GL::Camera &base_camera, const GL::Vector3 &offset, const EyeParams &params) const
+void StereoView::Eye::setup_frame(const GL::Camera &base_camera, const GL::Vector3 &offset, float frustum_skew, const EyeParams &params) const
 {
        camera.set_position(base_camera.get_position()+offset);
        camera.set_up_direction(base_camera.get_up_direction());
@@ -107,6 +109,7 @@ void StereoView::Eye::setup_frame(const GL::Camera &base_camera, const GL::Vecto
        camera.set_field_of_view(params.fov);
        camera.set_aspect(params.aspect);
        camera.set_depth_clip(params.near_clip, params.far_clip);
+       camera.set_frustum_axis(frustum_skew, 0);
 }
 
 void StereoView::Eye::render(const GL::Renderable &renderable, const GL::Tag &tag) const
index fe3d6d6b82f57de8a920ea01c326ccde6c817748..5516823ccb1a219f7c689975514fc5fa85ffee08 100644 (file)
@@ -41,7 +41,7 @@ private:
                Eye();
 
                void create_target(unsigned, unsigned);
-               void setup_frame(const GL::Camera &, const GL::Vector3 &, const EyeParams &) const;
+               void setup_frame(const GL::Camera &, const GL::Vector3 &, float, const EyeParams &) const;
                void render(const GL::Renderable &, const GL::Tag &) const;
        };