Blender V5.0
wm_xr_draw.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
12
13#include <cstring>
14
15#include "DNA_userdef_types.h"
16
17#include "BLI_listbase.h"
18#include "BLI_math_geom.h"
19#include "BLI_math_matrix.h"
20#include "BLI_math_rotation.h"
21#include "BLI_math_vector.h"
22
24
25#include "GHOST_C-api.h"
26
27#include "GPU_batch_presets.hh"
28#include "GPU_immediate.hh"
29#include "GPU_matrix.hh"
30#include "GPU_state.hh"
31#include "GPU_viewport.hh"
32
33#include "UI_resources.hh"
34
35#include "WM_api.hh"
36
37#include "wm_xr_intern.hh"
38
39void wm_xr_pose_to_mat(const GHOST_XrPose *pose, float r_mat[4][4])
40{
41 quat_to_mat4(r_mat, pose->orientation_quat);
42 copy_v3_v3(r_mat[3], pose->position);
43}
44
45void wm_xr_pose_scale_to_mat(const GHOST_XrPose *pose, float scale, float r_mat[4][4])
46{
47 wm_xr_pose_to_mat(pose, r_mat);
48
49 BLI_assert(scale > 0.0f);
50 mul_v3_fl(r_mat[0], scale);
51 mul_v3_fl(r_mat[1], scale);
52 mul_v3_fl(r_mat[2], scale);
53}
54
55void wm_xr_pose_to_imat(const GHOST_XrPose *pose, float r_imat[4][4])
56{
57 float iquat[4];
58 invert_qt_qt_normalized(iquat, pose->orientation_quat);
59 quat_to_mat4(r_imat, iquat);
60 translate_m4(r_imat, -pose->position[0], -pose->position[1], -pose->position[2]);
61}
62
63void wm_xr_pose_scale_to_imat(const GHOST_XrPose *pose, float scale, float r_imat[4][4])
64{
65 float iquat[4];
66 invert_qt_qt_normalized(iquat, pose->orientation_quat);
67 quat_to_mat4(r_imat, iquat);
68
69 BLI_assert(scale > 0.0f);
70 scale = 1.0f / scale;
71 mul_v3_fl(r_imat[0], scale);
72 mul_v3_fl(r_imat[1], scale);
73 mul_v3_fl(r_imat[2], scale);
74
75 translate_m4(r_imat, -pose->position[0], -pose->position[1], -pose->position[2]);
76}
77
78static void wm_xr_draw_matrices_create(const wmXrDrawData *draw_data,
79 const GHOST_XrDrawViewInfo *draw_view,
80 const XrSessionSettings *session_settings,
81 const wmXrSessionState *session_state,
82 float r_viewmat[4][4],
83 float r_projmat[4][4])
84{
85 GHOST_XrPose eye_pose;
86 float eye_inv[4][4], base_inv[4][4], nav_inv[4][4], m[4][4];
87
88 /* Calculate inverse eye matrix. */
89 copy_qt_qt(eye_pose.orientation_quat, draw_view->eye_pose.orientation_quat);
90 copy_v3_v3(eye_pose.position, draw_view->eye_pose.position);
91 if ((session_settings->flag & XR_SESSION_USE_POSITION_TRACKING) == 0) {
92 sub_v3_v3(eye_pose.position, draw_view->local_pose.position);
93 }
94 if ((session_settings->flag & XR_SESSION_USE_ABSOLUTE_TRACKING) == 0) {
95 sub_v3_v3(eye_pose.position, draw_data->eye_position_ofs);
96 }
97
98 wm_xr_pose_to_imat(&eye_pose, eye_inv);
99
100 /* Apply base pose and navigation. */
101 wm_xr_pose_scale_to_imat(&draw_data->base_pose, draw_data->base_scale, base_inv);
102 wm_xr_pose_scale_to_imat(&session_state->nav_pose_prev, session_state->nav_scale_prev, nav_inv);
103 mul_m4_m4m4(m, eye_inv, base_inv);
104 mul_m4_m4m4(r_viewmat, m, nav_inv);
105
106 perspective_m4_fov(r_projmat,
107 draw_view->fov.angle_left,
108 draw_view->fov.angle_right,
109 draw_view->fov.angle_up,
110 draw_view->fov.angle_down,
111 session_settings->clip_start,
112 session_settings->clip_end);
113}
114
116 const wmXrRuntimeData *runtime_data,
117 const wmXrSurfaceData *surface_data,
118 const GHOST_XrDrawViewInfo *draw_view)
119{
120 const wmXrViewportPair *vp = static_cast<const wmXrViewportPair *>(
121 BLI_findlink(&surface_data->viewports, draw_view->view_idx));
122 BLI_assert(vp && vp->viewport);
123
124 const bool is_upside_down = GHOST_XrSessionNeedsUpsideDownDrawing(runtime_data->context);
125 rcti rect{};
126 rect.xmin = 0;
127 rect.ymin = 0;
128 rect.xmax = draw_view->width - 1;
129 rect.ymax = draw_view->height - 1;
130
131 wmViewport(&rect);
132
133 /* For upside down contexts, draw with inverted y-values. */
134 if (is_upside_down) {
135 std::swap(rect.ymin, rect.ymax);
136 }
137 GPU_viewport_draw_to_screen_ex(vp->viewport, 0, &rect, draw_view->expects_srgb_buffer, true);
138}
139
140void wm_xr_draw_view(const GHOST_XrDrawViewInfo *draw_view, void *customdata)
141{
142 wmXrDrawData *draw_data = static_cast<wmXrDrawData *>(customdata);
143 wmXrData *xr_data = draw_data->xr_data;
144 wmXrSurfaceData *surface_data = draw_data->surface_data;
145 wmXrSessionState *session_state = &xr_data->runtime->session_state;
146 XrSessionSettings *settings = &xr_data->session_settings;
147
148 const int display_flags = V3D_OFSDRAW_OVERRIDE_SCENE_SETTINGS | settings->draw_flags;
149
150 float viewmat[4][4], winmat[4][4];
151
153
154 wm_xr_session_draw_data_update(session_state, settings, draw_view, draw_data);
155 wm_xr_draw_matrices_create(draw_data, draw_view, settings, session_state, viewmat, winmat);
156 wm_xr_session_state_update(settings, draw_data, draw_view, session_state);
157
158 if (!wm_xr_session_surface_offscreen_ensure(surface_data, draw_view)) {
159 return;
160 }
161
162 const wmXrViewportPair *vp = static_cast<const wmXrViewportPair *>(
163 BLI_findlink(&surface_data->viewports, draw_view->view_idx));
164 BLI_assert(vp && vp->offscreen && vp->viewport);
165
166 /* In case a framebuffer is still bound from drawing the last eye. */
168 /* Some systems have drawing glitches without this. */
169 GPU_clear_depth(1.0f);
170
171 /* Draws the view into the surface_data->viewport's frame-buffers. */
173 draw_data->scene,
174 &settings->shading,
175 (eDrawType)settings->shading.type,
178 draw_view->width,
179 draw_view->height,
180 display_flags,
181 viewmat,
182 winmat,
183 settings->clip_start,
184 settings->clip_end,
185 session_state->vignette_data->aperture,
186 true,
187 false,
188 true,
189 nullptr,
190 false,
191 vp->offscreen,
192 vp->viewport);
193
194 /* The draw-manager uses both GPUOffscreen and GPUViewport to manage frame and texture buffers. A
195 * call to GPU_viewport_draw_to_screen() is still needed to get the final result from the
196 * viewport buffers composited together and potentially color managed for display on screen.
197 * It needs a bound frame-buffer to draw into, for which we simply reuse the GPUOffscreen one.
198 *
199 * In a next step, Ghost-XR will use the currently bound frame-buffer to retrieve the image
200 * to be submitted to the OpenXR swap-chain. So do not un-bind the off-screen yet! */
201
202 GPU_offscreen_bind(vp->offscreen, false);
203
204 wm_xr_draw_viewport_buffers_to_active_framebuffer(xr_data->runtime, surface_data, draw_view);
205}
206
207bool wm_xr_passthrough_enabled(void *customdata)
208{
209 wmXrDrawData *draw_data = static_cast<wmXrDrawData *>(customdata);
210 wmXrData *xr_data = draw_data->xr_data;
211 XrSessionSettings *settings = &xr_data->session_settings;
212
213 return (settings->draw_flags & V3D_OFSDRAW_XR_SHOW_PASSTHROUGH) != 0;
214}
215
216void wm_xr_disable_passthrough(void *customdata)
217{
218 wmXrDrawData *draw_data = static_cast<wmXrDrawData *>(customdata);
219 wmXrData *xr_data = draw_data->xr_data;
220 XrSessionSettings *settings = &xr_data->session_settings;
221
223 WM_global_report(RPT_INFO, "Passthrough not available");
224}
225
226static blender::gpu::Batch *wm_xr_controller_model_batch_create(GHOST_XrContextHandle xr_context,
227 const char *subaction_path)
228{
229 GHOST_XrControllerModelData model_data;
230
231 if (!GHOST_XrGetControllerModelData(xr_context, subaction_path, &model_data) ||
232 model_data.count_vertices < 1)
233 {
234 return nullptr;
235 }
236
237 GPUVertFormat format = {0};
238 GPU_vertformat_attr_add(&format, "pos", blender::gpu::VertAttrType::SFLOAT_32_32_32);
239 GPU_vertformat_attr_add(&format, "nor", blender::gpu::VertAttrType::SFLOAT_32_32_32);
240
242 GPU_vertbuf_data_alloc(*vbo, model_data.count_vertices);
243 vbo->data<GHOST_XrControllerModelVertex>().copy_from(
244 {model_data.vertices, model_data.count_vertices});
245
246 blender::gpu::IndexBuf *ibo = nullptr;
247 if (model_data.count_indices > 0 && ((model_data.count_indices % 3) == 0)) {
248 GPUIndexBufBuilder ibo_builder;
249 const uint prim_len = model_data.count_indices / 3;
250 GPU_indexbuf_init(&ibo_builder, GPU_PRIM_TRIS, prim_len, model_data.count_vertices);
251 for (uint i = 0; i < prim_len; ++i) {
252 const uint32_t *idx = &model_data.indices[i * 3];
253 GPU_indexbuf_add_tri_verts(&ibo_builder, idx[0], idx[1], idx[2]);
254 }
255 ibo = GPU_indexbuf_build(&ibo_builder);
256 }
257
259}
260
262 GHOST_XrContextHandle xr_context,
264{
265 GHOST_XrControllerModelData model_data;
266
267 float color[4];
268 switch (settings->controller_draw_style) {
271 color[0] = color[1] = color[2] = 0.0f;
272 color[3] = 0.4f;
273 break;
276 color[0] = 0.422f;
277 color[1] = 0.438f;
278 color[2] = 0.446f;
279 color[3] = 0.4f;
280 break;
281 }
282
285
286 LISTBASE_FOREACH (wmXrController *, controller, &state->controllers) {
287 if (!controller->grip_active) {
288 continue;
289 }
290
291 blender::gpu::Batch *model = controller->model;
292 if (!model) {
293 model = controller->model = wm_xr_controller_model_batch_create(xr_context,
294 controller->subaction_path);
295 }
296
297 if (model &&
298 GHOST_XrGetControllerModelData(xr_context, controller->subaction_path, &model_data) &&
299 model_data.count_components > 0)
300 {
302 GPU_batch_uniform_4fv(model, "color", color);
303
305 GPU_matrix_mul(controller->grip_mat);
306 for (uint component_idx = 0; component_idx < model_data.count_components; ++component_idx) {
307 const GHOST_XrControllerModelComponent *component = &model_data.components[component_idx];
309 GPU_matrix_mul(component->transform);
311 model->elem ? component->index_offset : component->vertex_offset,
312 model->elem ? component->index_count : component->vertex_count);
314 }
316 }
317 else {
318 /* Fallback. */
319 const float scale = 0.05f;
320 blender::gpu::Batch *sphere = GPU_batch_preset_sphere(2);
322 GPU_batch_uniform_4fv(sphere, "color", color);
323
325 GPU_matrix_mul(controller->grip_mat);
326 GPU_matrix_scale_1f(scale);
327 GPU_batch_draw(sphere);
329 }
330 }
331}
332
334{
335 bool draw_ray;
336 switch (settings->controller_draw_style) {
339 draw_ray = false;
340 break;
343 draw_ray = !state->is_raycast_shown;
344 break;
345 }
346
348 uint pos = GPU_vertformat_attr_add(format, "pos", blender::gpu::VertAttrType::SFLOAT_32_32_32);
350 format, "color", blender::gpu::VertAttrType::SFLOAT_32_32_32_32);
352
353 float viewport[4];
354 GPU_viewport_size_get_f(viewport);
355 immUniform2fv("viewportSize", &viewport[2]);
356
357 immUniform1f("lineWidth", 3.0f * U.pixelsize);
358
359 if (draw_ray) {
360 const float color[4] = {0.33f, 0.33f, 1.0f, 0.5f};
361 const float scale = settings->clip_end;
362 float ray[3];
363
366
367 LISTBASE_FOREACH (wmXrController *, controller, &state->controllers) {
368 if (!controller->grip_active) {
369 continue;
370 }
371
373
374 const float (*mat)[4] = controller->aim_mat;
375 madd_v3_v3v3fl(ray, mat[3], mat[2], -scale);
376
378 immVertex3fv(pos, mat[3]);
379 immAttr4fv(col, color);
380 immVertex3fv(pos, ray);
381
382 immEnd();
383 }
384 }
385 else {
386 const float r[4] = {255 / 255.0f, 51 / 255.0f, 82 / 255.0f, 255 / 255.0f};
387 const float g[4] = {139 / 255.0f, 220 / 255.0f, 0 / 255.0f, 255 / 255.0f};
388 const float b[4] = {40 / 255.0f, 144 / 255.0f, 255 / 255.0f, 255 / 255.0f};
389 const float scale = 0.01f;
390 float x_axis[3], y_axis[3], z_axis[3];
391
394
395 LISTBASE_FOREACH (wmXrController *, controller, &state->controllers) {
396 if (!controller->grip_active) {
397 continue;
398 }
399
401
402 const float (*mat)[4] = controller->aim_mat;
403 madd_v3_v3v3fl(x_axis, mat[3], mat[0], scale);
404 madd_v3_v3v3fl(y_axis, mat[3], mat[1], scale);
405 madd_v3_v3v3fl(z_axis, mat[3], mat[2], scale);
406
408 immVertex3fv(pos, mat[3]);
409 immAttr4fv(col, r);
410 immVertex3fv(pos, x_axis);
411
413 immVertex3fv(pos, mat[3]);
414 immAttr4fv(col, g);
415 immVertex3fv(pos, y_axis);
416
418 immVertex3fv(pos, mat[3]);
419 immAttr4fv(col, b);
420 immVertex3fv(pos, z_axis);
421
422 immEnd();
423 }
424 }
425
427}
428
429void wm_xr_draw_controllers(const bContext * /*C*/, ARegion * /*region*/, void *customdata)
430{
431 wmXrData *xr = static_cast<wmXrData *>(customdata);
432 const XrSessionSettings *settings = &xr->session_settings;
433 GHOST_XrContextHandle xr_context = xr->runtime->context;
435
436 wm_xr_controller_model_draw(settings, xr_context, state);
438}
@ RPT_INFO
Definition BKE_report.hh:35
#define BLI_assert(a)
Definition BLI_assert.h:46
void * BLI_findlink(const ListBase *listbase, int number) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition listbase.cc:534
#define LISTBASE_FOREACH(type, var, list)
void perspective_m4_fov(float mat[4][4], float angle_left, float angle_right, float angle_up, float angle_down, float nearClip, float farClip)
void mul_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4])
void translate_m4(float mat[4][4], float Tx, float Ty, float Tz)
void quat_to_mat4(float m[4][4], const float q[4])
void invert_qt_qt_normalized(float q1[4], const float q2[4])
void copy_qt_qt(float q[4], const float a[4])
MINLINE void sub_v3_v3(float r[3], const float a[3])
MINLINE void mul_v3_fl(float r[3], float f)
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE void madd_v3_v3v3fl(float r[3], const float a[3], const float b[3], float f)
unsigned int uint
eDrawType
@ V3D_OFSDRAW_OVERRIDE_SCENE_SETTINGS
@ V3D_OFSDRAW_XR_SHOW_PASSTHROUGH
@ XR_SESSION_USE_ABSOLUTE_TRACKING
@ XR_SESSION_USE_POSITION_TRACKING
@ XR_CONTROLLER_DRAW_LIGHT_RAY
@ XR_CONTROLLER_DRAW_LIGHT
@ XR_CONTROLLER_DRAW_DARK_RAY
@ XR_CONTROLLER_DRAW_DARK
void ED_view3d_draw_offscreen_simple(Depsgraph *depsgraph, Scene *scene, View3DShading *shading_override, eDrawType drawtype, int object_type_exclude_viewport_override, int object_type_exclude_select_override, int winx, int winy, unsigned int draw_flags, const float viewmat[4][4], const float winmat[4][4], float clip_start, float clip_end, float vignette_aperture, bool is_xr_surface, bool is_image_render, bool draw_background, const char *viewname, bool do_color_management, GPUOffScreen *ofs, GPUViewport *viewport)
static Controller * controller
GHOST C-API function and type declarations.
void GPU_batch_program_set_builtin(blender::gpu::Batch *batch, GPUBuiltinShader shader_id)
blender::gpu::Batch * GPU_batch_create_ex(GPUPrimType primitive_type, blender::gpu::VertBuf *vertex_buf, blender::gpu::IndexBuf *index_buf, GPUBatchFlag owns_flag)
Definition gpu_batch.cc:51
@ GPU_BATCH_OWNS_INDEX
Definition GPU_batch.hh:46
@ GPU_BATCH_OWNS_VBO
Definition GPU_batch.hh:42
void GPU_batch_draw(blender::gpu::Batch *batch)
#define GPU_batch_uniform_4fv(batch, name, val)
Definition GPU_batch.hh:279
void GPU_batch_draw_range(blender::gpu::Batch *batch, int vertex_first, int vertex_count)
blender::gpu::Batch * GPU_batch_preset_sphere(int lod) ATTR_WARN_UNUSED_RESULT
void GPU_offscreen_bind(GPUOffScreen *offscreen, bool save)
void GPU_framebuffer_restore()
void GPU_clear_depth(float depth)
void immEnd()
void immUniform2fv(const char *name, const float data[2])
void immUnbindProgram()
void immAttr4fv(uint attr_id, const float data[4])
void immBindBuiltinProgram(GPUBuiltinShader shader_id)
void immAttrSkip(uint attr_id)
void immUniform1f(const char *name, float x)
GPUVertFormat * immVertexFormat()
void immVertex3fv(uint attr_id, const float data[3])
void immBegin(GPUPrimType, uint vertex_len)
void GPU_indexbuf_init(GPUIndexBufBuilder *, GPUPrimType, uint prim_len, uint vertex_len)
blender::gpu::IndexBuf * GPU_indexbuf_build(GPUIndexBufBuilder *)
void GPU_indexbuf_add_tri_verts(GPUIndexBufBuilder *, uint v1, uint v2, uint v3)
void GPU_matrix_push()
#define GPU_matrix_mul(x)
void GPU_matrix_scale_1f(float factor)
void GPU_matrix_pop()
@ GPU_PRIM_LINES
@ GPU_PRIM_TRIS
@ GPU_SHADER_3D_UNIFORM_COLOR
@ GPU_SHADER_3D_POLYLINE_FLAT_COLOR
@ GPU_DEPTH_LESS_EQUAL
Definition GPU_state.hh:114
@ GPU_DEPTH_NONE
Definition GPU_state.hh:111
@ GPU_BLEND_NONE
Definition GPU_state.hh:85
@ GPU_BLEND_ALPHA
Definition GPU_state.hh:87
void GPU_blend(GPUBlend blend)
Definition gpu_state.cc:42
void GPU_depth_test(GPUDepthTest test)
Definition gpu_state.cc:68
void GPU_viewport_size_get_f(float coords[4])
Definition gpu_state.cc:273
static blender::gpu::VertBuf * GPU_vertbuf_create_with_format(const GPUVertFormat &format)
void GPU_vertbuf_data_alloc(blender::gpu::VertBuf &verts, uint v_len)
uint GPU_vertformat_attr_add(GPUVertFormat *format, blender::StringRef name, blender::gpu::VertAttrType type)
void GPU_viewport_draw_to_screen_ex(GPUViewport *viewport, int view, const rcti *rect, bool display_colorspace, bool do_overlay_merge)
#define U
MutableSpan< T > data()
nullptr float
uint pos
uint col
format
static ulong state[N]
int object_type_exclude_viewport
struct View3DShading shading
int ymin
int ymax
int xmin
int xmax
XrSessionSettings session_settings
struct wmXrRuntimeData * runtime
wmXrData * xr_data
float eye_position_ofs[3]
struct Depsgraph * depsgraph
GHOST_XrPose base_pose
wmXrSurfaceData * surface_data
struct Scene * scene
GHOST_XrContextHandle context
wmXrSessionState session_state
GHOST_XrPose nav_pose_prev
struct wmXrVignetteData * vignette_data
struct GPUViewport * viewport
struct GPUOffScreen * offscreen
i
Definition text_draw.cc:230
void WM_global_report(eReportType type, const char *message)
void wmViewport(const rcti *winrct)
void wm_xr_pose_to_mat(const GHOST_XrPose *pose, float r_mat[4][4])
Definition wm_xr_draw.cc:39
static void wm_xr_draw_viewport_buffers_to_active_framebuffer(const wmXrRuntimeData *runtime_data, const wmXrSurfaceData *surface_data, const GHOST_XrDrawViewInfo *draw_view)
void wm_xr_draw_controllers(const bContext *, ARegion *, void *customdata)
static void wm_xr_controller_model_draw(const XrSessionSettings *settings, GHOST_XrContextHandle xr_context, wmXrSessionState *state)
static void wm_xr_controller_aim_draw(const XrSessionSettings *settings, wmXrSessionState *state)
void wm_xr_pose_scale_to_mat(const GHOST_XrPose *pose, float scale, float r_mat[4][4])
Definition wm_xr_draw.cc:45
static void wm_xr_draw_matrices_create(const wmXrDrawData *draw_data, const GHOST_XrDrawViewInfo *draw_view, const XrSessionSettings *session_settings, const wmXrSessionState *session_state, float r_viewmat[4][4], float r_projmat[4][4])
Definition wm_xr_draw.cc:78
bool wm_xr_passthrough_enabled(void *customdata)
Check if XR passthrough is enabled.
static blender::gpu::Batch * wm_xr_controller_model_batch_create(GHOST_XrContextHandle xr_context, const char *subaction_path)
void wm_xr_disable_passthrough(void *customdata)
Disable XR passthrough if not supported.
void wm_xr_pose_scale_to_imat(const GHOST_XrPose *pose, float scale, float r_imat[4][4])
Definition wm_xr_draw.cc:63
void wm_xr_draw_view(const GHOST_XrDrawViewInfo *draw_view, void *customdata)
Draw a viewport for a single eye.
void wm_xr_pose_to_imat(const GHOST_XrPose *pose, float r_imat[4][4])
Definition wm_xr_draw.cc:55
void wm_xr_session_draw_data_update(wmXrSessionState *state, const XrSessionSettings *settings, const GHOST_XrDrawViewInfo *draw_view, wmXrDrawData *draw_data)
void wm_xr_session_state_update(const XrSessionSettings *settings, const wmXrDrawData *draw_data, const GHOST_XrDrawViewInfo *draw_view, wmXrSessionState *state)
bool wm_xr_session_surface_offscreen_ensure(wmXrSurfaceData *surface_data, const GHOST_XrDrawViewInfo *draw_view)
bool WM_xr_session_is_ready(const wmXrData *xr)