Move some common calculations to base classes
authorMikko Rasa <tdb@tdb.fi>
Sat, 17 Sep 2016 23:20:01 +0000 (02:20 +0300)
committerMikko Rasa <tdb@tdb.fi>
Sat, 17 Sep 2016 23:20:01 +0000 (02:20 +0300)
source/headtrackingcamera.cpp [new file with mode: 0644]
source/headtrackingcamera.h
source/ovr/oculusriftcamera.cpp
source/ovr/oculusriftcamera.h
source/ovr/oculusriftcombiner.cpp
source/ovr/oculusriftcombiner.h
source/stereocombiner.cpp
source/stereocombiner.h

diff --git a/source/headtrackingcamera.cpp b/source/headtrackingcamera.cpp
new file mode 100644 (file)
index 0000000..95868e2
--- /dev/null
@@ -0,0 +1,24 @@
+#include "headtrackingcamera.h"
+
+namespace Msp {
+namespace VR {
+
+HeadTrackingCamera::HeadTrackingCamera(const GL::Camera &c):
+       base_camera(c)
+{ }
+
+void HeadTrackingCamera::update_from_matrix(const GL::Matrix &hmd_matrix)
+{
+       GL::Matrix matrix = base_camera.get_object_matrix()*hmd_matrix;
+
+       set_position(matrix*GL::Vector3());
+       set_look_direction((matrix*GL::Vector4(0, 0, -1, 0)).slice<3>(0));
+       set_up_direction((matrix*GL::Vector4(0, 1, 0, 0)).slice<3>(0));
+
+       set_depth_clip(base_camera.get_near_clip(), base_camera.get_far_clip());
+       set_field_of_view(base_camera.get_field_of_view());
+       set_aspect(base_camera.get_aspect());
+}
+
+} // namespace VR
+} // namespace Msp
index 36f0170209b7ad64b639557cbe1a4b783d521059..5bb911e72deeccd61d2bfd2d8e77221f789876a4 100644 (file)
@@ -9,13 +9,16 @@ namespace VR {
 class HeadTrackingCamera: public Msp::GL::Camera
 {
 protected:
-       HeadTrackingCamera() { }
+       const GL::Camera &base_camera;
 
+       HeadTrackingCamera(const GL::Camera &);
 public:
        virtual ~HeadTrackingCamera() { }
 
        virtual void reset_tracking() { }
        virtual void update() = 0;
+protected:
+       void update_from_matrix(const GL::Matrix &);
 };
 
 } // namespace VR
index 0eede270de864b92f17bf18031c0d012cf2b1a65..713ae3cec5a480f5bc943fb1572856e4507c6fda 100644 (file)
@@ -6,8 +6,8 @@ namespace Msp {
 namespace VR {
 
 OculusRiftCamera::OculusRiftCamera(const OculusRiftDevice &d, const GL::Camera &c):
-       device(d),
-       base_camera(c)
+       HeadTrackingCamera(c),
+       device(d)
 {
        unsigned supported = ovrTrackingCap_Orientation|ovrTrackingCap_MagYawCorrection|ovrTrackingCap_Position;
        ovrHmd_ConfigureTracking(device.get_private().ovr_hmd, supported, 0);
@@ -28,20 +28,8 @@ void OculusRiftCamera::update()
 
        ovrTrackingState state = ovrHmd_GetTrackingState(device.get_private().ovr_hmd, time);
        OVR::Posef head_pose = state.HeadPose.ThePose;
-       OVR::Matrix4f tracking_matrix(head_pose.Rotation);
-       OVR::Vector3f trans = head_pose.Translation;
-       const float *m = &tracking_matrix.M[0][0];
-
-       const GL::Vector3 &base_look = base_camera.get_look_direction();
-       GL::Vector3 base_right = normalize(cross(base_look, base_camera.get_up_direction()));
-       GL::Vector3 base_up = normalize(cross(base_right, base_look));
-
-       set_position(base_camera.get_position()+trans.x*base_right+trans.y*base_up-trans.z*base_look);
-       set_up_direction(base_right*m[1]+base_up*m[5]-base_look*m[9]);
-       set_look_direction(-base_right*m[2]-base_up*m[6]+base_look*m[10]);
-       set_depth_clip(base_camera.get_near_clip(), base_camera.get_far_clip());
-       set_field_of_view(base_camera.get_field_of_view());
-       set_aspect(base_camera.get_aspect());
+       OVR::Matrix4f tracking_matrix(head_pose);
+       update_from_matrix(transpose(GL::Matrix(&tracking_matrix.M[0][0])));
 }
 
 } // namespace VR
index a2b0b28925f1a5ec6e7d826432a02398615812d0..b6acae1691648786aaf76dacb51b292c1596f7c5 100644 (file)
@@ -12,7 +12,6 @@ class OculusRiftCamera: public HeadTrackingCamera
 {
 private:
        const OculusRiftDevice &device;
-       const GL::Camera &base_camera;
 
 public:
        OculusRiftCamera(const OculusRiftDevice &, const GL::Camera &);
index b9515edcddb9ff8b9161dac229b62d080862d983..2d40ea95c1ff0e00b2231c94d812874f675ba11e 100644 (file)
@@ -1,4 +1,3 @@
-#include <cmath>
 #include <msp/gl/meshbuilder.h>
 #include <msp/gl/texture2d.h>
 #include "oculusriftcombiner.h"
@@ -76,6 +75,12 @@ void create_distortion_mesh(Msp::GL::Mesh &mesh, ovrHmd hmd, ovrEyeType eye, con
 namespace Msp {
 namespace VR {
 
+struct OculusRiftCombiner::Frustum: StereoCombiner::Frustum
+{
+       Frustum(const ovrFovPort &);
+};
+
+
 OculusRiftCombiner::OculusRiftCombiner(OculusRiftDevice &d, GL::View &v):
        device(d),
        view(v),
@@ -87,17 +92,13 @@ OculusRiftCombiner::OculusRiftCombiner(OculusRiftDevice &d, GL::View &v):
 
        ovrFovPort left_fov = hmd->DefaultEyeFov[ovrEye_Left];
        ovrFovPort right_fov = hmd->DefaultEyeFov[ovrEye_Right];
-       float vertical = max(max(left_fov.UpTan, left_fov.DownTan), max(right_fov.UpTan, right_fov.DownTan));
-       fov = Geometry::atan<float>(vertical)*2.0f;
+       configure_eye_frustums(Frustum(left_fov), Frustum(right_fov));
 
-       float inner = max(left_fov.RightTan, right_fov.LeftTan);
-       float outer = max(left_fov.LeftTan, right_fov.RightTan);
-       frustum_skew = (inner-outer)/(inner+outer);
-
-       left_fov.UpTan = right_fov.UpTan = vertical;
-       left_fov.DownTan = right_fov.DownTan = vertical;
-       left_fov.RightTan = right_fov.LeftTan = inner;
-       left_fov.LeftTan = right_fov.RightTan = outer;
+       left_fov.UpTan = left_fov.DownTan = tan(fov/2.0f);
+       left_fov.LeftTan = left_fov.UpTan*render_aspect*(1-frustum_skew);
+       left_fov.RightTan = left_fov.UpTan*render_aspect*(1+frustum_skew);
+       right_fov = left_fov;
+       swap(right_fov.LeftTan, right_fov.RightTan);
 
        create_distortion_mesh(left_mesh, hmd, ovrEye_Left, left_fov);
        create_distortion_mesh(right_mesh, hmd, ovrEye_Right, right_fov);
@@ -105,7 +106,6 @@ OculusRiftCombiner::OculusRiftCombiner(OculusRiftDevice &d, GL::View &v):
        ovrSizei tex_size = ovrHmd_GetFovTextureSize(hmd, ovrEye_Left, left_fov, 1.0);
        target_width = tex_size.w;
        target_height = tex_size.h;
-       render_aspect = (inner+outer)/(vertical*2);
 
        left_shdata.uniform("texture", 0);
        right_shdata.uniform("texture", 0);
@@ -167,5 +167,10 @@ void OculusRiftCombiner::render(const GL::Texture2D &left, const GL::Texture2D &
        device.end_frame();
 }
 
+
+OculusRiftCombiner::Frustum::Frustum(const ovrFovPort &fov):
+       StereoCombiner::Frustum(-fov.LeftTan, fov.RightTan, -fov.DownTan, fov.UpTan)
+{ }
+
 } // namespace VR
 } // namespace Msp
index 27c3c83bac49caa7ad8a0d7e590e34d7ac8b4ea9..14f0e4cdc7c3603d8100f3aaf984991a9b57d39a 100644 (file)
@@ -19,6 +19,8 @@ are specified in multiples of the screen width.
 class OculusRiftCombiner: public StereoCombiner
 {
 private:
+       struct Frustum;
+
        OculusRiftDevice &device;
        GL::View &view;
        GL::Mesh left_mesh;
index c24a937484aae3c162de692dee4d143959cc2176..75c788997e770fa0f1a7340d03b578e969062d51 100644 (file)
@@ -1,5 +1,8 @@
+#include <algorithm>
 #include "stereocombiner.h"
 
+using namespace std;
+
 namespace Msp {
 namespace VR {
 
@@ -10,5 +13,32 @@ StereoCombiner::StereoCombiner():
        frustum_skew(0.0f)
 { }
 
+void StereoCombiner::configure_eye_frustums(const Frustum &left_frustum, const Frustum &right_frustum)
+{
+       float vertical = max(max(left_frustum.top, -left_frustum.bottom), max(right_frustum.top, -right_frustum.bottom));
+       fov = Geometry::atan<float>(vertical)*2.0f;
+
+       float inner = max(left_frustum.right, -right_frustum.left);
+       float outer = max(-left_frustum.left, right_frustum.right);
+       frustum_skew = (inner-outer)/(inner+outer);
+
+       render_aspect = (inner+outer)/(vertical*2);
+}
+
+
+StereoCombiner::Frustum::Frustum():
+       left(-1),
+       right(1),
+       bottom(-1),
+       top(1)
+{ }
+
+StereoCombiner::Frustum::Frustum(float l, float r, float b, float t):
+       left(l),
+       right(r),
+       bottom(b),
+       top(t)
+{ }
+
 } // namespace VR
 } // namespace Msp
index 5439aeba673da3a0d46de75a60e1445995e2dd7a..bef0849b39ee4a460d8c8c838957286f70dc4fa9 100644 (file)
@@ -10,6 +10,17 @@ namespace VR {
 class StereoCombiner
 {
 protected:
+       struct Frustum
+       {
+               float left;
+               float right;
+               float bottom;
+               float top;
+
+               Frustum();
+               Frustum(float, float, float, float);
+       };
+
        unsigned target_width;
        unsigned target_height;
        float render_aspect;
@@ -20,6 +31,9 @@ protected:
 public:
        virtual ~StereoCombiner() { }
 
+protected:
+       void configure_eye_frustums(const Frustum &, const Frustum &);
+public:
        float get_target_width() const { return target_width; }
        float get_target_height() const { return target_height; }
        float get_render_aspect() const { return render_aspect; }