Blender V4.3
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
13#include <cstring>
14
15#include "BLI_listbase.h"
16#include "BLI_math_matrix.h"
17#include "BLI_math_rotation.h"
18#include "BLI_math_vector.h"
19
21
22#include "GHOST_C-api.h"
23#include "GPU_batch_presets.hh"
24#include "GPU_immediate.hh"
25#include "GPU_matrix.hh"
26
27#include "GPU_viewport.hh"
28
29#include "WM_api.hh"
30
31#include "wm_xr_intern.hh"
32
33void wm_xr_pose_to_mat(const GHOST_XrPose *pose, float r_mat[4][4])
34{
35 quat_to_mat4(r_mat, pose->orientation_quat);
36 copy_v3_v3(r_mat[3], pose->position);
37}
38
39void wm_xr_pose_scale_to_mat(const GHOST_XrPose *pose, float scale, float r_mat[4][4])
40{
41 wm_xr_pose_to_mat(pose, r_mat);
42
43 BLI_assert(scale > 0.0f);
44 mul_v3_fl(r_mat[0], scale);
45 mul_v3_fl(r_mat[1], scale);
46 mul_v3_fl(r_mat[2], scale);
47}
48
49void wm_xr_pose_to_imat(const GHOST_XrPose *pose, float r_imat[4][4])
50{
51 float iquat[4];
52 invert_qt_qt_normalized(iquat, pose->orientation_quat);
53 quat_to_mat4(r_imat, iquat);
54 translate_m4(r_imat, -pose->position[0], -pose->position[1], -pose->position[2]);
55}
56
57void wm_xr_pose_scale_to_imat(const GHOST_XrPose *pose, float scale, float r_imat[4][4])
58{
59 float iquat[4];
60 invert_qt_qt_normalized(iquat, pose->orientation_quat);
61 quat_to_mat4(r_imat, iquat);
62
63 BLI_assert(scale > 0.0f);
64 scale = 1.0f / scale;
65 mul_v3_fl(r_imat[0], scale);
66 mul_v3_fl(r_imat[1], scale);
67 mul_v3_fl(r_imat[2], scale);
68
69 translate_m4(r_imat, -pose->position[0], -pose->position[1], -pose->position[2]);
70}
71
72static void wm_xr_draw_matrices_create(const wmXrDrawData *draw_data,
73 const GHOST_XrDrawViewInfo *draw_view,
74 const XrSessionSettings *session_settings,
75 const wmXrSessionState *session_state,
76 float r_viewmat[4][4],
77 float r_projmat[4][4])
78{
79 GHOST_XrPose eye_pose;
80 float eye_inv[4][4], base_inv[4][4], nav_inv[4][4], m[4][4];
81
82 /* Calculate inverse eye matrix. */
83 copy_qt_qt(eye_pose.orientation_quat, draw_view->eye_pose.orientation_quat);
84 copy_v3_v3(eye_pose.position, draw_view->eye_pose.position);
85 if ((session_settings->flag & XR_SESSION_USE_POSITION_TRACKING) == 0) {
86 sub_v3_v3(eye_pose.position, draw_view->local_pose.position);
87 }
88 if ((session_settings->flag & XR_SESSION_USE_ABSOLUTE_TRACKING) == 0) {
89 sub_v3_v3(eye_pose.position, draw_data->eye_position_ofs);
90 }
91
92 wm_xr_pose_to_imat(&eye_pose, eye_inv);
93
94 /* Apply base pose and navigation. */
95 wm_xr_pose_scale_to_imat(&draw_data->base_pose, draw_data->base_scale, base_inv);
96 wm_xr_pose_scale_to_imat(&session_state->nav_pose_prev, session_state->nav_scale_prev, nav_inv);
97 mul_m4_m4m4(m, eye_inv, base_inv);
98 mul_m4_m4m4(r_viewmat, m, nav_inv);
99
100 perspective_m4_fov(r_projmat,
101 draw_view->fov.angle_left,
102 draw_view->fov.angle_right,
103 draw_view->fov.angle_up,
104 draw_view->fov.angle_down,
105 session_settings->clip_start,
106 session_settings->clip_end);
107}
108
110 const wmXrRuntimeData *runtime_data,
111 const wmXrSurfaceData *surface_data,
112 const GHOST_XrDrawViewInfo *draw_view)
113{
114 const wmXrViewportPair *vp = static_cast<const wmXrViewportPair *>(
115 BLI_findlink(&surface_data->viewports, draw_view->view_idx));
116 BLI_assert(vp && vp->viewport);
117
118 const bool is_upside_down = GHOST_XrSessionNeedsUpsideDownDrawing(runtime_data->context);
119 rcti rect{};
120 rect.xmin = 0;
121 rect.ymin = 0;
122 rect.xmax = draw_view->width - 1;
123 rect.ymax = draw_view->height - 1;
124
125 wmViewport(&rect);
126
127 /* For upside down contexts, draw with inverted y-values. */
128 if (is_upside_down) {
129 std::swap(rect.ymin, rect.ymax);
130 }
131 GPU_viewport_draw_to_screen_ex(vp->viewport, 0, &rect, draw_view->expects_srgb_buffer, true);
132}
133
134void wm_xr_draw_view(const GHOST_XrDrawViewInfo *draw_view, void *customdata)
135{
136 wmXrDrawData *draw_data = static_cast<wmXrDrawData *>(customdata);
137 wmXrData *xr_data = draw_data->xr_data;
138 wmXrSurfaceData *surface_data = draw_data->surface_data;
139 wmXrSessionState *session_state = &xr_data->runtime->session_state;
140 XrSessionSettings *settings = &xr_data->session_settings;
141
142 const int display_flags = V3D_OFSDRAW_OVERRIDE_SCENE_SETTINGS | settings->draw_flags;
143
144 float viewmat[4][4], winmat[4][4];
145
147
148 wm_xr_session_draw_data_update(session_state, settings, draw_view, draw_data);
149 wm_xr_draw_matrices_create(draw_data, draw_view, settings, session_state, viewmat, winmat);
150 wm_xr_session_state_update(settings, draw_data, draw_view, session_state);
151
153 return;
154 }
155
156 const wmXrViewportPair *vp = static_cast<const wmXrViewportPair *>(
157 BLI_findlink(&surface_data->viewports, draw_view->view_idx));
158 BLI_assert(vp && vp->offscreen && vp->viewport);
159
160 /* In case a framebuffer is still bound from drawing the last eye. */
162 /* Some systems have drawing glitches without this. */
163 GPU_clear_depth(1.0f);
164
165 /* Draws the view into the surface_data->viewport's frame-buffers. */
167 draw_data->scene,
168 &settings->shading,
169 (eDrawType)settings->shading.type,
170 settings->object_type_exclude_viewport,
171 settings->object_type_exclude_select,
172 draw_view->width,
173 draw_view->height,
174 display_flags,
175 viewmat,
176 winmat,
177 settings->clip_start,
178 settings->clip_end,
179 true,
180 false,
181 true,
182 nullptr,
183 false,
184 vp->offscreen,
185 vp->viewport);
186
187 /* The draw-manager uses both GPUOffscreen and GPUViewport to manage frame and texture buffers. A
188 * call to GPU_viewport_draw_to_screen() is still needed to get the final result from the
189 * viewport buffers composited together and potentially color managed for display on screen.
190 * It needs a bound frame-buffer to draw into, for which we simply reuse the GPUOffscreen one.
191 *
192 * In a next step, Ghost-XR will use the currently bound frame-buffer to retrieve the image
193 * to be submitted to the OpenXR swap-chain. So do not un-bind the off-screen yet! */
194
195 GPU_offscreen_bind(vp->offscreen, false);
196
198}
199
200bool wm_xr_passthrough_enabled(void *customdata)
201{
202 wmXrDrawData *draw_data = static_cast<wmXrDrawData *>(customdata);
203 wmXrData *xr_data = draw_data->xr_data;
204 XrSessionSettings *settings = &xr_data->session_settings;
205
206 return (settings->draw_flags & V3D_OFSDRAW_XR_SHOW_PASSTHROUGH) != 0;
207}
208
209void wm_xr_disable_passthrough(void *customdata)
210{
211 wmXrDrawData *draw_data = static_cast<wmXrDrawData *>(customdata);
212 wmXrData *xr_data = draw_data->xr_data;
213 XrSessionSettings *settings = &xr_data->session_settings;
214
215 settings->draw_flags &= ~V3D_OFSDRAW_XR_SHOW_PASSTHROUGH;
216 WM_report(RPT_INFO, "Passthrough not available");
217}
218
219static blender::gpu::Batch *wm_xr_controller_model_batch_create(GHOST_XrContextHandle xr_context,
220 const char *subaction_path)
221{
222 GHOST_XrControllerModelData model_data;
223
224 if (!GHOST_XrGetControllerModelData(xr_context, subaction_path, &model_data) ||
225 model_data.count_vertices < 1)
226 {
227 return nullptr;
228 }
229
230 GPUVertFormat format = {0};
233
235 GPU_vertbuf_data_alloc(*vbo, model_data.count_vertices);
236 vbo->data<GHOST_XrControllerModelVertex>().copy_from(
237 {model_data.vertices, model_data.count_vertices});
238
239 blender::gpu::IndexBuf *ibo = nullptr;
240 if (model_data.count_indices > 0 && ((model_data.count_indices % 3) == 0)) {
241 GPUIndexBufBuilder ibo_builder;
242 const uint prim_len = model_data.count_indices / 3;
243 GPU_indexbuf_init(&ibo_builder, GPU_PRIM_TRIS, prim_len, model_data.count_vertices);
244 for (uint i = 0; i < prim_len; ++i) {
245 const uint32_t *idx = &model_data.indices[i * 3];
246 GPU_indexbuf_add_tri_verts(&ibo_builder, idx[0], idx[1], idx[2]);
247 }
248 ibo = GPU_indexbuf_build(&ibo_builder);
249 }
250
252}
253
255 GHOST_XrContextHandle xr_context,
257{
258 GHOST_XrControllerModelData model_data;
259
260 float color[4];
261 switch (settings->controller_draw_style) {
264 color[0] = color[1] = color[2] = 0.0f;
265 color[3] = 0.4f;
266 break;
269 color[0] = 0.422f;
270 color[1] = 0.438f;
271 color[2] = 0.446f;
272 color[3] = 0.4f;
273 break;
274 }
275
278
279 LISTBASE_FOREACH (wmXrController *, controller, &state->controllers) {
280 if (!controller->grip_active) {
281 continue;
282 }
283
284 blender::gpu::Batch *model = controller->model;
285 if (!model) {
286 model = controller->model = wm_xr_controller_model_batch_create(xr_context,
287 controller->subaction_path);
288 }
289
290 if (model &&
291 GHOST_XrGetControllerModelData(xr_context, controller->subaction_path, &model_data) &&
292 model_data.count_components > 0)
293 {
295 GPU_batch_uniform_4fv(model, "color", color);
296
298 GPU_matrix_mul(controller->grip_mat);
299 for (uint component_idx = 0; component_idx < model_data.count_components; ++component_idx) {
300 const GHOST_XrControllerModelComponent *component = &model_data.components[component_idx];
302 GPU_matrix_mul(component->transform);
304 model->elem ? component->index_offset : component->vertex_offset,
305 model->elem ? component->index_count : component->vertex_count);
307 }
309 }
310 else {
311 /* Fallback. */
312 const float scale = 0.05f;
313 blender::gpu::Batch *sphere = GPU_batch_preset_sphere(2);
315 GPU_batch_uniform_4fv(sphere, "color", color);
316
318 GPU_matrix_mul(controller->grip_mat);
319 GPU_matrix_scale_1f(scale);
320 GPU_batch_draw(sphere);
322 }
323 }
324}
325
327{
328 bool draw_ray;
329 switch (settings->controller_draw_style) {
332 draw_ray = false;
333 break;
336 draw_ray = true;
337 break;
338 }
339
344
345 float viewport[4];
346 GPU_viewport_size_get_f(viewport);
347 immUniform2fv("viewportSize", &viewport[2]);
348
349 immUniform1f("lineWidth", 3.0f * U.pixelsize);
350
351 if (draw_ray) {
352 const uchar color[4] = {89, 89, 255, 127};
353 const float scale = settings->clip_end;
354 float ray[3];
355
358
359 LISTBASE_FOREACH (wmXrController *, controller, &state->controllers) {
360 if (!controller->grip_active) {
361 continue;
362 }
363
365
366 const float(*mat)[4] = controller->aim_mat;
367 madd_v3_v3v3fl(ray, mat[3], mat[2], -scale);
368
370 immVertex3fv(pos, mat[3]);
371 immAttr4ubv(col, color);
372 immVertex3fv(pos, ray);
373
374 immEnd();
375 }
376 }
377 else {
378 const uchar r[4] = {255, 51, 82, 255};
379 const uchar g[4] = {139, 220, 0, 255};
380 const uchar b[4] = {40, 144, 255, 255};
381 const float scale = 0.01f;
382 float x_axis[3], y_axis[3], z_axis[3];
383
386
387 LISTBASE_FOREACH (wmXrController *, controller, &state->controllers) {
388 if (!controller->grip_active) {
389 continue;
390 }
391
393
394 const float(*mat)[4] = controller->aim_mat;
395 madd_v3_v3v3fl(x_axis, mat[3], mat[0], scale);
396 madd_v3_v3v3fl(y_axis, mat[3], mat[1], scale);
397 madd_v3_v3v3fl(z_axis, mat[3], mat[2], scale);
398
400 immVertex3fv(pos, mat[3]);
401 immAttr4ubv(col, r);
402 immVertex3fv(pos, x_axis);
403
405 immVertex3fv(pos, mat[3]);
406 immAttr4ubv(col, g);
407 immVertex3fv(pos, y_axis);
408
410 immVertex3fv(pos, mat[3]);
411 immAttr4ubv(col, b);
412 immVertex3fv(pos, z_axis);
413
414 immEnd();
415 }
416 }
417
419}
420
421void wm_xr_draw_controllers(const bContext * /*C*/, ARegion * /*region*/, void *customdata)
422{
423 wmXrData *xr = static_cast<wmXrData *>(customdata);
424 const XrSessionSettings *settings = &xr->session_settings;
425 GHOST_XrContextHandle xr_context = xr->runtime->context;
427
428 wm_xr_controller_model_draw(settings, xr_context, state);
430}
#define BLI_assert(a)
Definition BLI_assert.h:50
#define LISTBASE_FOREACH(type, var, list)
void * BLI_findlink(const struct ListBase *listbase, int number) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
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 char uchar
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, 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.
blender::gpu::Batch * GPU_batch_create_ex(GPUPrimType primitive_type, blender::gpu::VertBuf *vertex_buf, blender::gpu::IndexBuf *index_buf, eGPUBatchFlag owns_flag)
Definition gpu_batch.cc:56
void GPU_batch_program_set_builtin(blender::gpu::Batch *batch, eGPUBuiltinShader shader_id)
void GPU_batch_draw(blender::gpu::Batch *batch)
#define GPU_batch_uniform_4fv(batch, name, val)
Definition GPU_batch.hh:307
void GPU_batch_draw_range(blender::gpu::Batch *batch, int vertex_first, int vertex_count)
@ GPU_BATCH_OWNS_INDEX
Definition GPU_batch.hh:51
@ GPU_BATCH_OWNS_VBO
Definition GPU_batch.hh:42
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 immAttrSkip(uint attr_id)
void immAttr4ubv(uint attr_id, const unsigned char data[4])
void immBindBuiltinProgram(eGPUBuiltinShader shader_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_BLEND_NONE
Definition GPU_state.hh:85
@ GPU_BLEND_ALPHA
Definition GPU_state.hh:87
void GPU_blend(eGPUBlend blend)
Definition gpu_state.cc:42
@ GPU_DEPTH_LESS_EQUAL
Definition GPU_state.hh:111
@ GPU_DEPTH_NONE
Definition GPU_state.hh:108
void GPU_depth_test(eGPUDepthTest test)
Definition gpu_state.cc:68
void GPU_viewport_size_get_f(float coords[4])
Definition gpu_state.cc:262
#define GPU_vertbuf_create_with_format(format)
void GPU_vertbuf_data_alloc(blender::gpu::VertBuf &verts, uint v_len)
@ GPU_FETCH_FLOAT
@ GPU_FETCH_INT_TO_FLOAT_UNIT
uint GPU_vertformat_attr_add(GPUVertFormat *, const char *name, GPUVertCompType, uint comp_len, GPUVertFetchMode)
@ GPU_COMP_F32
@ GPU_COMP_U8
void GPU_viewport_draw_to_screen_ex(GPUViewport *viewport, int view, const rcti *rect, bool display_colorspace, bool do_overlay_merge)
unsigned int U
Definition btGjkEpa3.h:78
MutableSpan< T > data()
local_group_size(16, 16) .push_constant(Type b
direct_radiance_1_tx direct_radiance_3_tx indirect_radiance_2_tx radiance_feedback_img draw_fullscreen fragment_source("eevee_deferred_combine_frag.glsl") .specialization_constant(Type out_radiance draw_view
draw_view in_light_buf[] float
uint col
format
static ulong state[N]
unsigned int uint32_t
Definition stdint.h:80
int xmin
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 GPUViewport * viewport
struct GPUOffScreen * offscreen
void WM_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:33
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:39
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:72
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:57
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:49
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)