From 9b288a6a1ae4dabe8b836fcc76ab45f5a1af0ebc Mon Sep 17 00:00:00 2001 From: Simon Zeni Date: Wed, 25 Oct 2023 15:49:07 -0400 Subject: [PATCH] c/[util/shader]: Implement cylinder layer for compute renderer --- src/xrt/compositor/render/render_interface.h | 16 ++- src/xrt/compositor/shaders/layer.comp | 116 ++++++++++++++++++- src/xrt/compositor/util/comp_render_cs.c | 82 +++++++++++++ 3 files changed, 212 insertions(+), 2 deletions(-) diff --git a/src/xrt/compositor/render/render_interface.h b/src/xrt/compositor/render/render_interface.h index 4dbab8309..0679ff2c6 100644 --- a/src/xrt/compositor/render/render_interface.h +++ b/src/xrt/compositor/render/render_interface.h @@ -1149,11 +1149,25 @@ struct render_compute_layer_ubo_data uint32_t padding[2]; } images_samplers[RENDER_MAX_LAYERS]; + //! Shared between cylinder and equirect2. + struct xrt_matrix_4x4 mv_inverse[RENDER_MAX_LAYERS]; + + + /*! + * For cylinder layer + */ + struct + { + float radius; + float central_angle; + float aspect_ratio; + float padding; + } cylinder_data[RENDER_MAX_LAYERS]; + /*! * For equirect2 layers */ - struct xrt_matrix_4x4 mv_inverse[RENDER_MAX_LAYERS]; struct { float radius; diff --git a/src/xrt/compositor/shaders/layer.comp b/src/xrt/compositor/shaders/layer.comp index e829abf14..a1953209d 100644 --- a/src/xrt/compositor/shaders/layer.comp +++ b/src/xrt/compositor/shaders/layer.comp @@ -44,9 +44,15 @@ layout(set = 0, binding = 3, std140) uniform restrict Config // which image/sampler(s) correspond to each layer ivec2 images_samplers[RENDER_MAX_LAYERS]; + // shared between cylinder and equirect2 + mat4 mv_inverse[RENDER_MAX_LAYERS]; + + + // for cylinder layer + vec4 cylinder_data[RENDER_MAX_LAYERS]; + // for equirect2 layer - mat4 mv_inverse[RENDER_MAX_LAYERS]; vec4 eq2_data[RENDER_MAX_LAYERS]; @@ -127,6 +133,111 @@ vec2 transform_uv(vec2 uv, uint layer) } } +vec4 do_cylinder(vec2 view_uv, uint layer) +{ + // Get ray position in model space. + const vec3 ray_origin = (ubo.mv_inverse[layer] * vec4(0, 0, 0, 1)).xyz; + + // [0 .. 1] to tangent lengths (at unit Z). + const vec2 uv = fma(view_uv, ubo.pre_transform.zw, ubo.pre_transform.xy); + + // With Z at the unit plane and flip y for OpenXR coordinate system, + // transform the ray into model space. + const vec3 ray_dir = normalize((ubo.mv_inverse[layer] * vec4(uv.x, -uv.y, -1, 0)).xyz); + + const float radius = ubo.cylinder_data[layer].x; + const float central_angle = ubo.cylinder_data[layer].y; + const float aspect_ratio = ubo.cylinder_data[layer].z; + + vec3 dir_from_cyl; + // CPU code will set +INFINITY to zero. + if (radius == 0) { + dir_from_cyl = ray_dir; + } else { + // Find if the cylinder intersects with the ray direction + // Inspired by Inigo Quilez + // https://iquilezles.org/articles/intersectors/ + + const vec3 axis = vec3(0.f, 1.f, 0.f); + + float card = dot(axis, ray_dir); + float caoc = dot(axis, ray_origin); + float a = 1.f - card * card; + float b = dot(ray_origin, ray_dir) - caoc * card; + float c = dot(ray_origin, ray_origin) - caoc * caoc - radius * radius; + float h = b * b - a * c; + if(h < 0.f) { + // no intersection + return vec4(0.f); + } + + h = sqrt(h); + vec2 distances = vec2(-b - h, -b + h) / a; + + if (distances.y < 0) { + return vec4(0.f); + } + + dir_from_cyl = normalize(ray_origin + (ray_dir * distances.y)); + } + + const float lon = atan(dir_from_cyl.x, -dir_from_cyl.z) / (2 * PI) + 0.5; // => [0, 1] + // float lat = -asin(dir_from_cyl.y); // => [-π/2, π/2] + // float y = tan(lat); // => [-inf, inf] + // simplified: -y/sqrt(1 - y^2) + const float y = -dir_from_cyl.y / sqrt(1 - (dir_from_cyl.y * dir_from_cyl.y)); // => [-inf, inf] + + vec4 out_color = vec4(0.f); + +#ifdef DEBUG + const int lon_int = int(lon * 1000.f); + const int y_int = int(y * 1000.f); + + if (lon < 0.001 && lon > -0.001) { + out_color = vec4(1, 0, 0, 1); + } else if (lon_int % 50 == 0) { + out_color = vec4(1, 1, 1, 1); + } else if (y_int % 50 == 0) { + out_color = vec4(1, 1, 1, 1); + } else { + out_color = vec4(lon, y, 0, 1); + } +#endif + + const float chan = central_angle / (PI * 2.f); + + // height in radii, radius only matters for determining intersection + const float height = central_angle * aspect_ratio; + + // Normalize [0, 2π] to [0, 1] + const float uhan = 0.5 + chan / 2.f; + const float lhan = 0.5 - chan / 2.f; + + const float ymin = -height / 2; + const float ymax = height / 2; + + if (y < ymax && y > ymin && lon < uhan && lon > lhan) { + // map configured display region to whole texture + vec2 offset = vec2(lhan, ymin); + vec2 extent = vec2(uhan - lhan, ymax - ymin); + vec2 sample_point = (vec2(lon, y) - offset) / extent; + + vec2 uv_sub = fma(sample_point, ubo.post_transform[layer].zw, ubo.post_transform[layer].xy); + + uint index = ubo.images_samplers[layer].x; +#ifdef DEBUG + out_color += texture(source[index], uv_sub) / 2.f; +#else + + out_color = texture(source[index], uv_sub); +#endif + } else { + out_color += vec4(0.f); + } + + return out_color; +} + vec4 do_equirect2(vec2 view_uv, uint layer) { // Get ray position in model space. @@ -347,6 +458,9 @@ vec4 do_layers(vec2 view_uv) vec4 rgba = vec4(0, 0, 0, 0); switch (ubo.layer_type_and_unpremultiplied[layer].x) { + case XRT_LAYER_CYLINDER: + rgba = do_cylinder(view_uv, layer); + break; case XRT_LAYER_EQUIRECT2: rgba = do_equirect2(view_uv, layer); break; diff --git a/src/xrt/compositor/util/comp_render_cs.c b/src/xrt/compositor/util/comp_render_cs.c index 982a7e77a..0b694d88e 100644 --- a/src/xrt/compositor/util/comp_render_cs.c +++ b/src/xrt/compositor/util/comp_render_cs.c @@ -242,6 +242,71 @@ do_cs_quad_layer(const struct xrt_layer_data *data, } +static inline void +do_cs_cylinder_layer(const struct xrt_layer_data *data, + const struct comp_layer *layer, + const struct xrt_matrix_4x4 *eye_view_mat, + const struct xrt_matrix_4x4 *world_view_mat, + uint32_t view_index, + uint32_t cur_layer, + uint32_t cur_image, + VkSampler clamp_to_edge, + VkSampler clamp_to_border_black, + VkSampler src_samplers[RENDER_MAX_IMAGES], + VkImageView src_image_views[RENDER_MAX_IMAGES], + struct render_compute_layer_ubo_data *ubo_data, + uint32_t *out_cur_image) +{ + const struct xrt_layer_cylinder_data *c = &data->cylinder; + + const struct comp_swapchain_image *image = &layer->sc_array[0]->images[c->sub.image_index]; + uint32_t array_index = c->sub.array_index; + + // Image to use. + src_samplers[cur_image] = clamp_to_edge; + src_image_views[cur_image] = get_image_view(image, data->flags, array_index); + + // Used for Subimage and OpenGL flip. + set_post_transform_rect( // + data, // data + &c->sub.norm_rect, // src_norm_rect + false, // invert_flip + &ubo_data->post_transforms[cur_layer]); // out_norm_rect + + ubo_data->cylinder_data[cur_layer].central_angle = c->central_angle; + ubo_data->cylinder_data[cur_layer].aspect_ratio = c->aspect_ratio; + + struct xrt_vec3 scale = {1.f, 1.f, 1.f}; + + struct xrt_matrix_4x4 model; + math_matrix_4x4_model(&c->pose, &scale, &model); + + struct xrt_matrix_4x4 model_inv; + math_matrix_4x4_inverse(&model, &model_inv); + + const struct xrt_matrix_4x4 *v = is_layer_view_space(data) ? eye_view_mat : world_view_mat; + + struct xrt_matrix_4x4 v_inv; + math_matrix_4x4_inverse(v, &v_inv); + + math_matrix_4x4_multiply(&model_inv, &v_inv, &ubo_data->mv_inverse[cur_layer]); + + // Simplifies the shader. + if (c->radius >= INFINITY) { + ubo_data->cylinder_data[cur_layer].radius = 0.f; + } else { + ubo_data->cylinder_data[cur_layer].radius = c->radius; + } + + ubo_data->cylinder_data[cur_layer].central_angle = c->central_angle; + ubo_data->cylinder_data[cur_layer].aspect_ratio = c->aspect_ratio; + + ubo_data->images_samplers[cur_layer].images[0] = cur_image; + cur_image++; + + *out_cur_image = cur_image; +} + /* * * Compute distortion helpers. @@ -408,6 +473,7 @@ comp_render_cs_layer(struct render_compute *crc, */ uint32_t required_image_samplers; switch (data->type) { + case XRT_LAYER_CYLINDER: required_image_samplers = 1; break; case XRT_LAYER_EQUIRECT2: required_image_samplers = 1; break; case XRT_LAYER_STEREO_PROJECTION: required_image_samplers = 1; break; case XRT_LAYER_STEREO_PROJECTION_DEPTH: required_image_samplers = 2; break; @@ -423,6 +489,22 @@ comp_render_cs_layer(struct render_compute *crc, } switch (data->type) { + case XRT_LAYER_CYLINDER: + do_cs_cylinder_layer( // + data, // data + layer, // layer + &eye_view_mat, // eye_view_mat + &world_view_mat, // world_view_mat + view_index, // view_index + cur_layer, // cur_layer + cur_image, // cur_image + clamp_to_edge, // clamp_to_edge + clamp_to_border_black, // clamp_to_border_black + src_samplers, // src_samplers + src_image_views, // src_image_views + ubo_data, // ubo_data + &cur_image); // out_cur_image + break; case XRT_LAYER_EQUIRECT2: do_cs_equirect2_layer( // data, // data