The open source OpenXR runtime
1// Copyright 2020-2023, Collabora Ltd.
2//
3// Author: Jakob Bornecrantz <jakob@collabora.com>
4// Author: Charlton Rodda <charlton.rodda@collabora.com>
5// Author: Lubosz Sarnecki <lubosz.sarnecki@collabora.com>
6// Author: Simon Zeni <simon.zeni@collabora.com>
7//
8// SPDX-License-Identifier: BSL-1.0
9
10#version 460
11
12layout (binding = 0, std140) uniform Config
13{
14 vec4 post_transform;
15 mat4 mv_inverse;
16 vec4 to_tangent;
17 float radius;
18 float central_horizontal_angle;
19 float upper_vertical_angle;
20 float lower_vertical_angle;
21} ubo;
22
23layout (binding = 1) uniform sampler2D image;
24
25layout (location = 0) flat in vec3 in_camera_position;
26layout (location = 1) in vec3 in_camera_ray_unnormalized;
27layout (location = 0) out vec4 out_color;
28
29const float PI = acos(-1);
30
31
32vec2 sphere_intersect(vec3 ray_origin, vec3 ray_direction, vec3 sphere_center, float radius)
33{
34 vec3 ray_sphere_diff = ray_origin - sphere_center;
35
36 float B = dot(ray_sphere_diff, ray_direction);
37
38 vec3 QC = ray_sphere_diff - B * ray_direction;
39
40 float H = radius * radius - dot(QC, QC);
41
42 if (H < 0.0) {
43 return vec2(-1.0); // no intersection
44 }
45
46 H = sqrt(H);
47
48 return vec2(-B - H, -B + H);
49}
50
51void main ()
52{
53 vec3 ray_origin = in_camera_position;
54 vec3 ray_dir = normalize(in_camera_ray_unnormalized);
55
56 vec3 dir_from_sph;
57 // CPU code will set +INFINITY to zero.
58 if (ubo.radius == 0) {
59 dir_from_sph = ray_dir;
60 } else {
61 vec2 distances = sphere_intersect(ray_origin, ray_dir, vec3(0, 0, 0), ubo.radius);
62
63 if (distances.y < 0) {
64 out_color = vec4(0.0);
65 return;
66 }
67
68 vec3 pos = ray_origin + (ray_dir * distances.y);
69 dir_from_sph = normalize(pos);
70 }
71
72 float lon = atan(dir_from_sph.x, -dir_from_sph.z) / (2 * PI) + 0.5;
73 float lat = acos(dir_from_sph.y) / PI;
74
75#ifdef DEBUG
76 int lon_int = int(lon * 1000.0);
77 int lat_int = int(lat * 1000.0);
78
79 if (lon < 0.001 && lon > -0.001) {
80 out_color = vec4(1, 0, 0, 1);
81 } else if (lon_int % 50 == 0) {
82 out_color = vec4(1, 1, 1, 1);
83 } else if (lat_int % 50 == 0) {
84 out_color = vec4(1, 1, 1, 1);
85 } else {
86 out_color = vec4(lon, lat, 0, 1);
87 }
88#endif
89
90 float chan = ubo.central_horizontal_angle / (PI * 2.0f);
91
92 // Normalize [0, 2π] to [0, 1]
93 float uhan = 0.5 + chan / 2.0f;
94 float lhan = 0.5 - chan / 2.0f;
95
96 // Normalize [-π/2, π/2] to [0, 1]
97 float uvan = ubo.upper_vertical_angle / PI + 0.5f;
98 float lvan = ubo.lower_vertical_angle / PI + 0.5f;
99
100 if (lat < uvan && lat > lvan && lon < uhan && lon > lhan) {
101 // map configured display region to whole texture
102 vec2 ll_offset = vec2(lhan, lvan);
103 vec2 ll_extent = vec2(uhan - lhan, uvan - lvan);
104 vec2 sample_point = (vec2(lon, lat) - ll_offset) / ll_extent;
105
106 vec2 uv_sub = fma(sample_point, ubo.post_transform.zw, ubo.post_transform.xy);
107
108#ifdef DEBUG
109 out_color += texture(image, uv_sub) / 2.0;
110#else
111 out_color = texture(image, uv_sub);
112 } else {
113 out_color = vec4(0, 0, 0, 0);
114#endif
115 }
116}