diff --git a/src/xrt/auxiliary/math/m_vec2.h b/src/xrt/auxiliary/math/m_vec2.h index dfbc64cf5..213489205 100644 --- a/src/xrt/auxiliary/math/m_vec2.h +++ b/src/xrt/auxiliary/math/m_vec2.h @@ -81,6 +81,12 @@ m_vec2_len(struct xrt_vec2 l) return sqrtf(m_vec2_len_sqrd(l)); } +static inline float +m_vec2_dot(struct xrt_vec2 l, struct xrt_vec2 r) +{ + return l.x * r.x + l.y * r.y; +} + #ifdef __cplusplus } diff --git a/src/xrt/auxiliary/util/u_distortion_mesh.c b/src/xrt/auxiliary/util/u_distortion_mesh.c index aebed7a15..c7eddc350 100644 --- a/src/xrt/auxiliary/util/u_distortion_mesh.c +++ b/src/xrt/auxiliary/util/u_distortion_mesh.c @@ -22,17 +22,11 @@ DEBUG_GET_ONCE_NUM_OPTION(mesh_size, "XRT_MESH_SIZE", 64) -/* - * - * Func running helpers. - * - */ - -typedef void (*func_cb)(struct u_uv_generator *gen, - int view, - float x, - float y, - struct u_uv_triplet *result); +typedef bool (*func_calc)(struct xrt_device *xdev, + int view, + float u, + float v, + struct xrt_vec2_triplet *result); static int index_for(int row, int col, int stride, int offset) @@ -41,17 +35,16 @@ index_for(int row, int col, int stride, int offset) } void -run_func(struct u_uv_generator *gen, +run_func(struct xrt_device *xdev, + func_calc calc, int num_views, struct xrt_hmd_parts *target, size_t num) { - assert(gen != NULL); + assert(calc != NULL); assert(num_views == 2); assert(num_views <= 2); - func_cb func = gen->calc; - size_t offset_vertices[2] = {0}; size_t offset_indices[2] = {0}; @@ -63,7 +56,8 @@ run_func(struct u_uv_generator *gen, size_t num_vertices_per_view = vert_rows * vert_cols; size_t num_vertices = num_vertices_per_view * num_views; - size_t stride_in_floats = 8; + size_t num_uv_channels = 3; + size_t stride_in_floats = 2 + num_uv_channels * 2; size_t num_floats = num_vertices * stride_in_floats; float *verts = U_TYPED_ARRAY_CALLOC(float, num_floats); @@ -84,8 +78,14 @@ run_func(struct u_uv_generator *gen, // Make the position in the range of [-1, 1] verts[i + 0] = u * 2.0 - 1.0; verts[i + 1] = v * 2.0 - 1.0; - func(gen, view, u, v, - (struct u_uv_triplet *)&verts[i + 2]); + + if (!calc(xdev, view, u, v, + (struct xrt_vec2_triplet + *)&verts[i + 2])) { + // bail on error, without updating + // distortion.preferred + return; + } i += stride_in_floats; } @@ -125,7 +125,7 @@ run_func(struct u_uv_generator *gen, target->distortion.mesh.vertices = verts; target->distortion.mesh.stride = stride_in_floats * sizeof(float); target->distortion.mesh.num_vertices = num_vertices; - target->distortion.mesh.num_uv_channels = 3; + target->distortion.mesh.num_uv_channels = num_uv_channels; target->distortion.mesh.indices = indices; target->distortion.mesh.num_indices[0] = num_indices_per_view; target->distortion.mesh.num_indices[1] = num_indices_per_view; @@ -134,22 +134,58 @@ run_func(struct u_uv_generator *gen, target->distortion.mesh.total_num_indices = num_indices; } -void -u_distortion_mesh_from_gen(struct u_uv_generator *gen, - int num_views, - struct xrt_hmd_parts *target) +bool +u_compute_distortion_vive(float aspect_x_over_y, + float grow_for_undistort, + float undistort_r2_cutoff, + float center[2], + float coefficients[3][3], + float u, + float v, + struct xrt_vec2_triplet *result) { - size_t num = debug_get_num_option_mesh_size(); - run_func(gen, num_views, target, num); + struct xrt_vec2 factor = {0.5 / (1.0 + grow_for_undistort), + aspect_x_over_y * 0.5 / + (1.0 + grow_for_undistort)}; + + struct xrt_vec2 texCoord = {2.0 * u - 1.0, 2.0 * v - 1.0}; + + texCoord.y /= aspect_x_over_y; + texCoord.x -= center[0]; + texCoord.y -= center[1]; + + float r2 = m_vec2_dot(texCoord, texCoord); + + + struct xrt_vec3 d_inv = { + (r2 * coefficients[2][0] + coefficients[1][0]) * r2 + + coefficients[0][0] * r2 + 1.0, + (r2 * coefficients[2][1] + coefficients[1][1]) * r2 + + coefficients[0][1] * r2 + 1.0, + (r2 * coefficients[2][2] + coefficients[1][2]) * r2 + + coefficients[0][2] * r2 + 1.0}; + + struct xrt_vec3 d = {1.0 / d_inv.x, 1.0 / d_inv.y, 1.0 / d_inv.z}; + + struct xrt_vec2 offset = {0.5, 0.5}; + + struct xrt_vec2 tc_r = { + offset.x + (texCoord.x * d.x + center[0]) * factor.x, + offset.y + (texCoord.y * d.x + center[1]) * factor.y}; + + struct xrt_vec2 tc_g = { + offset.x + (texCoord.x * d.y + center[0]) * factor.x, + offset.y + (texCoord.y * d.y + center[1]) * factor.y}; + struct xrt_vec2 tc_b = { + offset.x + (texCoord.x * d.z + center[0]) * factor.x, + offset.y + (texCoord.y * d.z + center[1]) * factor.y}; + + result->r = tc_r; + result->g = tc_g; + result->b = tc_b; + return true; } - -/* - * - * Panotools. - * - */ - #define mul m_vec2_mul #define mul_scalar m_vec2_mul_scalar #define add m_vec2_add @@ -158,25 +194,13 @@ u_distortion_mesh_from_gen(struct u_uv_generator *gen, #define div_scalar m_vec2_div_scalar #define len m_vec2_len -/*! - * @implements u_uv_generator - */ -struct panotools_state +bool +u_compute_distortion_panotools(struct u_panotools_values *values, + float u, + float v, + struct xrt_vec2_triplet *result) { - struct u_uv_generator base; - - const struct u_panotools_values *vals[2]; -}; - -static void -panotools_calc(struct u_uv_generator *generator, - int view, - float u, - float v, - struct u_uv_triplet *result) -{ - struct panotools_state *state = (struct panotools_state *)generator; - const struct u_panotools_values val = *state->vals[view]; + const struct u_panotools_values val = *values; struct xrt_vec2 r = {u, v}; r = mul(r, val.viewport_size); @@ -208,61 +232,11 @@ panotools_calc(struct u_uv_generator *generator, result->r = r_uv; result->g = g_uv; result->b = b_uv; + return true; } -static void -panotools_destroy(struct u_uv_generator *generator) -{ - free(generator); -} - -static void -panotools_fill_in(const struct u_panotools_values *left, - const struct u_panotools_values *right, - struct panotools_state *state) -{ - state->base.calc = panotools_calc; - state->base.destroy = panotools_destroy; - state->vals[0] = left; - state->vals[1] = right; -} - -void -u_distortion_mesh_from_panotools(const struct u_panotools_values *left, - const struct u_panotools_values *right, - struct xrt_hmd_parts *target) -{ - struct panotools_state state; - panotools_fill_in(left, right, &state); - - size_t num = debug_get_num_option_mesh_size(); - run_func(&state.base, 2, target, num); -} - -void -u_distortion_mesh_generator_from_panotools( - const struct u_panotools_values *left, - const struct u_panotools_values *right, - struct u_uv_generator **out_gen) -{ - struct panotools_state *state = U_TYPED_CALLOC(struct panotools_state); - panotools_fill_in(left, right, state); - *out_gen = &state->base; -} - - -/* - * - * No distortion. - * - */ - -static void -no_distortion_calc(struct u_uv_generator *generator, - int view, - float u, - float v, - struct u_uv_triplet *result) +bool +u_compute_distortion_none(float u, float v, struct xrt_vec2_triplet *result) { result->r.x = u; result->r.y = v; @@ -270,13 +244,27 @@ no_distortion_calc(struct u_uv_generator *generator, result->g.y = v; result->b.x = u; result->b.y = v; + return true; +} + +static bool +compute_distortion_none(struct xrt_device *xdev, + int view, + float u, + float v, + struct xrt_vec2_triplet *result) +{ + return u_compute_distortion_none(u, v, result); } void -u_distortion_mesh_none(struct xrt_hmd_parts *target) +u_compute_distortion_mesh(struct xrt_device *xdev) { - struct u_uv_generator gen; - gen.calc = no_distortion_calc; - - run_func(&gen, 2, target, 8); + struct xrt_hmd_parts *target = xdev->hmd; + func_calc calc = xdev->compute_distortion; + if (calc == NULL) { + calc = compute_distortion_none; + } + size_t num = debug_get_num_option_mesh_size(); + run_func(xdev, calc, 2, target, num); } diff --git a/src/xrt/auxiliary/util/u_distortion_mesh.h b/src/xrt/auxiliary/util/u_distortion_mesh.h index b91a1b623..e3a3481af 100644 --- a/src/xrt/auxiliary/util/u_distortion_mesh.h +++ b/src/xrt/auxiliary/util/u_distortion_mesh.h @@ -16,6 +16,21 @@ extern "C" { #endif +/*! + * Distortion correction implementation for the Vive, Vive Pro, Valve Index + * distortion values found in the HMD configuration. + * + * @ingroup aux_util + */ +bool +u_compute_distortion_vive(float aspect_x_over_y, + float grow_for_undistort, + float undistort_r2_cutoff, + float center[2], + float coefficients[3][3], + float u, + float v, + struct xrt_vec2_triplet *result); /*! * Values to create a distortion mesh from panotools values. @@ -37,80 +52,33 @@ struct u_panotools_values }; /*! - * Three UV pairs, one for each color channel in the source image. + * Distortion correction implementation for Panotools distortion values. * * @ingroup aux_util */ -struct u_uv_triplet -{ - struct xrt_vec2 r, g, b; -}; +bool +u_compute_distortion_panotools(struct u_panotools_values *values, + float u, + float v, + struct xrt_vec2_triplet *result); /*! - * @interface u_uv_generator - * - * Generator interface for building meshes, can be implemented by drivers for - * special meshes. + * Identity distortion correction sets all result coordinates to u,v. * * @ingroup aux_util */ -struct u_uv_generator -{ - void (*calc)(struct u_uv_generator *, - int view, - float u, - float v, - struct u_uv_triplet *result); - - void (*destroy)(struct u_uv_generator *); -}; +bool +u_compute_distortion_none(float u, float v, struct xrt_vec2_triplet *result); /*! - * Given a @ref u_uv_generator generates num_views meshes, populates target. + * Given a @ref xrt_device generates meshes by calling + * xdev->compute_distortion(), populates xdev->hmd_parts.distortion.mesh * * @ingroup aux_util - * @public @memberof u_uv_generator - * @relatesalso xrt_hmd_parts + * @relatesalso xrt_device */ void -u_distortion_mesh_from_gen(struct u_uv_generator *, - int num_views, - struct xrt_hmd_parts *target); - -/*! - * Given two sets of panotools values creates a mesh generator, copies the - * values into it. This probably isn't the function you want. - * - * @ingroup aux_util - * @see u_distortion_mesh_from_panotools - */ -void -u_distortion_mesh_generator_from_panotools( - const struct u_panotools_values *left, - const struct u_panotools_values *right, - struct u_uv_generator **out_gen); - -/*! - * Given two sets of panotools values creates the left and th right uv meshes. - * This is probably the function you want. - * - * @ingroup aux_util - * @relates xrt_hmd_parts - */ -void -u_distortion_mesh_from_panotools(const struct u_panotools_values *left, - const struct u_panotools_values *right, - struct xrt_hmd_parts *target); - -/*! - * Create two distortion meshes with no distortion. - * - * @ingroup aux_util - * @relates xrt_hmd_parts - */ -void -u_distortion_mesh_none(struct xrt_hmd_parts *target); - +u_compute_distortion_mesh(struct xrt_device *xdev); #ifdef __cplusplus } diff --git a/src/xrt/compositor/main/comp_compositor.c b/src/xrt/compositor/main/comp_compositor.c index 2088cc673..3bff1418d 100644 --- a/src/xrt/compositor/main/comp_compositor.c +++ b/src/xrt/compositor/main/comp_compositor.c @@ -49,6 +49,7 @@ #include "util/u_misc.h" #include "util/u_time.h" #include "util/u_debug.h" +#include "util/u_distortion_mesh.h" #include "main/comp_compositor.h" @@ -1160,6 +1161,31 @@ xrt_gfx_provider_create_native(struct xrt_device *xdev) // Init the settings to default. comp_settings_init(&c->settings, xdev); + if (c->xdev->hmd->distortion.preferred == + XRT_DISTORTION_MODEL_COMPUTE || + c->xdev->hmd->distortion.preferred == XRT_DISTORTION_MODEL_NONE) { + COMP_DEBUG( + c, "Computing distortion mesh on compositor startup..."); + u_compute_distortion_mesh(c->xdev); + + if (c->xdev->hmd->distortion.preferred != + XRT_DISTORTION_MODEL_MESHUV) { + COMP_ERROR(c, "Failed to create mesh distortion for %s", + c->xdev->str); + + //! @todo Check if compositor supports current non-mesh + //! distortion model and bail if not. + // Monado will likely support only mesh in the future. + + // c->base.base.destroy(&c->base.base); + // return NULL; + } else { + COMP_DEBUG(c, "Distortion mesh computed!"); + c->settings.distortion_model = + XRT_DISTORTION_MODEL_MESHUV; + } + } + c->last_frame_time_ns = os_monotonic_get_ns(); c->frame_overhead_ns = 2000000; //! @todo set this to an estimate that's better than 6ms diff --git a/src/xrt/compositor/main/comp_distortion.c b/src/xrt/compositor/main/comp_distortion.c index 9d35e09f8..fd6db1ae3 100644 --- a/src/xrt/compositor/main/comp_distortion.c +++ b/src/xrt/compositor/main/comp_distortion.c @@ -353,7 +353,7 @@ comp_distortion_init_pipeline(struct comp_distortion *d, fragment_shader_code = shaders_none_frag; fragment_shader_size = sizeof(shaders_none_frag); break; - case XRT_DISTORTION_MODEL_PANOTOOLS: + case XRT_DISTORTION_MODEL_OPENHMD: fragment_shader_code = shaders_panotools_frag; fragment_shader_size = sizeof(shaders_panotools_frag); break; @@ -702,26 +702,30 @@ comp_distortion_update_uniform_buffer_warp(struct comp_distortion *d, break; case XRT_DISTORTION_MODEL_MESHUV: break; + case XRT_DISTORTION_MODEL_NONE: + break; case XRT_DISTORTION_MODEL_PANOTOOLS: + break; + case XRT_DISTORTION_MODEL_OPENHMD: default: /* * Pano vision fragment shader */ - d->ubo_pano.hmd_warp_param[0] = c->xdev->hmd->distortion.pano.distortion_k[0]; - d->ubo_pano.hmd_warp_param[1] = c->xdev->hmd->distortion.pano.distortion_k[1]; - d->ubo_pano.hmd_warp_param[2] = c->xdev->hmd->distortion.pano.distortion_k[2]; - d->ubo_pano.hmd_warp_param[3] = c->xdev->hmd->distortion.pano.distortion_k[3]; - d->ubo_pano.aberr[0] = c->xdev->hmd->distortion.pano.aberration_k[0]; - d->ubo_pano.aberr[1] = c->xdev->hmd->distortion.pano.aberration_k[1]; - d->ubo_pano.aberr[2] = c->xdev->hmd->distortion.pano.aberration_k[2]; - d->ubo_pano.aberr[3] = c->xdev->hmd->distortion.pano.aberration_k[3]; + d->ubo_pano.hmd_warp_param[0] = c->xdev->hmd->distortion.openhmd.distortion_k[0]; + d->ubo_pano.hmd_warp_param[1] = c->xdev->hmd->distortion.openhmd.distortion_k[1]; + d->ubo_pano.hmd_warp_param[2] = c->xdev->hmd->distortion.openhmd.distortion_k[2]; + d->ubo_pano.hmd_warp_param[3] = c->xdev->hmd->distortion.openhmd.distortion_k[3]; + d->ubo_pano.aberr[0] = c->xdev->hmd->distortion.openhmd.aberration_k[0]; + d->ubo_pano.aberr[1] = c->xdev->hmd->distortion.openhmd.aberration_k[1]; + d->ubo_pano.aberr[2] = c->xdev->hmd->distortion.openhmd.aberration_k[2]; + d->ubo_pano.aberr[3] = c->xdev->hmd->distortion.openhmd.aberration_k[3]; d->ubo_pano.lens_center[0][0] = c->xdev->hmd->views[0].lens_center.x_meters; d->ubo_pano.lens_center[0][1] = c->xdev->hmd->views[0].lens_center.y_meters; d->ubo_pano.lens_center[1][0] = c->xdev->hmd->views[1].lens_center.x_meters; d->ubo_pano.lens_center[1][1] = c->xdev->hmd->views[1].lens_center.y_meters; d->ubo_pano.viewport_scale[0] = c->xdev->hmd->views[0].display.w_meters; d->ubo_pano.viewport_scale[1] = c->xdev->hmd->views[0].display.h_meters; - d->ubo_pano.warp_scale = c->xdev->hmd->distortion.pano.warp_scale; + d->ubo_pano.warp_scale = c->xdev->hmd->distortion.openhmd.warp_scale; memcpy(d->ubo_handle.mapped, &d->ubo_pano, sizeof(d->ubo_pano)); break; @@ -859,7 +863,7 @@ comp_distortion_init_buffers(struct comp_distortion *d, d->has_fragment_shader_ubo = true; switch (d->distortion_model) { - case XRT_DISTORTION_MODEL_PANOTOOLS: + case XRT_DISTORTION_MODEL_OPENHMD: ubo_size = sizeof(d->ubo_pano); break; case XRT_DISTORTION_MODEL_MESHUV: diff --git a/src/xrt/drivers/dummy/dummy_hmd.c b/src/xrt/drivers/dummy/dummy_hmd.c index 5bddf9d16..873ca133c 100644 --- a/src/xrt/drivers/dummy/dummy_hmd.c +++ b/src/xrt/drivers/dummy/dummy_hmd.c @@ -194,10 +194,10 @@ dummy_hmd_create(void) u_var_add_root(dh, "Dummy HMD", true); u_var_add_pose(dh, &dh->pose, "pose"); - if (dh->base.hmd->distortion.preferred == XRT_DISTORTION_MODEL_NONE) { - // Setup the distortion mesh. - u_distortion_mesh_none(dh->base.hmd); - } + dh->base.hmd->distortion.models = XRT_DISTORTION_MODEL_NONE; + dh->base.hmd->distortion.preferred = XRT_DISTORTION_MODEL_NONE; + dh->base.compute_distortion = NULL; + dh->base.device_type = XRT_DEVICE_TYPE_HMD; return &dh->base; diff --git a/src/xrt/drivers/hdk/hdk_device.cpp b/src/xrt/drivers/hdk/hdk_device.cpp index 89b5d1d81..8838a5822 100644 --- a/src/xrt/drivers/hdk/hdk_device.cpp +++ b/src/xrt/drivers/hdk/hdk_device.cpp @@ -34,6 +34,7 @@ #include "util/u_misc.h" #include "util/u_device.h" #include "util/u_time.h" +#include "util/u_distortion_mesh.h" #include "hdk_device.h" @@ -487,6 +488,7 @@ hdk_device_create(struct os_hid_device *dev, // We only have a mesh for 2, so use "none" there until it's supported. hd->base.hmd->distortion.models = XRT_DISTORTION_MODEL_NONE; hd->base.hmd->distortion.preferred = XRT_DISTORTION_MODEL_NONE; + hd->base.compute_distortion = NULL; // if (variant == HDK_VARIANT_1_3_1_4) { // hd->base.hmd->distortion.models = // xrt_distortion_model(hd->base.hmd->distortion.models | diff --git a/src/xrt/drivers/north_star/ns_hmd.c b/src/xrt/drivers/north_star/ns_hmd.c index 2700540eb..38b425434 100644 --- a/src/xrt/drivers/north_star/ns_hmd.c +++ b/src/xrt/drivers/north_star/ns_hmd.c @@ -112,19 +112,18 @@ ns_hmd_get_view_pose(struct xrt_device *xdev, * */ -static void -ns_mesh_calc(struct u_uv_generator *gen, +static bool +ns_mesh_calc(struct xrt_device *xdev, int view, float u, float v, - struct u_uv_triplet *result) + struct xrt_vec2_triplet *result) { - struct ns_mesh *mesh = ns_mesh(gen); + struct ns_hmd *ns = ns_hmd(xdev); struct ns_uv uv = {u, v}; struct ns_uv warped_uv = {0.0f, 0.0f}; - ns_display_uv_to_render_uv(uv, &warped_uv, - &mesh->ns->eye_configs_v1[view]); + ns_display_uv_to_render_uv(uv, &warped_uv, &ns->eye_configs_v1[view]); result->r.x = warped_uv.u; result->r.y = warped_uv.v; @@ -132,13 +131,7 @@ ns_mesh_calc(struct u_uv_generator *gen, result->g.y = warped_uv.v; result->b.x = warped_uv.u; result->b.y = warped_uv.v; -} - -static void -ns_mesh_destroy(struct u_uv_generator *gen) -{ - struct ns_mesh *mesh = (struct ns_mesh *)gen; - (void)mesh; // Noop + return true; } /* @@ -301,15 +294,14 @@ ns_v2_fov_calculate(struct ns_hmd *ns, int eye_index) -static void -ns_v2_mesh_calc(struct u_uv_generator *gen, +static bool +ns_v2_mesh_calc(struct xrt_device *xdev, int view, float u, float v, - struct u_uv_triplet *result) + struct xrt_vec2_triplet *result) { - - + struct ns_hmd *ns = ns_hmd(xdev); float x = 0.0f; float y = 0.0f; @@ -317,16 +309,15 @@ ns_v2_mesh_calc(struct u_uv_generator *gen, u = 1.0 - u; v = 1.0 - v; - struct ns_mesh *mesh = ns_mesh(gen); - float L = mesh->ns->eye_configs_v2[view].fov.angle_left; - float R = mesh->ns->eye_configs_v2[view].fov.angle_right; - float T = mesh->ns->eye_configs_v2[view].fov.angle_up; - float B = mesh->ns->eye_configs_v2[view].fov.angle_down; + float L = ns->eye_configs_v2[view].fov.angle_left; + float R = ns->eye_configs_v2[view].fov.angle_right; + float T = ns->eye_configs_v2[view].fov.angle_up; + float B = ns->eye_configs_v2[view].fov.angle_down; - float x_ray = ns_v2_polyval2d( - u, v, mesh->ns->eye_configs_v2[view].x_coefficients); - float y_ray = ns_v2_polyval2d( - u, v, mesh->ns->eye_configs_v2[view].y_coefficients); + float x_ray = + ns_v2_polyval2d(u, v, ns->eye_configs_v2[view].x_coefficients); + float y_ray = + ns_v2_polyval2d(u, v, ns->eye_configs_v2[view].y_coefficients); x = (x_ray + L) / (L - R); y = (y_ray + T) / (T - B); @@ -338,6 +329,7 @@ ns_v2_mesh_calc(struct u_uv_generator *gen, result->g.y = y; result->b.x = x; result->b.y = y; + return true; } @@ -551,20 +543,10 @@ ns_hmd_create(const char *config_path, bool print_spew, bool print_debug) ns_v2_fov_calculate(ns, 0); ns_v2_fov_calculate(ns, 1); - - - // Setup the distortion mesh. - struct ns_mesh mesh; - U_ZERO(&mesh); - mesh.ns = ns; - mesh.base.calc = ns_v2_mesh_calc; - mesh.base.destroy = ns_mesh_destroy; - - // Do the mesh generation. - u_distortion_mesh_from_gen(&mesh.base, 2, ns->base.hmd); - // u_distortion_mesh_none(ns->base.hmd); - - + ns->base.hmd->distortion.models = XRT_DISTORTION_MODEL_COMPUTE; + ns->base.hmd->distortion.preferred = + XRT_DISTORTION_MODEL_COMPUTE; + ns->base.compute_distortion = ns_v2_mesh_calc; } else { // V1 @@ -591,17 +573,10 @@ ns_hmd_create(const char *config_path, bool print_spew, bool print_debug) ns->tracker = rs_6dof_create(); #endif - - - // Setup the distortion mesh. - struct ns_mesh mesh; - U_ZERO(&mesh); - mesh.ns = ns; - mesh.base.calc = ns_mesh_calc; - mesh.base.destroy = ns_mesh_destroy; - - // Do the mesh generation. - u_distortion_mesh_from_gen(&mesh.base, 2, ns->base.hmd); + ns->base.hmd->distortion.models = XRT_DISTORTION_MODEL_COMPUTE; + ns->base.hmd->distortion.preferred = + XRT_DISTORTION_MODEL_COMPUTE; + ns->base.compute_distortion = ns_mesh_calc; } // If built, try to load the realsense tracker. diff --git a/src/xrt/drivers/north_star/ns_hmd.h b/src/xrt/drivers/north_star/ns_hmd.h index 213165a85..ec4f33019 100644 --- a/src/xrt/drivers/north_star/ns_hmd.h +++ b/src/xrt/drivers/north_star/ns_hmd.h @@ -10,7 +10,6 @@ #pragma once #include "math/m_api.h" -#include "util/u_distortion_mesh.h" #include "util/u_json.h" #include "util/u_misc.h" #include "xrt/xrt_defines.h" @@ -150,20 +149,6 @@ struct ns_hmd // be an enum or something }; - -/*! - * The mesh generator for the North Star distortion. - * - * @ingroup drv_ns - * @implements u_uv_generator - */ -struct ns_mesh -{ - struct u_uv_generator base; - struct ns_hmd *ns; -}; - - /* * * Functions @@ -181,17 +166,6 @@ ns_hmd(struct xrt_device *xdev) return (struct ns_hmd *)xdev; } -/*! - * Get the North Star mesh generator from a @ref u_uv_generator. - * - * @ingroup drv_ns - */ -static inline struct ns_mesh * -ns_mesh(struct u_uv_generator *gen) -{ - return (struct ns_mesh *)gen; -} - /*! * Convert the display UV to the render UV using the distortion mesh. * diff --git a/src/xrt/drivers/ohmd/oh_device.c b/src/xrt/drivers/ohmd/oh_device.c index ba8886cb1..93e395ac7 100644 --- a/src/xrt/drivers/ohmd/oh_device.c +++ b/src/xrt/drivers/ohmd/oh_device.c @@ -24,6 +24,7 @@ #include "openhmd.h" #include "math/m_api.h" +#include "math/m_vec2.h" #include "xrt/xrt_device.h" #include "util/u_var.h" #include "util/u_misc.h" @@ -372,6 +373,97 @@ get_info(struct oh_device *ohd, const char *prod) return info; } +#define mul m_vec2_mul +#define mul_scalar m_vec2_mul_scalar +#define add m_vec2_add +#define sub m_vec2_sub +#define div m_vec2_div +#define div_scalar m_vec2_div_scalar +#define len m_vec2_len + +// slightly different to u_compute_distortion_panotools in u_distortion_mesh +static bool +u_compute_distortion_openhmd(float distortion_k[5], + float aberration_k[3], + float scale, + struct xrt_vec2 lens_center, + struct xrt_vec2 viewport_size, + float u, + float v, + struct xrt_vec2_triplet *result) +{ + struct xrt_vec2 r = {u, v}; + r = mul(r, viewport_size); + r = sub(r, lens_center); + r = div_scalar(r, scale); + + float r_mag = len(r); + r_mag = distortion_k[0] + // r^1 + distortion_k[1] * r_mag + // r^2 + distortion_k[2] * r_mag * r_mag + // r^3 + distortion_k[3] * r_mag * r_mag * r_mag; // r^4 + + struct xrt_vec2 r_dist = mul_scalar(r, r_mag); + r_dist = mul_scalar(r_dist, scale); + + struct xrt_vec2 r_uv = mul_scalar(r_dist, aberration_k[0]); + r_uv = add(r_uv, lens_center); + r_uv = div(r_uv, viewport_size); + + struct xrt_vec2 g_uv = mul_scalar(r_dist, aberration_k[1]); + g_uv = add(g_uv, lens_center); + g_uv = div(g_uv, viewport_size); + + struct xrt_vec2 b_uv = mul_scalar(r_dist, aberration_k[2]); + b_uv = add(b_uv, lens_center); + b_uv = div(b_uv, viewport_size); + + result->r = r_uv; + result->g = g_uv; + result->b = b_uv; + return true; +} + +static bool +compute_distortion_openhmd(struct xrt_device *xdev, + int view, + float u, + float v, + struct xrt_vec2_triplet *result) +{ + struct xrt_hmd_parts *hmd = xdev->hmd; + struct xrt_vec2 lens_center = { + .x = hmd->views[view].lens_center.x_meters, + .y = hmd->views[view].lens_center.y_meters}; + + struct xrt_vec2 viewport_size = {.x = hmd->views[view].display.w_meters, + .y = + hmd->views[view].display.h_meters}; + + //! @todo: support distortion per view + return u_compute_distortion_openhmd( + hmd->distortion.openhmd.distortion_k, + hmd->distortion.openhmd.aberration_k, + hmd->distortion.openhmd.warp_scale, lens_center, viewport_size, u, + v, result); +} + +static bool +compute_distortion_vive(struct xrt_device *xdev, + int view, + float u, + float v, + struct xrt_vec2_triplet *result) +{ + struct xrt_hmd_parts *hmd = xdev->hmd; + return u_compute_distortion_vive( + hmd->distortion.vive.aspect_x_over_y, + hmd->distortion.vive.grow_for_undistort, + hmd->distortion.vive.undistort_r2_cutoff[view], + hmd->distortion.vive.center[view], + hmd->distortion.vive.coefficients[view], u, v, result); +} + struct oh_device * oh_device_create(ohmd_context *ctx, ohmd_device *dev, @@ -429,19 +521,17 @@ oh_device_create(ohmd_context *ctx, // clang-format off // Main display. - ohd->base.hmd->distortion.models = XRT_DISTORTION_MODEL_PANOTOOLS; - ohd->base.hmd->distortion.preferred = XRT_DISTORTION_MODEL_PANOTOOLS; ohd->base.hmd->screens[0].w_pixels = info.display.w_pixels; ohd->base.hmd->screens[0].h_pixels = info.display.h_pixels; ohd->base.hmd->screens[0].nominal_frame_interval_ns = info.display.nominal_frame_interval_ns; - ohd->base.hmd->distortion.pano.distortion_k[0] = info.pano_distortion_k[0]; - ohd->base.hmd->distortion.pano.distortion_k[1] = info.pano_distortion_k[1]; - ohd->base.hmd->distortion.pano.distortion_k[2] = info.pano_distortion_k[2]; - ohd->base.hmd->distortion.pano.distortion_k[3] = info.pano_distortion_k[3]; - ohd->base.hmd->distortion.pano.aberration_k[0] = info.pano_aberration_k[0]; - ohd->base.hmd->distortion.pano.aberration_k[1] = info.pano_aberration_k[1]; - ohd->base.hmd->distortion.pano.aberration_k[2] = info.pano_aberration_k[2]; - ohd->base.hmd->distortion.pano.warp_scale = info.pano_warp_scale; + ohd->base.hmd->distortion.openhmd.distortion_k[0] = info.pano_distortion_k[0]; + ohd->base.hmd->distortion.openhmd.distortion_k[1] = info.pano_distortion_k[1]; + ohd->base.hmd->distortion.openhmd.distortion_k[2] = info.pano_distortion_k[2]; + ohd->base.hmd->distortion.openhmd.distortion_k[3] = info.pano_distortion_k[3]; + ohd->base.hmd->distortion.openhmd.aberration_k[0] = info.pano_aberration_k[0]; + ohd->base.hmd->distortion.openhmd.aberration_k[1] = info.pano_aberration_k[1]; + ohd->base.hmd->distortion.openhmd.aberration_k[2] = info.pano_aberration_k[2]; + ohd->base.hmd->distortion.openhmd.warp_scale = info.pano_warp_scale; // Left ohd->base.hmd->views[0].display.w_meters = info.views[0].display.w_meters; @@ -470,6 +560,12 @@ oh_device_create(ohmd_context *ctx, ohd->base.hmd->views[1].rot = u_device_rotation_ident; // clang-format on + ohd->base.hmd->distortion.models |= + XRT_DISTORTION_MODEL_COMPUTE | XRT_DISTORTION_MODEL_OPENHMD; + ohd->base.hmd->distortion.preferred = XRT_DISTORTION_MODEL_COMPUTE; + ohd->base.compute_distortion = compute_distortion_openhmd; + ; + // Which blend modes does the device support. ohd->base.hmd->blend_mode = XRT_BLEND_MODE_OPAQUE; if (info.quirks.video_see_through) { @@ -478,11 +574,6 @@ oh_device_create(ohmd_context *ctx, } if (info.quirks.video_distortion_vive) { - ohd->base.hmd->distortion.models = (enum xrt_distortion_model)( - ohd->base.hmd->distortion.models | - XRT_DISTORTION_MODEL_VIVE); - ohd->base.hmd->distortion.preferred = XRT_DISTORTION_MODEL_VIVE; - // clang-format off // These need to be acquired from the vive config ohd->base.hmd->distortion.vive.aspect_x_over_y = 0.8999999761581421f; @@ -526,15 +617,21 @@ oh_device_create(ohmd_context *ctx, ohd->base.hmd->distortion.vive.coefficients[1][2][1] = -0.04517245633373419f; ohd->base.hmd->distortion.vive.coefficients[1][2][2] = -0.0928909347763f; // clang-format on + + ohd->base.hmd->distortion.models |= XRT_DISTORTION_MODEL_VIVE; + ohd->base.hmd->distortion.preferred = + XRT_DISTORTION_MODEL_COMPUTE; + ohd->base.compute_distortion = compute_distortion_vive; } if (info.quirks.video_distortion_none) { ohd->base.hmd->distortion.models = XRT_DISTORTION_MODEL_NONE; ohd->base.hmd->distortion.preferred = XRT_DISTORTION_MODEL_NONE; + ohd->base.compute_distortion = NULL; } if (info.quirks.left_center_pano_scale) { - ohd->base.hmd->distortion.pano.warp_scale = + ohd->base.hmd->distortion.openhmd.warp_scale = info.views[0].lens_center_x_meters; } @@ -600,10 +697,5 @@ oh_device_create(ohmd_context *ctx, u_var_add_root(ohd, "OpenHMD Wrapper", true); u_var_add_ro_text(ohd, ohd->base.str, "Card"); - if (ohd->base.hmd->distortion.preferred == XRT_DISTORTION_MODEL_NONE) { - // Setup the distortion mesh. - u_distortion_mesh_none(ohd->base.hmd); - } - return ohd; } diff --git a/src/xrt/drivers/psvr/psvr_device.c b/src/xrt/drivers/psvr/psvr_device.c index 3f6525e88..f7ce91c7c 100644 --- a/src/xrt/drivers/psvr/psvr_device.c +++ b/src/xrt/drivers/psvr/psvr_device.c @@ -123,6 +123,7 @@ struct psvr_device int last_packet; } calibration; + struct { bool last_frame; @@ -137,6 +138,9 @@ struct psvr_device struct xrt_quat rot; } fusion; #endif + + //! For compute_distortion + struct u_panotools_values vals; }; @@ -983,6 +987,18 @@ psvr_device_destroy(struct xrt_device *xdev) u_device_free(&psvr->base); } +static bool +psvr_compute_distortion(struct xrt_device *xdev, + int view, + float u, + float v, + struct xrt_vec2_triplet *result) +{ + struct psvr_device *psvr = psvr_device(xdev); + + return u_compute_distortion_panotools(&psvr->vals, u, v, result); +} + /* * @@ -1008,6 +1024,7 @@ psvr_device_create(struct hid_device_info *hmd_handle_info, psvr->base.update_inputs = psvr_device_update_inputs; psvr->base.get_tracked_pose = psvr_device_get_tracked_pose; psvr->base.get_view_pose = psvr_device_get_view_pose; + psvr->base.compute_distortion = psvr_compute_distortion; psvr->base.destroy = psvr_device_destroy; psvr->base.inputs[0].name = XRT_INPUT_GENERIC_HEAD_POSE; psvr->base.name = XRT_DEVICE_GENERIC_HMD; @@ -1029,7 +1046,11 @@ psvr_device_create(struct hid_device_info *hmd_handle_info, vals.lens_center.x = vals.viewport_size.x / 2.0; vals.lens_center.y = vals.viewport_size.y / 2.0; - u_distortion_mesh_from_panotools(&vals, &vals, psvr->base.hmd); + psvr->vals = vals; + + struct xrt_hmd_parts *hmd = psvr->base.hmd; + hmd->distortion.models = XRT_DISTORTION_MODEL_COMPUTE; + hmd->distortion.preferred = XRT_DISTORTION_MODEL_COMPUTE; } #if 1 diff --git a/src/xrt/drivers/survive/survive_driver.c b/src/xrt/drivers/survive/survive_driver.c index cd01e82ca..938652d87 100644 --- a/src/xrt/drivers/survive/survive_driver.c +++ b/src/xrt/drivers/survive/survive_driver.c @@ -22,6 +22,7 @@ #include "util/u_misc.h" #include "util/u_time.h" #include "util/u_device.h" +#include "util/u_distortion_mesh.h" #include "../auxiliary/os/os_time.h" @@ -903,6 +904,22 @@ get_distortion_properties(struct survive_device *d, _get_color_coeffs_lookup(hmd, eye_json, "distortion_blue", eye, 2); } +static bool +compute_distortion(struct xrt_device *xdev, + int view, + float u, + float v, + struct xrt_vec2_triplet *result) +{ + struct xrt_hmd_parts *hmd = xdev->hmd; + return u_compute_distortion_vive( + hmd->distortion.vive.aspect_x_over_y, + hmd->distortion.vive.grow_for_undistort, + hmd->distortion.vive.undistort_r2_cutoff[view], + hmd->distortion.vive.center[view], + hmd->distortion.vive.coefficients[view], u, v, result); +} + static bool _create_hmd_device(struct survive_system *sys, enum VIVE_VARIANT variant) { @@ -1076,8 +1093,10 @@ _create_hmd_device(struct survive_system *sys, enum VIVE_VARIANT variant) } } - survive->base.hmd->distortion.models = XRT_DISTORTION_MODEL_VIVE; - survive->base.hmd->distortion.preferred = XRT_DISTORTION_MODEL_VIVE; + survive->base.hmd->distortion.models = + XRT_DISTORTION_MODEL_VIVE | XRT_DISTORTION_MODEL_COMPUTE; + survive->base.hmd->distortion.preferred = XRT_DISTORTION_MODEL_COMPUTE; + survive->base.compute_distortion = compute_distortion; survive->base.orientation_tracking_supported = true; survive->base.position_tracking_supported = true; diff --git a/src/xrt/drivers/vive/vive_device.c b/src/xrt/drivers/vive/vive_device.c index c1e4c9e6d..7b6e5741e 100644 --- a/src/xrt/drivers/vive/vive_device.c +++ b/src/xrt/drivers/vive/vive_device.c @@ -17,6 +17,7 @@ #include "util/u_debug.h" #include "util/u_var.h" #include "util/u_time.h" +#include "util/u_distortion_mesh.h" #include "math/m_api.h" @@ -794,6 +795,23 @@ vive_init_defaults(struct vive_device *d) hmd->distortion.vive.undistort_r2_cutoff[1] = 1.0f; } + +static bool +compute_distortion(struct xrt_device *xdev, + int view, + float u, + float v, + struct xrt_vec2_triplet *result) +{ + struct xrt_hmd_parts *hmd = xdev->hmd; + return u_compute_distortion_vive( + hmd->distortion.vive.aspect_x_over_y, + hmd->distortion.vive.grow_for_undistort, + hmd->distortion.vive.undistort_r2_cutoff[view], + hmd->distortion.vive.center[view], + hmd->distortion.vive.coefficients[view], u, v, result); +} + struct vive_device * vive_device_create(struct os_hid_device *mainboard_dev, struct os_hid_device *sensors_dev, @@ -818,6 +836,11 @@ vive_device_create(struct os_hid_device *mainboard_dev, d->watchman_dev = watchman_dev; d->variant = variant; + d->base.hmd->distortion.models = + XRT_DISTORTION_MODEL_VIVE | XRT_DISTORTION_MODEL_COMPUTE; + d->base.hmd->distortion.preferred = XRT_DISTORTION_MODEL_COMPUTE; + d->base.compute_distortion = compute_distortion; + vive_init_defaults(d); switch (variant) { @@ -935,9 +958,6 @@ vive_device_create(struct os_hid_device *mainboard_dev, } } - d->base.hmd->distortion.models = XRT_DISTORTION_MODEL_VIVE; - d->base.hmd->distortion.preferred = XRT_DISTORTION_MODEL_VIVE; - // Init here. m_imu_3dof_init(&d->fusion, M_IMU_3DOF_USE_GRAVITY_DUR_20MS); diff --git a/src/xrt/include/xrt/xrt_defines.h b/src/xrt/include/xrt/xrt_defines.h index 24c29185f..21380f1c2 100644 --- a/src/xrt/include/xrt/xrt_defines.h +++ b/src/xrt/include/xrt/xrt_defines.h @@ -53,9 +53,11 @@ enum xrt_distortion_model { // clang-format off XRT_DISTORTION_MODEL_NONE = 1 << 0, - XRT_DISTORTION_MODEL_PANOTOOLS = 1 << 1, - XRT_DISTORTION_MODEL_VIVE = 1 << 2, - XRT_DISTORTION_MODEL_MESHUV = 1 << 3, + XRT_DISTORTION_MODEL_COMPUTE = 1 << 1, + XRT_DISTORTION_MODEL_PANOTOOLS = 1 << 2, + XRT_DISTORTION_MODEL_VIVE = 1 << 3, + XRT_DISTORTION_MODEL_MESHUV = 1 << 4, + XRT_DISTORTION_MODEL_OPENHMD = 1 << 5, // clang-format on }; @@ -129,6 +131,16 @@ struct xrt_vec2 float y; }; +/*! + * Three xrt_vec2 + * + * @ingroup xrt_iface_math + */ +struct xrt_vec2_triplet +{ + struct xrt_vec2 r, g, b; +}; + /*! * A 3 element vector with single floats. * diff --git a/src/xrt/include/xrt/xrt_device.h b/src/xrt/include/xrt/xrt_device.h index a2b4db635..7ad86128f 100644 --- a/src/xrt/include/xrt/xrt_device.h +++ b/src/xrt/include/xrt/xrt_device.h @@ -60,13 +60,16 @@ struct xrt_view } display; /*! - * Position in meters relative to display origin, before any rotation - * is applied by xrt_view::rot. + * Position relative to display origin, before any rotation is applied + * by xrt_view::rot. note: not set by most drivers, used only for + * panotools/ohmd distortion */ struct { float x_meters; float y_meters; + int x_pixels; + int y_pixels; } lens_center; /*! @@ -132,7 +135,7 @@ struct xrt_hmd_parts float aberration_k[4]; //! Panotools warp scale. float warp_scale; - } pano; + } openhmd; struct { @@ -296,6 +299,12 @@ struct xrt_device uint32_t view_index, struct xrt_pose *out_pose); + bool (*compute_distortion)(struct xrt_device *xdev, + int view, + float u, + float v, + struct xrt_vec2_triplet *result); + /*! * Destroy device. */