xrt: Replace mesh generator with xdev->compute_distortion()

Each HMD driver now has to implement compute_distortion() which will be called
by the compositor implementation to generate a mesh (usually).

u_distortion_mesh contains implementations for the defaults (panotools, OpenHMD, vive).

Also adds compute_distortion function for Vive distortion

There are differences between OpenHMD and Panotools values, main differences for now:
* psvr has 5 pano coefficients, ohmd has 3
* psvr uses viewport size and lens center in pixels for distortion calculation, ohmd in meter
* psvr uses different distortion scaling than ohmd
This commit is contained in:
Christoph Haag 2020-08-12 20:32:07 +02:00 committed by Jakob Bornecrantz
parent 2aaa3acfdf
commit fb71c71a8c
15 changed files with 410 additions and 294 deletions

View file

@ -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
}

View file

@ -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);
}

View file

@ -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
}

View file

@ -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

View file

@ -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:

View file

@ -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;

View file

@ -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 |

View file

@ -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.

View file

@ -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.
*

View file

@ -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;
}

View file

@ -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

View file

@ -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;

View file

@ -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);

View file

@ -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.
*

View file

@ -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.
*/