--- /dev/null
+#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
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
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);
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
{
private:
const OculusRiftDevice &device;
- const GL::Camera &base_camera;
public:
OculusRiftCamera(const OculusRiftDevice &, const GL::Camera &);
-#include <cmath>
#include <msp/gl/meshbuilder.h>
#include <msp/gl/texture2d.h>
#include "oculusriftcombiner.h"
namespace Msp {
namespace VR {
+struct OculusRiftCombiner::Frustum: StereoCombiner::Frustum
+{
+ Frustum(const ovrFovPort &);
+};
+
+
OculusRiftCombiner::OculusRiftCombiner(OculusRiftDevice &d, GL::View &v):
device(d),
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);
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);
device.end_frame();
}
+
+OculusRiftCombiner::Frustum::Frustum(const ovrFovPort &fov):
+ StereoCombiner::Frustum(-fov.LeftTan, fov.RightTan, -fov.DownTan, fov.UpTan)
+{ }
+
} // namespace VR
} // namespace Msp
class OculusRiftCombiner: public StereoCombiner
{
private:
+ struct Frustum;
+
OculusRiftDevice &device;
GL::View &view;
GL::Mesh left_mesh;
+#include <algorithm>
#include "stereocombiner.h"
+using namespace std;
+
namespace Msp {
namespace VR {
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
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;
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; }