d/wmr: Add render distortion configuration

Take the parameters from the headset configuration and the existing
render FoV, and use them to instantiate a distortion mesh.

TODO: Reverse the distortion in order to calculate good FoV range
that covers the full view for each headset.
This commit is contained in:
Jan Schmidt 2021-04-18 01:10:11 +10:00
parent f663727b07
commit 0cf7b4a9b3
2 changed files with 81 additions and 1 deletions

View file

@ -447,12 +447,64 @@ wmr_hmd_destroy(struct xrt_device *xdev)
free(wh);
}
static bool
compute_distortion_wmr(struct xrt_device *xdev, int view, float u, float v, struct xrt_uv_triplet *result)
{
struct wmr_hmd *wh = wmr_hmd(xdev);
assert(view == 0 || view == 1);
const struct wmr_distortion_eye_config *ec = wh->config.eye_params + view;
struct wmr_hmd_distortion_params *distortion_params = wh->distortion_params + view;
// Results r/g/b.
struct xrt_vec2 tc[3];
// Dear compiler, please vectorize.
for (int i = 0; i < 3; i++) {
const struct wmr_distortion_3K *distortion3K = ec->distortion3K + i;
/* Scale the 0..1 input UV back to pixels relative to the distortion center,
* accounting for the right eye starting at X = panel_width / 2.0 */
struct xrt_vec2 pix_coord = {(u + 1.0 * view) * (ec->display_size.x / 2.0) - distortion3K->eye_center.x,
v * ec->display_size.y - distortion3K->eye_center.y};
float r2 = m_vec2_dot(pix_coord, pix_coord);
float k1 = distortion3K->k[0];
float k2 = distortion3K->k[1];
float k3 = distortion3K->k[2];
float d = 1.0 + r2 * (k1 + r2 * (k2 + r2 * k3));
/* Map the distorted pixel coordinate back to normalised view plane coords using the inverse affine
* xform */
struct xrt_vec3 p = {(pix_coord.x * d + distortion3K->eye_center.x),
(pix_coord.y * d + distortion3K->eye_center.y), 1.0};
struct xrt_vec3 vp;
math_matrix_3x3_transform_vec3(&distortion_params->inv_affine_xform, &p, &vp);
/* Finally map back to the input texture 0..1 range based on the render FoV (from tex_N_range.x ..
* tex_N_range.y) */
tc[i].x = ((vp.x / vp.z) - distortion_params->tex_x_range.x) /
(distortion_params->tex_x_range.y - distortion_params->tex_x_range.x);
tc[i].y = ((vp.y / vp.z) - distortion_params->tex_y_range.x) /
(distortion_params->tex_y_range.y - distortion_params->tex_y_range.x);
}
result->r = tc[0];
result->g = tc[1];
result->b = tc[2];
return true;
}
struct xrt_device *
wmr_hmd_create(struct os_hid_device *hid_holo, struct os_hid_device *hid_ctrl, enum u_logging_level ll)
{
enum u_device_alloc_flags flags =
(enum u_device_alloc_flags)(U_DEVICE_ALLOC_HMD | U_DEVICE_ALLOC_TRACKING_NONE);
int ret = 0;
int eye;
struct wmr_hmd *wh = U_DEVICE_ALLOCATE(struct wmr_hmd, flags, 1, 0);
if (!wh) {
@ -542,7 +594,19 @@ wmr_hmd_create(struct os_hid_device *hid_holo, struct os_hid_device *hid_ctrl, e
u_var_add_log_level(wh, &wh->log_level, "log_level");
// Distortion information, fills in xdev->compute_distortion().
u_distortion_mesh_set_none(&wh->base);
for (eye = 0; eye < 2; eye++) {
math_matrix_3x3_inverse(&wh->config.eye_params[eye].affine_xform,
&wh->distortion_params[eye].inv_affine_xform);
wh->distortion_params[eye].tex_x_range.x = tan(wh->base.hmd->views[eye].fov.angle_left);
wh->distortion_params[eye].tex_x_range.y = tan(wh->base.hmd->views[eye].fov.angle_right);
wh->distortion_params[eye].tex_y_range.x = tan(wh->base.hmd->views[eye].fov.angle_down);
wh->distortion_params[eye].tex_y_range.y = tan(wh->base.hmd->views[eye].fov.angle_up);
}
wh->base.hmd->distortion.models = XRT_DISTORTION_MODEL_COMPUTE;
wh->base.hmd->distortion.preferred = XRT_DISTORTION_MODEL_COMPUTE;
wh->base.compute_distortion = compute_distortion_wmr;
u_distortion_mesh_fill_in_compute(&wh->base);
// Hand over hololens sensor device to reading thread.
ret = os_thread_helper_start(&wh->oth, wmr_run_thread, wh);

View file

@ -18,6 +18,7 @@
#include "os/os_threading.h"
#include "math/m_imu_3dof.h"
#include "util/u_logging.h"
#include "util/u_distortion_mesh.h"
#include "wmr_protocol.h"
#include "wmr_config.h"
@ -41,6 +42,18 @@ enum rvb_g1_status_bits
// clang-format on
};
struct wmr_hmd_distortion_params
{
/* Inverse affine transform to move from (undistorted) pixels
* to image plane / normalised image coordinates
*/
struct xrt_matrix_3x3 inv_affine_xform;
/* tan(angle) FoV min/max for X and Y in the input texture */
struct xrt_vec2 tex_x_range;
struct xrt_vec2 tex_y_range;
};
/*!
* @implements xrt_device
*/
@ -70,6 +83,9 @@ struct wmr_hmd
//! Latest raw IPD value from the device.
uint16_t raw_ipd;
/* Distortion related parameters */
struct wmr_hmd_distortion_params distortion_params[2];
struct hololens_sensors_packet packet;
struct