From 654b8083e06fb9f3338f7148bfd30b6305c7c5be Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Tue, 23 Dec 2014 00:13:47 +0200 Subject: [PATCH] Convert Oculus code to use SDK 0.4.4 The resulting aspect ratio might be subtly wrong at this point. Some changes are required for proper support. --- source/oculusriftcamera.cpp | 15 +- source/oculusriftcamera.h | 3 - source/oculusriftcombiner.cpp | 220 ++++++++++-------------------- source/oculusriftcombiner.h | 31 +---- source/oculusriftdevice.cpp | 28 ++-- source/oculusriftdevice.h | 2 + source/oculusriftdevice_private.h | 3 +- 7 files changed, 102 insertions(+), 200 deletions(-) diff --git a/source/oculusriftcamera.cpp b/source/oculusriftcamera.cpp index 2a8af2b..8b98adb 100644 --- a/source/oculusriftcamera.cpp +++ b/source/oculusriftcamera.cpp @@ -1,5 +1,4 @@ #include "oculusriftcamera.h" -#include "oculusriftcamera_private.h" #include "oculusriftdevice.h" #include "oculusriftdevice_private.h" @@ -8,23 +7,23 @@ namespace VR { OculusRiftCamera::OculusRiftCamera(const OculusRiftDevice &d, const GL::Camera &c): device(d), - base_camera(c), - priv(new Private) + base_camera(c) { const OculusRiftDevice::Private &dev_priv = device.get_private(); - priv->ovr_sensor = dev_priv.ovr_hmd->GetSensor(); - priv->fusion.AttachToSensor(priv->ovr_sensor); + unsigned supported = ovrTrackingCap_Orientation|ovrTrackingCap_MagYawCorrection; + ovrHmd_ConfigureTracking(dev_priv.ovr_hmd, supported, 0); } OculusRiftCamera::~OculusRiftCamera() { - delete priv; } void OculusRiftCamera::update() { - OVR::Matrix4f sensor_matrix = priv->fusion.GetOrientation(); - const float *m = &sensor_matrix.M[0][0]; + ovrTrackingState state = ovrHmd_GetTrackingState(device.get_private().ovr_hmd, ovr_GetTimeInSeconds()); + OVR::Posef head_pose = state.HeadPose.ThePose; + OVR::Matrix4f tracking_matrix(head_pose.Rotation); + 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())); diff --git a/source/oculusriftcamera.h b/source/oculusriftcamera.h index bff9967..525f7c6 100644 --- a/source/oculusriftcamera.h +++ b/source/oculusriftcamera.h @@ -11,11 +11,8 @@ class OculusRiftDevice; class OculusRiftCamera: public HeadTrackingCamera { private: - struct Private; - const OculusRiftDevice &device; const GL::Camera &base_camera; - Private *priv; public: OculusRiftCamera(const OculusRiftDevice &, const GL::Camera &); diff --git a/source/oculusriftcombiner.cpp b/source/oculusriftcombiner.cpp index 67b4729..e6b2908 100644 --- a/source/oculusriftcombiner.cpp +++ b/source/oculusriftcombiner.cpp @@ -2,195 +2,121 @@ #include #include #include "oculusriftcombiner.h" +#include "oculusriftdevice.h" +#include "oculusriftdevice_private.h" using namespace std; + namespace { const char vs_source[] = - "uniform float offset;\n" - "uniform vec2 lens_center;\n" - "uniform vec3 scale;\n" - "varying vec2 texcoord;\n" + "varying vec2 texcoord_r;\n" + "varying vec2 texcoord_g;\n" + "varying vec2 texcoord_b;\n" "void main()\n" "{\n" - " gl_Position = vec4(gl_Vertex.x*0.5+offset, gl_Vertex.yzw);\n" - " texcoord = (gl_Vertex.xy*0.5+0.5-lens_center)*scale.xy;\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" "}\n"; 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" + "varying vec2 texcoord_r;\n" + "varying vec2 texcoord_g;\n" + "varying vec2 texcoord_b;\n" "void main()\n" "{\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)+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)+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" + " float r = texture2D(texture, texcoord_r).r;\n" + " float g = texture2D(texture, texcoord_g).g;\n" + " float b = texture2D(texture, texcoord_b).b;\n" + " gl_FragColor = vec4(r, g, b, 1.0);\n" "}\n"; -} - -namespace Msp { -namespace VR { - -OculusRiftCombiner::OculusRiftCombiner(): - mesh(GL::VERTEX2), - shprog(vs_source, fs_source), - // Default values copied from the SDK - view_distance(0.438f), - lens_separation(0.424f), - eye_separation(0.42735f), - fill_factor(0.95f) +void create_distortion_mesh(Msp::GL::Mesh &mesh, ovrHmd hmd, ovrEyeType eye, const ovrFovPort &fov) { - width_div = 2; - - left_shdata.uniform("texture", 0); - left_shdata.uniform("offset", -0.5f); - right_shdata.uniform("texture", 0); - right_shdata.uniform("offset", 0.5f); - - chromatic[0] = 1.0f; - chromatic[1] = 0.0f; - chromatic[2] = 1.0f; - chromatic[3] = 0.0f; - - // This will also call update_parameters - set_distortion(1.0f, 0.22f, 0.24f); - - GL::MeshBuilder bld(mesh); - bld.begin(GL::TRIANGLE_STRIP); - bld.vertex(-1, 1); - bld.vertex(-1, -1); - bld.vertex(1, 1); - bld.vertex(1, -1); - bld.end(); -} + ovrDistortionMesh ovr_mesh; + ovrHmd_CreateDistortionMesh(hmd, eye, fov, ovrDistortionCap_Chromatic, &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]; + + Msp::GL::MeshBuilder bld(mesh); + for(unsigned i=0; i(ovr_mesh.pIndexData, ovr_mesh.pIndexData+ovr_mesh.IndexCount)); + mesh.add_batch(batch); -void OculusRiftCombiner::set_lens_separation(float s) -{ - lens_separation = s; - update_parameters(); + ovrHmd_DestroyDistortionMesh(&ovr_mesh); } -void OculusRiftCombiner::set_eye_separation(float s) -{ - eye_separation = s; - update_parameters(); } -void OculusRiftCombiner::set_distortion(float d0, float d1, float d2, float d3) -{ - distortion[0] = d0; - distortion[1] = d1; - distortion[2] = d2; - distortion[3] = d3; - - update_parameters(); -} +namespace Msp { +namespace VR { -void OculusRiftCombiner::set_red_aberration(float c0, float c1) +OculusRiftCombiner::OculusRiftCombiner(const OculusRiftDevice &d): + device(d), + left_mesh((GL::VERTEX2, GL::TEXCOORD2,0, GL::TEXCOORD2,1, GL::TEXCOORD2,2)), + right_mesh((GL::VERTEX2, GL::TEXCOORD2,0, GL::TEXCOORD2,1, GL::TEXCOORD2,2)), + shprog(vs_source, fs_source) { - chromatic[0] = c0; - chromatic[1] = c1; + width_div = 2; - update_parameters(); -} + const OculusRiftDevice::Private &dev_priv = device.get_private(); + ovrHmd hmd = dev_priv.ovr_hmd; -void OculusRiftCombiner::set_blue_aberration(float c2, float c3) -{ - chromatic[2] = c2; - chromatic[3] = c3; + 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(vertical)*2.0f; - update_parameters(); -} + float inner = max(left_fov.RightTan, right_fov.LeftTan); + float outer = max(left_fov.LeftTan, right_fov.RightTan); + frustum_skew = (inner-outer)*2/(inner+outer); -void OculusRiftCombiner::set_fill_factor(float f) -{ - fill_factor = f; - update_parameters(); -} + 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; -void OculusRiftCombiner::update_parameters() -{ - left_shdata.uniform4("distortion", distortion); - left_shdata.uniform4("chromatic", chromatic); - right_shdata.uniform4("distortion", distortion); - right_shdata.uniform4("chromatic", chromatic); - - // Set lens center positions, in output texture coordinates - left_shdata.uniform("lens_center", 1.0f-lens_separation, 0.5); - right_shdata.uniform("lens_center", lens_separation, 0.5); - - /* Compute distance between eye and lens centers, in sampling texture - coordinates. */ - float eye_offset = distort((eye_separation-lens_separation)*2); - left_shdata.uniform("eye_center", -eye_offset, 0.0f); - right_shdata.uniform("eye_center", eye_offset, 0.0f); - - /* Determine the necessary scaling factor to avoid quality degradation in - the center of the screen. */ - float horiz_oversize = distort((fill_factor-lens_separation)*2)/((fill_factor-lens_separation)*2)-eye_offset; - float vert_oversize = distort(1.25f*fill_factor)/(1.25f*fill_factor); - oversize = min(horiz_oversize, vert_oversize); - - left_shdata.uniform("scale", 2.0f, 2.5f, oversize); - right_shdata.uniform("scale", 2.0f, 2.5f, oversize); - - fov = Geometry::atan(oversize*0.625f/view_distance/2)*2.0f; - frustum_skew = lens_separation*2-1; -} + create_distortion_mesh(left_mesh, hmd, ovrEye_Left, left_fov); + create_distortion_mesh(right_mesh, hmd, ovrEye_Right, right_fov); -float OculusRiftCombiner::distort(float r) const -{ - float r_sq = r*r; - return r*(distortion[0]+(distortion[1]+(distortion[2]+distortion[3]*r_sq)*r_sq)*r_sq); -} + ovrSizei tex_size = ovrHmd_GetFovTextureSize(hmd, ovrEye_Left, left_fov, 1.0); + oversize = max(tex_size.w*2.0f/hmd->Resolution.w, tex_size.h*1.0f/hmd->Resolution.h); -float OculusRiftCombiner::undistort(float r) const -{ - float x = r; - while(1) - { - float y = distort(x); - if(abs(r-y)<1e-5) - return x; + shdata.uniform("texture", 0); - float x_sq = x*x; - float d = distortion[0]+(3*distortion[1]+(5*distortion[2]+7*distortion[3]*x_sq)*x_sq)*x_sq; - x -= (y-r)/d; - } } void OculusRiftCombiner::render(const GL::Texture2D &left, const GL::Texture2D &right) const { GL::Bind bind_shprog(shprog); + shdata.apply(); GL::Bind bind_tex(left); - left_shdata.apply(); - mesh.draw(); + left_mesh.draw(); right.bind(); - right_shdata.apply(); - mesh.draw(); + right_mesh.draw(); } } // namespace VR diff --git a/source/oculusriftcombiner.h b/source/oculusriftcombiner.h index afb5573..435ccb3 100644 --- a/source/oculusriftcombiner.h +++ b/source/oculusriftcombiner.h @@ -9,6 +9,8 @@ namespace Msp { namespace VR { +class OculusRiftDevice; + /** Presents a stereo view in a way suitable for an Oculus Rift HMD. All distances are specified in multiples of the screen width. @@ -16,34 +18,15 @@ are specified in multiples of the screen width. class OculusRiftCombiner: public StereoCombiner { private: - GL::Mesh mesh; + const OculusRiftDevice &device; + GL::Mesh left_mesh; + GL::Mesh right_mesh; GL::Program shprog; - GL::ProgramData left_shdata; - GL::ProgramData right_shdata; - float view_distance; - float lens_separation; - float eye_separation; - float distortion[4]; - float chromatic[4]; - float fill_factor; + GL::ProgramData shdata; public: - OculusRiftCombiner(); - - void set_view_distance(float); - void set_lens_separation(float); - void set_eye_separation(float); - void set_distortion(float = 1.0f, float = 0.0f, float = 0.0f, float = 0.0f); - void set_red_aberration(float = 1.0f, float = 0.0f); - void set_blue_aberration(float = 1.0f, float = 0.0f); - void set_fill_factor(float); -private: - void update_parameters(); + OculusRiftCombiner(const OculusRiftDevice &); - float distort(float) const; - float undistort(float) const; - -public: virtual void render(const GL::Texture2D &, const GL::Texture2D &) const; }; diff --git a/source/oculusriftdevice.cpp b/source/oculusriftdevice.cpp index 5f752df..9857f78 100644 --- a/source/oculusriftdevice.cpp +++ b/source/oculusriftdevice.cpp @@ -6,13 +6,16 @@ using namespace std; namespace Msp { namespace VR { +unsigned OculusRiftDevice::n_instances = 0; + OculusRiftDevice::OculusRiftDevice(): priv(new Private) { - static OVR::System system(OVR::Log::ConfigureDefaultLog(OVR::LogMask_Debug)); + if(!n_instances) + ovr_Initialize(); + ++n_instances; - priv->ovr_manager = OVR::DeviceManager::Create(); - priv->ovr_hmd = priv->ovr_manager->EnumerateDevices().CreateDevice(); + priv->ovr_hmd = ovrHmd_Create(0); if(!priv->ovr_hmd) { delete priv; @@ -22,7 +25,12 @@ OculusRiftDevice::OculusRiftDevice(): OculusRiftDevice::~OculusRiftDevice() { + ovrHmd_Destroy(priv->ovr_hmd); delete priv; + + --n_instances; + if(!n_instances) + ovr_Shutdown(); } OculusRiftCamera *OculusRiftDevice::create_camera(const GL::Camera &bc) const @@ -32,19 +40,7 @@ OculusRiftCamera *OculusRiftDevice::create_camera(const GL::Camera &bc) const OculusRiftCombiner *OculusRiftDevice::create_combiner() const { - OculusRiftCombiner *combiner = new OculusRiftCombiner; - - OVR::HMDInfo info; - if(priv->ovr_hmd->GetDeviceInfo(&info)) - { - combiner->set_view_distance(info.EyeToScreenDistance/info.HScreenSize); - combiner->set_lens_separation(info.LensSeparationDistance/info.HScreenSize); - combiner->set_distortion(info.DistortionK[0], info.DistortionK[1], info.DistortionK[2], info.DistortionK[3]); - combiner->set_red_aberration(info.ChromaAbCorrection[0], info.ChromaAbCorrection[1]); - combiner->set_blue_aberration(info.ChromaAbCorrection[2], info.ChromaAbCorrection[3]); - } - - return combiner; + return new OculusRiftCombiner(*this); } } // namespace VR diff --git a/source/oculusriftdevice.h b/source/oculusriftdevice.h index 9d9e2ec..41b721e 100644 --- a/source/oculusriftdevice.h +++ b/source/oculusriftdevice.h @@ -16,6 +16,8 @@ public: private: Private *priv; + static unsigned n_instances; + public: OculusRiftDevice(); virtual ~OculusRiftDevice(); diff --git a/source/oculusriftdevice_private.h b/source/oculusriftdevice_private.h index c2033ee..2b9c695 100644 --- a/source/oculusriftdevice_private.h +++ b/source/oculusriftdevice_private.h @@ -9,8 +9,7 @@ namespace VR { struct OculusRiftDevice::Private { - OVR::Ptr ovr_manager; - OVR::Ptr ovr_hmd; + ovrHmd ovr_hmd; }; } // namespace VR -- 2.45.2