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
12
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,
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
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]);
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)
Group Output data from inside of a node group A color picker Mix two input colors RGB to Convert a color s luminance to a grayscale value Generate a normal vector and a dot product Brightness Control the brightness and contrast of the input color Vector Map input vector components with curves Camera Retrieve information about the camera and how it relates to the current shading point s position Clamp a value between a minimum and a maximum Vector Perform vector math operation Invert Invert a color
#define U
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 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 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)