2023-08-16 00:20:26 +10:00
|
|
|
/* SPDX-FileCopyrightText: 2008 Blender Authors
|
2023-05-31 16:19:06 +02:00
|
|
|
*
|
|
|
|
|
* SPDX-License-Identifier: GPL-2.0-or-later */
|
2018-01-28 14:44:42 +11:00
|
|
|
|
2019-02-18 08:08:12 +11:00
|
|
|
/** \file
|
|
|
|
|
* \ingroup spview3d
|
2018-01-28 14:44:42 +11:00
|
|
|
*
|
|
|
|
|
* 3D View checks and manipulation (no operators).
|
|
|
|
|
*/
|
|
|
|
|
|
2025-01-26 20:08:00 +01:00
|
|
|
#include <algorithm>
|
2023-07-22 11:27:25 +10:00
|
|
|
#include <cfloat>
|
|
|
|
|
#include <cmath>
|
|
|
|
|
#include <cstdio>
|
|
|
|
|
#include <cstring>
|
2018-01-28 14:44:42 +11:00
|
|
|
|
|
|
|
|
#include "DNA_camera_types.h"
|
|
|
|
|
#include "DNA_curve_types.h"
|
|
|
|
|
#include "DNA_object_types.h"
|
|
|
|
|
#include "DNA_scene_types.h"
|
2018-11-15 00:05:54 +11:00
|
|
|
#include "DNA_world_types.h"
|
2018-01-28 14:44:42 +11:00
|
|
|
|
2024-12-17 13:36:49 +01:00
|
|
|
#include "RNA_path.hh"
|
|
|
|
|
|
2018-01-28 14:44:42 +11:00
|
|
|
#include "MEM_guardedalloc.h"
|
|
|
|
|
|
2021-04-05 10:48:28 -03:00
|
|
|
#include "BLI_array_utils.h"
|
2018-01-28 14:44:42 +11:00
|
|
|
#include "BLI_bitmap_draw_2d.h"
|
2025-02-11 16:59:42 +01:00
|
|
|
#include "BLI_listbase.h"
|
Cleanup: reduce amount of math-related includes
Using ClangBuildAnalyzer on the whole Blender build, it was pointing
out that BLI_math.h is the heaviest "header hub" (i.e. non tiny file
that is included a lot).
However, there's very little (actually zero) source files in Blender
that need "all the math" (base, colors, vectors, matrices,
quaternions, intersection, interpolation, statistics, solvers and
time). A common use case is source files needing just vectors, or
just vectors & matrices, or just colors etc. Actually, 181 files
were including the whole math thing without needing it at all.
This change removes BLI_math.h completely, and instead in all the
places that need it, includes BLI_math_vector.h or BLI_math_color.h
and so on.
Change from that:
- BLI_math_color.h was included 1399 times -> now 408 (took 114.0sec
to parse -> now 36.3sec)
- BLI_simd.h 1403 -> 418 (109.7sec -> 34.9sec).
Full rebuild of Blender (Apple M1, Xcode, RelWithDebInfo) is not
affected much (342sec -> 334sec). Most of benefit would be when
someone's changing BLI_simd.h or BLI_math_color.h or similar files,
that now there's 3x fewer files result in a recompile.
Pull Request #110944
2023-08-09 11:39:20 +03:00
|
|
|
#include "BLI_math_geom.h"
|
|
|
|
|
#include "BLI_math_matrix.h"
|
|
|
|
|
#include "BLI_math_rotation.h"
|
|
|
|
|
#include "BLI_math_vector.h"
|
2025-01-28 15:27:34 +01:00
|
|
|
#include "BLI_rect.h"
|
2018-01-28 14:44:42 +11:00
|
|
|
#include "BLI_utildefines.h"
|
2024-12-17 13:36:49 +01:00
|
|
|
#include "BLI_vector.hh"
|
2018-01-28 14:44:42 +11:00
|
|
|
|
|
|
|
|
#include "BKE_camera.h"
|
2023-11-16 11:41:55 +01:00
|
|
|
#include "BKE_context.hh"
|
2025-02-07 17:47:16 +01:00
|
|
|
#include "BKE_library.hh"
|
2023-10-09 23:41:53 +02:00
|
|
|
#include "BKE_object.hh"
|
2024-02-10 19:16:25 +01:00
|
|
|
#include "BKE_scene.hh"
|
2023-09-25 17:48:21 -04:00
|
|
|
#include "BKE_screen.hh"
|
2018-01-28 15:20:19 +11:00
|
|
|
|
2023-09-22 03:18:17 +02:00
|
|
|
#include "DEG_depsgraph.hh"
|
|
|
|
|
#include "DEG_depsgraph_query.hh"
|
2018-01-28 14:44:42 +11:00
|
|
|
|
2024-03-23 01:24:18 +01:00
|
|
|
#include "GPU_matrix.hh"
|
2018-01-28 16:40:23 +11:00
|
|
|
|
2023-08-04 23:11:22 +02:00
|
|
|
#include "WM_api.hh"
|
|
|
|
|
#include "WM_types.hh"
|
2018-01-28 14:44:42 +11:00
|
|
|
|
2023-08-05 02:57:52 +02:00
|
|
|
#include "ED_keyframing.hh"
|
2023-08-04 23:11:22 +02:00
|
|
|
#include "ED_screen.hh"
|
2023-08-05 02:57:52 +02:00
|
|
|
#include "ED_undo.hh"
|
|
|
|
|
#include "ED_view3d.hh"
|
2018-01-28 14:44:42 +11:00
|
|
|
|
2023-10-12 15:44:58 +02:00
|
|
|
#include "ANIM_keyframing.hh"
|
2024-05-02 12:00:37 +02:00
|
|
|
#include "ANIM_keyingsets.hh"
|
2023-10-12 15:44:58 +02:00
|
|
|
|
2023-08-05 02:57:52 +02:00
|
|
|
#include "UI_resources.hh"
|
2018-11-15 00:05:54 +11:00
|
|
|
|
2024-03-26 20:34:48 -04:00
|
|
|
#include "view3d_intern.hh" /* own include */
|
2018-01-28 14:44:42 +11:00
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name View Data Access Utilities
|
|
|
|
|
* \{ */
|
|
|
|
|
|
2018-11-15 00:05:54 +11:00
|
|
|
void ED_view3d_background_color_get(const Scene *scene, const View3D *v3d, float r_color[3])
|
|
|
|
|
{
|
2018-12-18 13:56:26 +11:00
|
|
|
if (v3d->shading.background_type == V3D_SHADING_BACKGROUND_WORLD) {
|
|
|
|
|
if (scene->world) {
|
2018-11-15 00:05:54 +11:00
|
|
|
copy_v3_v3(r_color, &scene->world->horr);
|
2018-12-18 13:56:26 +11:00
|
|
|
return;
|
|
|
|
|
}
|
2018-11-15 00:05:54 +11:00
|
|
|
}
|
2018-12-18 13:56:26 +11:00
|
|
|
else if (v3d->shading.background_type == V3D_SHADING_BACKGROUND_VIEWPORT) {
|
|
|
|
|
copy_v3_v3(r_color, v3d->shading.background_color);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-01-11 12:59:19 +11:00
|
|
|
UI_GetThemeColor3fv(TH_BACK, r_color);
|
2018-11-15 00:05:54 +11:00
|
|
|
}
|
|
|
|
|
|
UI: Improved overlay text contrast with new outline text decoration
Overlay texts were previously drawn with two sets of shadows:
- 3px blur,
- 5px blur, slightly offset
But since the shadow color was always set to black, it was still
causing legibility issues when the text itself was dark (set
via theme for example).
This PR adds a new "outline" BLF text decoration, and uses that
for the overlays. And it picks text/outline color depending
on the "background" color of the view.
Details:
- Instead of "shadow level" integer where the only valid options
are 0, 3 or 5, have a FontShadowType enum.
- Add a new FontShadowType::Outline enum entry, that does a 1px
outline by doing a 3x3 dilation in the font shader.
- BLF_draw_default_shadowed is changed to do outline, instead of
drawing the shadow twice.
- In the font shader, instead of encoding shadow type in signs of
the glyph_size, pass that as a "flags" vertex attribute. Put
font texture channel count into the same flags, so that the
vertex size stays the same.
- Well actually, vertex size becomes smaller by 4 bytes, since turns
out glyph_mode vertex attribute was not used for anything at all.
Images in the PR.
Co-authored-by: Harley Acheson <harley.acheson@gmail.com>
Pull Request: https://projects.blender.org/blender/blender/pulls/121383
2024-05-10 21:06:44 +02:00
|
|
|
void ED_view3d_text_colors_get(const Scene *scene,
|
|
|
|
|
const View3D *v3d,
|
|
|
|
|
float r_text_color[4],
|
|
|
|
|
float r_shadow_color[4])
|
|
|
|
|
{
|
|
|
|
|
/* Text fully opaque, shadow slightly transparent. */
|
|
|
|
|
r_text_color[3] = 1.0f;
|
|
|
|
|
r_shadow_color[3] = 0.8f;
|
|
|
|
|
|
2024-09-12 04:24:53 +02:00
|
|
|
/* Default text color from TH_TEXT_HI. If it is too close
|
|
|
|
|
* to the background color, darken or lighten it. */
|
|
|
|
|
UI_GetThemeColor3fv(TH_TEXT_HI, r_text_color);
|
2025-01-21 09:21:36 +01:00
|
|
|
float text_lightness = srgb_to_grayscale(r_text_color);
|
2024-05-29 20:10:45 +02:00
|
|
|
float bg_color[3];
|
UI: Improved overlay text contrast with new outline text decoration
Overlay texts were previously drawn with two sets of shadows:
- 3px blur,
- 5px blur, slightly offset
But since the shadow color was always set to black, it was still
causing legibility issues when the text itself was dark (set
via theme for example).
This PR adds a new "outline" BLF text decoration, and uses that
for the overlays. And it picks text/outline color depending
on the "background" color of the view.
Details:
- Instead of "shadow level" integer where the only valid options
are 0, 3 or 5, have a FontShadowType enum.
- Add a new FontShadowType::Outline enum entry, that does a 1px
outline by doing a 3x3 dilation in the font shader.
- BLF_draw_default_shadowed is changed to do outline, instead of
drawing the shadow twice.
- In the font shader, instead of encoding shadow type in signs of
the glyph_size, pass that as a "flags" vertex attribute. Put
font texture channel count into the same flags, so that the
vertex size stays the same.
- Well actually, vertex size becomes smaller by 4 bytes, since turns
out glyph_mode vertex attribute was not used for anything at all.
Images in the PR.
Co-authored-by: Harley Acheson <harley.acheson@gmail.com>
Pull Request: https://projects.blender.org/blender/blender/pulls/121383
2024-05-10 21:06:44 +02:00
|
|
|
ED_view3d_background_color_get(scene, v3d, bg_color);
|
2024-09-12 04:24:53 +02:00
|
|
|
const float distance = len_v3v3(r_text_color, bg_color);
|
|
|
|
|
if (distance < 0.5f) {
|
|
|
|
|
if (text_lightness > 0.5f) {
|
|
|
|
|
mul_v3_fl(r_text_color, 0.33f);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
mul_v3_fl(r_text_color, 3.0f);
|
|
|
|
|
}
|
|
|
|
|
clamp_v3(r_text_color, 0.0f, 1.0f);
|
UI: Improved overlay text contrast with new outline text decoration
Overlay texts were previously drawn with two sets of shadows:
- 3px blur,
- 5px blur, slightly offset
But since the shadow color was always set to black, it was still
causing legibility issues when the text itself was dark (set
via theme for example).
This PR adds a new "outline" BLF text decoration, and uses that
for the overlays. And it picks text/outline color depending
on the "background" color of the view.
Details:
- Instead of "shadow level" integer where the only valid options
are 0, 3 or 5, have a FontShadowType enum.
- Add a new FontShadowType::Outline enum entry, that does a 1px
outline by doing a 3x3 dilation in the font shader.
- BLF_draw_default_shadowed is changed to do outline, instead of
drawing the shadow twice.
- In the font shader, instead of encoding shadow type in signs of
the glyph_size, pass that as a "flags" vertex attribute. Put
font texture channel count into the same flags, so that the
vertex size stays the same.
- Well actually, vertex size becomes smaller by 4 bytes, since turns
out glyph_mode vertex attribute was not used for anything at all.
Images in the PR.
Co-authored-by: Harley Acheson <harley.acheson@gmail.com>
Pull Request: https://projects.blender.org/blender/blender/pulls/121383
2024-05-10 21:06:44 +02:00
|
|
|
}
|
2024-09-12 04:24:53 +02:00
|
|
|
|
|
|
|
|
/* Shadow color is black or white depending on final text lightness. */
|
2025-01-21 09:21:36 +01:00
|
|
|
text_lightness = srgb_to_grayscale(r_text_color);
|
2024-09-12 04:24:53 +02:00
|
|
|
if (text_lightness > 0.4f) {
|
2024-05-29 20:10:45 +02:00
|
|
|
copy_v3_fl(r_shadow_color, 0.0f);
|
UI: Improved overlay text contrast with new outline text decoration
Overlay texts were previously drawn with two sets of shadows:
- 3px blur,
- 5px blur, slightly offset
But since the shadow color was always set to black, it was still
causing legibility issues when the text itself was dark (set
via theme for example).
This PR adds a new "outline" BLF text decoration, and uses that
for the overlays. And it picks text/outline color depending
on the "background" color of the view.
Details:
- Instead of "shadow level" integer where the only valid options
are 0, 3 or 5, have a FontShadowType enum.
- Add a new FontShadowType::Outline enum entry, that does a 1px
outline by doing a 3x3 dilation in the font shader.
- BLF_draw_default_shadowed is changed to do outline, instead of
drawing the shadow twice.
- In the font shader, instead of encoding shadow type in signs of
the glyph_size, pass that as a "flags" vertex attribute. Put
font texture channel count into the same flags, so that the
vertex size stays the same.
- Well actually, vertex size becomes smaller by 4 bytes, since turns
out glyph_mode vertex attribute was not used for anything at all.
Images in the PR.
Co-authored-by: Harley Acheson <harley.acheson@gmail.com>
Pull Request: https://projects.blender.org/blender/blender/pulls/121383
2024-05-10 21:06:44 +02:00
|
|
|
}
|
2024-09-12 04:24:53 +02:00
|
|
|
else {
|
|
|
|
|
copy_v3_fl(r_shadow_color, 1.0f);
|
|
|
|
|
}
|
UI: Improved overlay text contrast with new outline text decoration
Overlay texts were previously drawn with two sets of shadows:
- 3px blur,
- 5px blur, slightly offset
But since the shadow color was always set to black, it was still
causing legibility issues when the text itself was dark (set
via theme for example).
This PR adds a new "outline" BLF text decoration, and uses that
for the overlays. And it picks text/outline color depending
on the "background" color of the view.
Details:
- Instead of "shadow level" integer where the only valid options
are 0, 3 or 5, have a FontShadowType enum.
- Add a new FontShadowType::Outline enum entry, that does a 1px
outline by doing a 3x3 dilation in the font shader.
- BLF_draw_default_shadowed is changed to do outline, instead of
drawing the shadow twice.
- In the font shader, instead of encoding shadow type in signs of
the glyph_size, pass that as a "flags" vertex attribute. Put
font texture channel count into the same flags, so that the
vertex size stays the same.
- Well actually, vertex size becomes smaller by 4 bytes, since turns
out glyph_mode vertex attribute was not used for anything at all.
Images in the PR.
Co-authored-by: Harley Acheson <harley.acheson@gmail.com>
Pull Request: https://projects.blender.org/blender/blender/pulls/121383
2024-05-10 21:06:44 +02:00
|
|
|
}
|
|
|
|
|
|
2020-05-25 10:43:44 +02:00
|
|
|
bool ED_view3d_has_workbench_in_texture_color(const Scene *scene,
|
|
|
|
|
const Object *ob,
|
|
|
|
|
const View3D *v3d)
|
|
|
|
|
{
|
|
|
|
|
if (v3d->shading.type == OB_SOLID) {
|
|
|
|
|
if (v3d->shading.color_type == V3D_SHADING_TEXTURE_COLOR) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2020-06-30 16:58:19 +02:00
|
|
|
if (ob && ob->mode == OB_MODE_TEXTURE_PAINT) {
|
2020-05-25 10:43:44 +02:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (v3d->shading.type == OB_RENDER) {
|
2023-01-23 17:59:07 +01:00
|
|
|
if (BKE_scene_uses_blender_workbench(scene)) {
|
2020-05-25 10:43:44 +02:00
|
|
|
return scene->display.shading.color_type == V3D_SHADING_TEXTURE_COLOR;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2018-01-28 14:44:42 +11:00
|
|
|
Camera *ED_view3d_camera_data_get(View3D *v3d, RegionView3D *rv3d)
|
|
|
|
|
{
|
2019-01-15 23:24:20 +11:00
|
|
|
/* establish the camera object,
|
|
|
|
|
* so we can default to view mapping if anything is wrong with it */
|
2018-01-28 14:44:42 +11:00
|
|
|
if ((rv3d->persp == RV3D_CAMOB) && v3d->camera && (v3d->camera->type == OB_CAMERA)) {
|
2023-07-12 18:02:56 +02:00
|
|
|
return static_cast<Camera *>(v3d->camera->data);
|
2018-01-28 14:44:42 +11:00
|
|
|
}
|
2023-07-12 18:02:56 +02:00
|
|
|
return nullptr;
|
2018-01-28 14:44:42 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ED_view3d_dist_range_get(const View3D *v3d, float r_dist_range[2])
|
|
|
|
|
{
|
|
|
|
|
r_dist_range[0] = v3d->grid * 0.001f;
|
2019-02-16 12:21:44 +11:00
|
|
|
r_dist_range[1] = v3d->clip_end * 10.0f;
|
2018-01-28 14:44:42 +11:00
|
|
|
}
|
|
|
|
|
|
2022-05-13 19:13:31 +02:00
|
|
|
bool ED_view3d_clip_range_get(const Depsgraph *depsgraph,
|
2018-01-28 14:44:42 +11:00
|
|
|
const View3D *v3d,
|
|
|
|
|
const RegionView3D *rv3d,
|
2024-05-06 09:20:06 +10:00
|
|
|
const bool use_ortho_factor,
|
2024-05-06 09:20:05 +10:00
|
|
|
float *r_clip_start,
|
2024-05-06 09:20:06 +10:00
|
|
|
float *r_clip_end)
|
2018-01-28 14:44:42 +11:00
|
|
|
{
|
|
|
|
|
CameraParams params;
|
|
|
|
|
|
|
|
|
|
BKE_camera_params_init(¶ms);
|
2018-01-28 15:20:19 +11:00
|
|
|
BKE_camera_params_from_view3d(¶ms, depsgraph, v3d, rv3d);
|
2018-01-28 14:44:42 +11:00
|
|
|
|
|
|
|
|
if (use_ortho_factor && params.is_ortho) {
|
2019-02-16 12:21:44 +11:00
|
|
|
const float fac = 2.0f / (params.clip_end - params.clip_start);
|
|
|
|
|
params.clip_start *= fac;
|
|
|
|
|
params.clip_end *= fac;
|
2018-01-28 14:44:42 +11:00
|
|
|
}
|
|
|
|
|
|
2024-05-06 09:20:05 +10:00
|
|
|
if (r_clip_start) {
|
|
|
|
|
*r_clip_start = params.clip_start;
|
2019-03-26 21:16:47 +11:00
|
|
|
}
|
2024-05-06 09:20:05 +10:00
|
|
|
if (r_clip_end) {
|
|
|
|
|
*r_clip_end = params.clip_end;
|
2019-03-26 21:16:47 +11:00
|
|
|
}
|
2018-01-28 14:44:42 +11:00
|
|
|
|
|
|
|
|
return params.is_ortho;
|
|
|
|
|
}
|
|
|
|
|
|
2024-09-10 17:31:02 +10:00
|
|
|
bool ED_view3d_viewplane_get(const Depsgraph *depsgraph,
|
2018-01-28 14:44:42 +11:00
|
|
|
const View3D *v3d,
|
|
|
|
|
const RegionView3D *rv3d,
|
|
|
|
|
int winx,
|
|
|
|
|
int winy,
|
2019-02-16 12:21:44 +11:00
|
|
|
rctf *r_viewplane,
|
|
|
|
|
float *r_clip_start,
|
|
|
|
|
float *r_clip_end,
|
|
|
|
|
float *r_pixsize)
|
2018-01-28 14:44:42 +11:00
|
|
|
{
|
|
|
|
|
CameraParams params;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-01-28 14:44:42 +11:00
|
|
|
BKE_camera_params_init(¶ms);
|
2018-01-28 15:20:19 +11:00
|
|
|
BKE_camera_params_from_view3d(¶ms, depsgraph, v3d, rv3d);
|
2018-01-28 14:44:42 +11:00
|
|
|
BKE_camera_params_compute_viewplane(¶ms, winx, winy, 1.0f, 1.0f);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-03-26 21:16:47 +11:00
|
|
|
if (r_viewplane) {
|
|
|
|
|
*r_viewplane = params.viewplane;
|
|
|
|
|
}
|
|
|
|
|
if (r_clip_start) {
|
|
|
|
|
*r_clip_start = params.clip_start;
|
|
|
|
|
}
|
|
|
|
|
if (r_clip_end) {
|
|
|
|
|
*r_clip_end = params.clip_end;
|
|
|
|
|
}
|
|
|
|
|
if (r_pixsize) {
|
|
|
|
|
*r_pixsize = params.viewdx;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-01-28 14:44:42 +11:00
|
|
|
return params.is_ortho;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** \} */
|
|
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name View State/Context Utilities
|
|
|
|
|
* \{ */
|
|
|
|
|
|
2025-02-04 21:17:14 +11:00
|
|
|
void view3d_operator_needs_gpu(const bContext *C)
|
2018-01-28 16:22:34 +11:00
|
|
|
{
|
2020-03-06 16:56:42 +01:00
|
|
|
ARegion *region = CTX_wm_region(C);
|
2018-01-28 16:22:34 +11:00
|
|
|
|
2025-02-04 21:17:14 +11:00
|
|
|
view3d_region_operator_needs_gpu(region);
|
2018-01-28 16:22:34 +11:00
|
|
|
}
|
|
|
|
|
|
2025-02-04 21:17:14 +11:00
|
|
|
void view3d_region_operator_needs_gpu(ARegion *region)
|
2018-01-28 16:22:34 +11:00
|
|
|
{
|
|
|
|
|
/* for debugging purpose, context should always be OK */
|
2023-07-12 18:02:56 +02:00
|
|
|
if ((region == nullptr) || (region->regiontype != RGN_TYPE_WINDOW)) {
|
2025-02-04 21:17:14 +11:00
|
|
|
printf("view3d_region_operator_needs_gpu error, wrong region\n");
|
2018-01-28 16:22:34 +11:00
|
|
|
}
|
|
|
|
|
else {
|
2023-07-12 18:02:56 +02:00
|
|
|
RegionView3D *rv3d = static_cast<RegionView3D *>(region->regiondata);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-03-06 16:56:42 +01:00
|
|
|
wmViewport(®ion->winrct); /* TODO: bad */
|
2018-07-15 15:27:15 +02:00
|
|
|
GPU_matrix_projection_set(rv3d->winmat);
|
|
|
|
|
GPU_matrix_set(rv3d->viewmat);
|
2018-01-28 16:22:34 +11:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-01-28 14:44:42 +11:00
|
|
|
void ED_view3d_polygon_offset(const RegionView3D *rv3d, const float dist)
|
|
|
|
|
{
|
|
|
|
|
if (rv3d->rflag & RV3D_ZOFFSET_DISABLED) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2021-01-25 17:22:52 -06:00
|
|
|
float viewdist = rv3d->dist;
|
2018-01-28 14:44:42 +11:00
|
|
|
|
2021-03-18 09:35:12 +11:00
|
|
|
/* Special exception for orthographic camera (`viewdist` isn't used for perspective cameras). */
|
2018-01-28 14:44:42 +11:00
|
|
|
if (dist != 0.0f) {
|
|
|
|
|
if (rv3d->persp == RV3D_CAMOB) {
|
|
|
|
|
if (rv3d->is_persp == false) {
|
|
|
|
|
viewdist = 1.0f / max_ff(fabsf(rv3d->winmat[0][0]), fabsf(rv3d->winmat[1][1]));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-07-16 20:24:05 +02:00
|
|
|
GPU_polygon_offset(viewdist, dist);
|
2018-01-28 14:44:42 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool ED_view3d_context_activate(bContext *C)
|
|
|
|
|
{
|
2020-04-03 14:23:21 +02:00
|
|
|
bScreen *screen = CTX_wm_screen(C);
|
2020-04-03 13:25:03 +02:00
|
|
|
ScrArea *area = CTX_wm_area(C);
|
2018-01-28 14:44:42 +11:00
|
|
|
|
2023-07-12 18:02:56 +02:00
|
|
|
/* area can be nullptr when called from python */
|
|
|
|
|
if (area == nullptr || area->spacetype != SPACE_VIEW3D) {
|
2020-04-03 14:23:21 +02:00
|
|
|
area = BKE_screen_find_big_area(screen, SPACE_VIEW3D, 0);
|
2018-01-28 14:44:42 +11:00
|
|
|
}
|
|
|
|
|
|
2023-07-12 18:02:56 +02:00
|
|
|
if (area == nullptr) {
|
2018-01-28 14:44:42 +11:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2021-01-25 17:22:52 -06:00
|
|
|
ARegion *region = BKE_area_find_region_active_win(area);
|
2023-07-12 18:02:56 +02:00
|
|
|
if (region == nullptr) {
|
2018-01-28 14:44:42 +11:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-24 15:56:58 +10:00
|
|
|
/* Bad context switch. */
|
2020-04-03 13:25:03 +02:00
|
|
|
CTX_wm_area_set(C, area);
|
2020-03-06 16:56:42 +01:00
|
|
|
CTX_wm_region_set(C, region);
|
2018-01-28 14:44:42 +11:00
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** \} */
|
|
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name View Clipping Utilities
|
|
|
|
|
* \{ */
|
2018-01-28 15:20:19 +11:00
|
|
|
|
2018-01-28 14:44:42 +11:00
|
|
|
void ED_view3d_clipping_calc_from_boundbox(float clip[4][4],
|
|
|
|
|
const BoundBox *bb,
|
|
|
|
|
const bool is_flip)
|
|
|
|
|
{
|
2021-01-25 17:22:52 -06:00
|
|
|
for (int val = 0; val < 4; val++) {
|
2018-01-28 14:44:42 +11:00
|
|
|
normal_tri_v3(clip[val], bb->vec[val], bb->vec[val == 3 ? 0 : val + 1], bb->vec[val + 4]);
|
|
|
|
|
if (UNLIKELY(is_flip)) {
|
|
|
|
|
negate_v3(clip[val]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
clip[val][3] = -dot_v3v3(clip[val], bb->vec[val]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-01-28 15:20:19 +11:00
|
|
|
void ED_view3d_clipping_calc(
|
2020-03-06 16:56:42 +01:00
|
|
|
BoundBox *bb, float planes[4][4], const ARegion *region, const Object *ob, const rcti *rect)
|
2018-01-28 14:44:42 +11:00
|
|
|
{
|
2018-01-28 15:20:19 +11:00
|
|
|
/* init in case unproject fails */
|
|
|
|
|
memset(bb->vec, 0, sizeof(bb->vec));
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-01-28 14:44:42 +11:00
|
|
|
/* four clipping planes and bounding volume */
|
|
|
|
|
/* first do the bounding volume */
|
2018-01-28 15:20:19 +11:00
|
|
|
for (int val = 0; val < 4; val++) {
|
2022-10-07 22:52:53 +11:00
|
|
|
float xs = ELEM(val, 0, 3) ? rect->xmin : rect->xmax;
|
|
|
|
|
float ys = ELEM(val, 0, 1) ? rect->ymin : rect->ymax;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2021-06-01 12:49:20 +10:00
|
|
|
ED_view3d_unproject_v3(region, xs, ys, 0.0, bb->vec[val]);
|
|
|
|
|
ED_view3d_unproject_v3(region, xs, ys, 1.0, bb->vec[4 + val]);
|
2018-01-28 15:20:19 +11:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-01-28 15:20:19 +11:00
|
|
|
/* optionally transform to object space */
|
|
|
|
|
if (ob) {
|
|
|
|
|
float imat[4][4];
|
2024-02-14 16:14:49 +01:00
|
|
|
invert_m4_m4(imat, ob->object_to_world().ptr());
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-01-28 15:20:19 +11:00
|
|
|
for (int val = 0; val < 8; val++) {
|
|
|
|
|
mul_m4_v3(imat, bb->vec[val]);
|
|
|
|
|
}
|
2018-01-28 14:44:42 +11:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-01-28 14:44:42 +11:00
|
|
|
/* verify if we have negative scale. doing the transform before cross
|
|
|
|
|
* product flips the sign of the vector compared to doing cross product
|
|
|
|
|
* before transform then, so we correct for that. */
|
2024-02-14 16:14:49 +01:00
|
|
|
int flip_sign = (ob) ? is_negative_m4(ob->object_to_world().ptr()) : false;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-01-28 14:44:42 +11:00
|
|
|
ED_view3d_clipping_calc_from_boundbox(planes, bb, flip_sign);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** \} */
|
|
|
|
|
|
2020-11-07 20:16:32 +11:00
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name View Clipping Clamp Min/Max
|
|
|
|
|
* \{ */
|
|
|
|
|
|
|
|
|
|
struct PointsInPlanesMinMax_UserData {
|
|
|
|
|
float min[3];
|
|
|
|
|
float max[3];
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static void points_in_planes_minmax_fn(
|
2023-07-12 18:02:56 +02:00
|
|
|
const float co[3], int /*i*/, int /*j*/, int /*k*/, void *user_data_p)
|
2020-11-07 20:16:32 +11:00
|
|
|
{
|
2023-07-20 11:30:25 +10:00
|
|
|
PointsInPlanesMinMax_UserData *user_data = static_cast<PointsInPlanesMinMax_UserData *>(
|
2023-07-12 18:02:56 +02:00
|
|
|
user_data_p);
|
2020-11-07 20:16:32 +11:00
|
|
|
minmax_v3v3_v3(user_data->min, user_data->max, co);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool ED_view3d_clipping_clamp_minmax(const RegionView3D *rv3d, float min[3], float max[3])
|
|
|
|
|
{
|
|
|
|
|
/* 6 planes for the cube, 4..6 for the current view clipping planes. */
|
|
|
|
|
float planes[6 + 6][4];
|
|
|
|
|
|
|
|
|
|
/* Convert the min/max to 6 planes. */
|
|
|
|
|
for (int i = 0; i < 3; i++) {
|
|
|
|
|
float *plane_min = planes[(i * 2) + 0];
|
|
|
|
|
float *plane_max = planes[(i * 2) + 1];
|
|
|
|
|
zero_v3(plane_min);
|
|
|
|
|
zero_v3(plane_max);
|
|
|
|
|
plane_min[i] = -1.0f;
|
|
|
|
|
plane_min[3] = +min[i];
|
|
|
|
|
plane_max[i] = +1.0f;
|
|
|
|
|
plane_max[3] = -max[i];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Copy planes from the viewport & flip. */
|
|
|
|
|
int planes_len = 6;
|
|
|
|
|
int clip_len = (RV3D_LOCK_FLAGS(rv3d) & RV3D_BOXCLIP) ? 4 : 6;
|
|
|
|
|
for (int i = 0; i < clip_len; i++) {
|
|
|
|
|
negate_v4_v4(planes[planes_len], rv3d->clip[i]);
|
|
|
|
|
planes_len += 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Calculate points intersecting all planes (effectively intersecting two bounding boxes). */
|
2023-07-20 11:30:25 +10:00
|
|
|
PointsInPlanesMinMax_UserData user_data;
|
2020-11-07 20:16:32 +11:00
|
|
|
INIT_MINMAX(user_data.min, user_data.max);
|
|
|
|
|
|
|
|
|
|
const float eps_coplanar = 1e-4f;
|
|
|
|
|
const float eps_isect = 1e-6f;
|
|
|
|
|
if (isect_planes_v3_fn(
|
|
|
|
|
planes, planes_len, eps_coplanar, eps_isect, points_in_planes_minmax_fn, &user_data))
|
|
|
|
|
{
|
|
|
|
|
copy_v3_v3(min, user_data.min);
|
|
|
|
|
copy_v3_v3(max, user_data.max);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** \} */
|
|
|
|
|
|
2018-01-28 14:44:42 +11:00
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name View Bound-Box Utilities
|
|
|
|
|
* \{ */
|
|
|
|
|
|
2020-08-02 17:17:31 +10:00
|
|
|
static bool view3d_boundbox_clip_m4(const BoundBox *bb, const float persmatob[4][4])
|
2018-01-28 14:44:42 +11:00
|
|
|
{
|
|
|
|
|
int a, flag = -1, fl;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-01-28 14:44:42 +11:00
|
|
|
for (a = 0; a < 8; a++) {
|
|
|
|
|
float vec[4], min, max;
|
|
|
|
|
copy_v3_v3(vec, bb->vec[a]);
|
|
|
|
|
vec[3] = 1.0;
|
|
|
|
|
mul_m4_v4(persmatob, vec);
|
|
|
|
|
max = vec[3];
|
|
|
|
|
min = -vec[3];
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-01-28 14:44:42 +11:00
|
|
|
fl = 0;
|
2019-03-26 21:16:47 +11:00
|
|
|
if (vec[0] < min) {
|
|
|
|
|
fl += 1;
|
|
|
|
|
}
|
|
|
|
|
if (vec[0] > max) {
|
|
|
|
|
fl += 2;
|
|
|
|
|
}
|
|
|
|
|
if (vec[1] < min) {
|
|
|
|
|
fl += 4;
|
|
|
|
|
}
|
|
|
|
|
if (vec[1] > max) {
|
|
|
|
|
fl += 8;
|
|
|
|
|
}
|
|
|
|
|
if (vec[2] < min) {
|
|
|
|
|
fl += 16;
|
|
|
|
|
}
|
|
|
|
|
if (vec[2] > max) {
|
|
|
|
|
fl += 32;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-01-28 14:44:42 +11:00
|
|
|
flag &= fl;
|
2019-03-26 21:16:47 +11:00
|
|
|
if (flag == 0) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2018-01-28 14:44:42 +11:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-01-28 14:44:42 +11:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool ED_view3d_boundbox_clip_ex(const RegionView3D *rv3d, const BoundBox *bb, float obmat[4][4])
|
|
|
|
|
{
|
|
|
|
|
/* return 1: draw */
|
|
|
|
|
|
|
|
|
|
float persmatob[4][4];
|
|
|
|
|
|
2023-07-12 18:02:56 +02:00
|
|
|
if (bb == nullptr) {
|
2019-03-26 21:16:47 +11:00
|
|
|
return true;
|
|
|
|
|
}
|
2018-01-28 14:44:42 +11:00
|
|
|
|
|
|
|
|
mul_m4_m4m4(persmatob, (float(*)[4])rv3d->persmat, obmat);
|
|
|
|
|
|
|
|
|
|
return view3d_boundbox_clip_m4(bb, persmatob);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool ED_view3d_boundbox_clip(RegionView3D *rv3d, const BoundBox *bb)
|
|
|
|
|
{
|
2023-07-12 18:02:56 +02:00
|
|
|
if (bb == nullptr) {
|
2019-03-26 21:16:47 +11:00
|
|
|
return true;
|
|
|
|
|
}
|
2018-01-28 14:44:42 +11:00
|
|
|
return view3d_boundbox_clip_m4(bb, rv3d->persmatob);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** \} */
|
|
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name View Perspective & Mode Switching
|
|
|
|
|
*
|
|
|
|
|
* Misc view utility functions.
|
|
|
|
|
* \{ */
|
|
|
|
|
|
|
|
|
|
bool ED_view3d_offset_lock_check(const View3D *v3d, const RegionView3D *rv3d)
|
|
|
|
|
{
|
2020-03-17 11:32:03 +11:00
|
|
|
return (rv3d->persp != RV3D_CAMOB) && (v3d->ob_center_cursor || v3d->ob_center);
|
2018-01-28 14:44:42 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ED_view3d_lastview_store(RegionView3D *rv3d)
|
|
|
|
|
{
|
|
|
|
|
copy_qt_qt(rv3d->lviewquat, rv3d->viewquat);
|
|
|
|
|
rv3d->lview = rv3d->view;
|
2020-02-09 11:50:25 +11:00
|
|
|
rv3d->lview_axis_roll = rv3d->view_axis_roll;
|
2018-01-28 14:44:42 +11:00
|
|
|
if (rv3d->persp != RV3D_CAMOB) {
|
|
|
|
|
rv3d->lpersp = rv3d->persp;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ED_view3d_lock_clear(View3D *v3d)
|
|
|
|
|
{
|
2023-07-12 18:02:56 +02:00
|
|
|
v3d->ob_center = nullptr;
|
2020-03-17 11:32:03 +11:00
|
|
|
v3d->ob_center_bone[0] = '\0';
|
|
|
|
|
v3d->ob_center_cursor = false;
|
|
|
|
|
|
2018-01-28 14:44:42 +11:00
|
|
|
v3d->flag2 &= ~V3D_LOCK_CAMERA;
|
|
|
|
|
}
|
|
|
|
|
|
2018-05-21 20:29:00 +02:00
|
|
|
void ED_view3d_persp_switch_from_camera(const Depsgraph *depsgraph,
|
|
|
|
|
View3D *v3d,
|
|
|
|
|
RegionView3D *rv3d,
|
|
|
|
|
const char persp)
|
2018-01-28 14:44:42 +11:00
|
|
|
{
|
|
|
|
|
BLI_assert(rv3d->persp == RV3D_CAMOB);
|
|
|
|
|
BLI_assert(persp != RV3D_CAMOB);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-01-28 14:44:42 +11:00
|
|
|
if (v3d->camera) {
|
2018-05-22 07:48:12 +02:00
|
|
|
Object *ob_camera_eval = DEG_get_evaluated_object(depsgraph, v3d->camera);
|
2022-10-24 14:16:37 +02:00
|
|
|
rv3d->dist = ED_view3d_offset_distance(
|
2024-02-14 16:14:49 +01:00
|
|
|
ob_camera_eval->object_to_world().ptr(), rv3d->ofs, VIEW3D_DIST_FALLBACK);
|
2023-07-12 18:02:56 +02:00
|
|
|
ED_view3d_from_object(ob_camera_eval, rv3d->ofs, rv3d->viewquat, &rv3d->dist, nullptr);
|
2025-02-05 09:38:55 +01:00
|
|
|
WM_main_add_notifier(NC_SPACE | ND_SPACE_VIEW3D, v3d);
|
2018-01-28 14:44:42 +11:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-01-28 14:44:42 +11:00
|
|
|
if (!ED_view3d_camera_lock_check(v3d, rv3d)) {
|
|
|
|
|
rv3d->persp = persp;
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-03-06 16:56:42 +01:00
|
|
|
bool ED_view3d_persp_ensure(const Depsgraph *depsgraph, View3D *v3d, ARegion *region)
|
2018-01-28 14:44:42 +11:00
|
|
|
{
|
2023-07-12 18:02:56 +02:00
|
|
|
RegionView3D *rv3d = static_cast<RegionView3D *>(region->regiondata);
|
2018-01-28 14:44:42 +11:00
|
|
|
const bool autopersp = (U.uiflag & USER_AUTOPERSP) != 0;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
VR: Initial Virtual Reality support - Milestone 1, Scene Inspection
NOTE: While most of the milestone 1 goals are there, a few smaller features and
improvements are still to be done.
Big picture of this milestone: Initial, OpenXR-based virtual reality support
for users and foundation for advanced use cases.
Maniphest Task: https://developer.blender.org/T71347
The tasks contains more information about this milestone.
To be clear: This is not a feature rich VR implementation, it's focused on the
initial scene inspection use case. We intentionally focused on that, further
features like controller support are part of the next milestone.
- How to use?
Instructions on how to use this are here:
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/How_to_Test
These will be updated and moved to a more official place (likely the manual) soon.
Currently Windows Mixed Reality and Oculus devices are usable. Valve/HTC
headsets don't support the OpenXR standard yet and hence, do not work with this
implementation.
---------------
This is the C-side implementation of the features added for initial VR
support as per milestone 1. A "VR Scene Inspection" Add-on will be
committed separately, to expose the VR functionality in the UI. It also
adds some further features for milestone 1, namely a landmarking system
(stored view locations in the VR space)
Main additions/features:
* Support for rendering viewports to an HMD, with good performance.
* Option to sync the VR view perspective with a fully interactive,
regular 3D View (VR-Mirror).
* Option to disable positional tracking. Keeps the current position (calculated
based on the VR eye center pose) when enabled while a VR session is running.
* Some regular viewport settings for the VR view
* RNA/Python-API to query and set VR session state information.
* WM-XR: Layer tying Ghost-XR to the Blender specific APIs/data
* wmSurface API: drawable, non-window container (manages Ghost-OpenGL and GPU
context)
* DNA/RNA for management of VR session settings
* `--debug-xr` and `--debug-xr-time` commandline options
* Utility batch & config file for using the Oculus runtime on Windows.
* Most VR data is runtime only. The exception is user settings which are saved
to files (`XrSessionSettings`).
* VR support can be disabled through the `WITH_XR_OPENXR` compiler flag.
For architecture and code documentation, see
https://wiki.blender.org/wiki/Source/Interface/XR.
---------------
A few thank you's:
* A huge shoutout to Ray Molenkamp for his help during the project - it would
have not been that successful without him!
* Sebastian Koenig and Simeon Conzendorf for testing and feedback!
* The reviewers, especially Brecht Van Lommel!
* Dalai Felinto for pushing and managing me to get this done ;)
* The OpenXR working group for providing an open standard. I think we're the
first bigger application to adopt OpenXR. Congratulations to them and
ourselves :)
This project started as a Google Summer of Code 2019 project - "Core Support of
Virtual Reality Headsets through OpenXR" (see
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/).
Some further information, including ideas for further improvements can be found
in the final GSoC report:
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/Final_Report
Differential Revisions: D6193, D7098
Reviewed by: Brecht Van Lommel, Jeroen Bakker
2020-03-17 20:20:55 +01:00
|
|
|
BLI_assert((RV3D_LOCK_FLAGS(rv3d) & RV3D_LOCK_ANY_TRANSFORM) == 0);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-03-26 21:16:47 +11:00
|
|
|
if (ED_view3d_camera_lock_check(v3d, rv3d)) {
|
2018-01-28 14:44:42 +11:00
|
|
|
return false;
|
2019-03-26 21:16:47 +11:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-01-28 14:44:42 +11:00
|
|
|
if (rv3d->persp != RV3D_PERSP) {
|
|
|
|
|
if (rv3d->persp == RV3D_CAMOB) {
|
2019-01-15 23:24:20 +11:00
|
|
|
/* If autopersp and previous view was an axis one,
|
|
|
|
|
* switch back to PERSP mode, else reuse previous mode. */
|
2023-07-13 09:54:00 +10:00
|
|
|
char persp = (autopersp && RV3D_VIEW_IS_AXIS(rv3d->lview)) ? char(RV3D_PERSP) : rv3d->lpersp;
|
2018-05-21 20:29:00 +02:00
|
|
|
ED_view3d_persp_switch_from_camera(depsgraph, v3d, rv3d, persp);
|
2018-01-28 14:44:42 +11:00
|
|
|
}
|
2020-02-09 11:50:25 +11:00
|
|
|
else if (autopersp && RV3D_VIEW_IS_AXIS(rv3d->view)) {
|
2018-01-28 14:44:42 +11:00
|
|
|
rv3d->persp = RV3D_PERSP;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-01-28 14:44:42 +11:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** \} */
|
|
|
|
|
|
2022-02-18 16:43:10 +11:00
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name Camera View Utilities
|
|
|
|
|
*
|
|
|
|
|
* Utilities for manipulating the camera-view.
|
|
|
|
|
* \{ */
|
|
|
|
|
|
|
|
|
|
bool ED_view3d_camera_view_zoom_scale(RegionView3D *rv3d, const float scale)
|
|
|
|
|
{
|
|
|
|
|
const float camzoom_init = rv3d->camzoom;
|
|
|
|
|
float zoomfac = BKE_screen_view3d_zoom_to_fac(rv3d->camzoom);
|
|
|
|
|
/* Clamp both before and after conversion to prevent NAN on negative values. */
|
|
|
|
|
|
|
|
|
|
zoomfac = zoomfac * scale;
|
|
|
|
|
CLAMP(zoomfac, RV3D_CAMZOOM_MIN_FACTOR, RV3D_CAMZOOM_MAX_FACTOR);
|
|
|
|
|
rv3d->camzoom = BKE_screen_view3d_zoom_from_fac(zoomfac);
|
|
|
|
|
CLAMP(rv3d->camzoom, RV3D_CAMZOOM_MIN, RV3D_CAMZOOM_MAX);
|
|
|
|
|
return (rv3d->camzoom != camzoom_init);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool ED_view3d_camera_view_pan(ARegion *region, const float event_ofs[2])
|
|
|
|
|
{
|
2023-07-12 18:02:56 +02:00
|
|
|
RegionView3D *rv3d = static_cast<RegionView3D *>(region->regiondata);
|
2022-02-18 16:43:10 +11:00
|
|
|
const float camdxy_init[2] = {rv3d->camdx, rv3d->camdy};
|
|
|
|
|
const float zoomfac = BKE_screen_view3d_zoom_to_fac(rv3d->camzoom) * 2.0f;
|
|
|
|
|
rv3d->camdx += event_ofs[0] / (region->winx * zoomfac);
|
|
|
|
|
rv3d->camdy += event_ofs[1] / (region->winy * zoomfac);
|
|
|
|
|
CLAMP(rv3d->camdx, -1.0f, 1.0f);
|
|
|
|
|
CLAMP(rv3d->camdy, -1.0f, 1.0f);
|
|
|
|
|
return (camdxy_init[0] != rv3d->camdx) || (camdxy_init[1] != rv3d->camdy);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** \} */
|
|
|
|
|
|
2018-01-28 14:44:42 +11:00
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name Camera Lock API
|
|
|
|
|
*
|
2020-12-02 18:16:04 -05:00
|
|
|
* Lock the camera to the 3D Viewport, allowing view manipulation to transform the camera.
|
2018-01-28 14:44:42 +11:00
|
|
|
* \{ */
|
|
|
|
|
|
|
|
|
|
bool ED_view3d_camera_lock_check(const View3D *v3d, const RegionView3D *rv3d)
|
|
|
|
|
{
|
2024-05-16 14:53:09 +02:00
|
|
|
return ((v3d->camera) && ID_IS_EDITABLE(v3d->camera) && (v3d->flag2 & V3D_LOCK_CAMERA) &&
|
2018-01-28 14:44:42 +11:00
|
|
|
(rv3d->persp == RV3D_CAMOB));
|
|
|
|
|
}
|
|
|
|
|
|
2018-05-22 07:31:11 +02:00
|
|
|
void ED_view3d_camera_lock_init_ex(const Depsgraph *depsgraph,
|
|
|
|
|
View3D *v3d,
|
|
|
|
|
RegionView3D *rv3d,
|
|
|
|
|
const bool calc_dist)
|
2018-01-28 14:44:42 +11:00
|
|
|
{
|
|
|
|
|
if (ED_view3d_camera_lock_check(v3d, rv3d)) {
|
2018-05-22 07:48:12 +02:00
|
|
|
Object *ob_camera_eval = DEG_get_evaluated_object(depsgraph, v3d->camera);
|
2018-01-28 14:44:42 +11:00
|
|
|
if (calc_dist) {
|
|
|
|
|
/* using a fallback dist is OK here since ED_view3d_from_object() compensates for it */
|
2018-05-22 07:48:12 +02:00
|
|
|
rv3d->dist = ED_view3d_offset_distance(
|
2024-02-14 16:14:49 +01:00
|
|
|
ob_camera_eval->object_to_world().ptr(), rv3d->ofs, VIEW3D_DIST_FALLBACK);
|
2018-01-28 14:44:42 +11:00
|
|
|
}
|
2023-07-12 18:02:56 +02:00
|
|
|
ED_view3d_from_object(ob_camera_eval, rv3d->ofs, rv3d->viewquat, &rv3d->dist, nullptr);
|
2018-01-28 14:44:42 +11:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-05-21 20:29:00 +02:00
|
|
|
void ED_view3d_camera_lock_init(const Depsgraph *depsgraph, View3D *v3d, RegionView3D *rv3d)
|
2018-01-28 14:44:42 +11:00
|
|
|
{
|
2018-11-30 12:16:19 +01:00
|
|
|
ED_view3d_camera_lock_init_ex(depsgraph, v3d, rv3d, true);
|
2018-01-28 14:44:42 +11:00
|
|
|
}
|
|
|
|
|
|
2018-05-21 20:29:00 +02:00
|
|
|
bool ED_view3d_camera_lock_sync(const Depsgraph *depsgraph, View3D *v3d, RegionView3D *rv3d)
|
2018-01-28 14:44:42 +11:00
|
|
|
{
|
|
|
|
|
if (ED_view3d_camera_lock_check(v3d, rv3d)) {
|
|
|
|
|
ObjectTfmProtectedChannels obtfm;
|
|
|
|
|
Object *root_parent;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-11-05 16:08:00 -06:00
|
|
|
if (v3d->camera->transflag & OB_TRANSFORM_ADJUST_ROOT_PARENT_FOR_VIEW_LOCK &&
|
|
|
|
|
(root_parent = v3d->camera->parent))
|
|
|
|
|
{
|
2018-01-28 14:44:42 +11:00
|
|
|
Object *ob_update;
|
|
|
|
|
float tmat[4][4];
|
|
|
|
|
float imat[4][4];
|
|
|
|
|
float view_mat[4][4];
|
|
|
|
|
float diff_mat[4][4];
|
|
|
|
|
float parent_mat[4][4];
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-01-28 14:44:42 +11:00
|
|
|
while (root_parent->parent) {
|
|
|
|
|
root_parent = root_parent->parent;
|
|
|
|
|
}
|
2018-05-22 07:48:12 +02:00
|
|
|
Object *ob_camera_eval = DEG_get_evaluated_object(depsgraph, v3d->camera);
|
2018-05-21 20:29:00 +02:00
|
|
|
Object *root_parent_eval = DEG_get_evaluated_object(depsgraph, root_parent);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-01-28 14:44:42 +11:00
|
|
|
ED_view3d_to_m4(view_mat, rv3d->ofs, rv3d->viewquat, rv3d->dist);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2024-02-14 16:14:49 +01:00
|
|
|
normalize_m4_m4(tmat, ob_camera_eval->object_to_world().ptr());
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-01-28 14:44:42 +11:00
|
|
|
invert_m4_m4(imat, tmat);
|
|
|
|
|
mul_m4_m4m4(diff_mat, view_mat, imat);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2024-02-14 16:14:49 +01:00
|
|
|
mul_m4_m4m4(parent_mat, diff_mat, root_parent_eval->object_to_world().ptr());
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-01-28 14:44:42 +11:00
|
|
|
BKE_object_tfm_protected_backup(root_parent, &obtfm);
|
|
|
|
|
BKE_object_apply_mat4(root_parent, parent_mat, true, false);
|
|
|
|
|
BKE_object_tfm_protected_restore(root_parent, &obtfm, root_parent->protectflag);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-01-28 14:44:42 +11:00
|
|
|
ob_update = v3d->camera;
|
|
|
|
|
while (ob_update) {
|
2018-12-06 17:52:37 +01:00
|
|
|
DEG_id_tag_update(&ob_update->id, ID_RECALC_TRANSFORM);
|
2018-01-28 14:44:42 +11:00
|
|
|
WM_main_add_notifier(NC_OBJECT | ND_TRANSFORM, ob_update);
|
|
|
|
|
ob_update = ob_update->parent;
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2018-01-28 14:44:42 +11:00
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
/* always maintain the same scale */
|
|
|
|
|
const short protect_scale_all = (OB_LOCK_SCALEX | OB_LOCK_SCALEY | OB_LOCK_SCALEZ);
|
|
|
|
|
BKE_object_tfm_protected_backup(v3d->camera, &obtfm);
|
2018-05-21 20:29:00 +02:00
|
|
|
ED_view3d_to_object(depsgraph, v3d->camera, rv3d->ofs, rv3d->viewquat, rv3d->dist);
|
2018-01-28 14:44:42 +11:00
|
|
|
BKE_object_tfm_protected_restore(
|
|
|
|
|
v3d->camera, &obtfm, v3d->camera->protectflag | protect_scale_all);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-12-06 17:52:37 +01:00
|
|
|
DEG_id_tag_update(&v3d->camera->id, ID_RECALC_TRANSFORM);
|
2018-01-28 14:44:42 +11:00
|
|
|
WM_main_add_notifier(NC_OBJECT | ND_TRANSFORM, v3d->camera);
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-01-28 14:44:42 +11:00
|
|
|
return true;
|
|
|
|
|
}
|
2020-07-03 17:18:56 +02:00
|
|
|
return false;
|
2018-01-28 14:44:42 +11:00
|
|
|
}
|
|
|
|
|
|
2023-06-03 08:36:28 +10:00
|
|
|
bool ED_view3d_camera_autokey(
|
|
|
|
|
const Scene *scene, ID *id_key, bContext *C, const bool do_rotate, const bool do_translate)
|
2018-01-28 14:44:42 +11:00
|
|
|
{
|
2024-12-17 13:36:49 +01:00
|
|
|
BLI_assert(GS(id_key->name) == ID_OB);
|
|
|
|
|
using namespace blender;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2024-12-17 13:36:49 +01:00
|
|
|
/* While `autokeyframe_object` does already call `autokeyframe_cfra_can_key` we need this here
|
|
|
|
|
* because at the time of writing this it returns void. Once the keying result is returned, like
|
|
|
|
|
* implemented for `blender::animrig::insert_keyframes`, this `if` can be removed. */
|
|
|
|
|
if (!animrig::autokeyframe_cfra_can_key(scene, id_key)) {
|
|
|
|
|
return false;
|
2018-01-28 14:44:42 +11:00
|
|
|
}
|
2024-12-17 13:36:49 +01:00
|
|
|
|
|
|
|
|
Object *camera_object = reinterpret_cast<Object *>(id_key);
|
|
|
|
|
|
|
|
|
|
Vector<RNAPath> rna_paths;
|
|
|
|
|
|
|
|
|
|
if (do_rotate) {
|
|
|
|
|
switch (camera_object->rotmode) {
|
|
|
|
|
case ROT_MODE_QUAT:
|
|
|
|
|
rna_paths.append({"rotation_quaternion"});
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case ROT_MODE_AXISANGLE:
|
|
|
|
|
rna_paths.append({"rotation_axis_angle"});
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case ROT_MODE_EUL:
|
|
|
|
|
rna_paths.append({"rotation_euler"});
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (do_translate) {
|
|
|
|
|
rna_paths.append({"location"});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
animrig::autokeyframe_object(C, scene, camera_object, rna_paths);
|
|
|
|
|
WM_main_add_notifier(NC_ANIMATION | ND_KEYFRAME | NA_ADDED, nullptr);
|
|
|
|
|
return true;
|
2018-01-28 14:44:42 +11:00
|
|
|
}
|
|
|
|
|
|
2023-06-03 08:36:28 +10:00
|
|
|
bool ED_view3d_camera_lock_autokey(
|
|
|
|
|
View3D *v3d, RegionView3D *rv3d, bContext *C, const bool do_rotate, const bool do_translate)
|
2018-01-28 14:44:42 +11:00
|
|
|
{
|
|
|
|
|
/* similar to ED_view3d_cameracontrol_update */
|
|
|
|
|
if (ED_view3d_camera_lock_check(v3d, rv3d)) {
|
|
|
|
|
Scene *scene = CTX_data_scene(C);
|
|
|
|
|
ID *id_key;
|
|
|
|
|
Object *root_parent;
|
2020-11-05 16:08:00 -06:00
|
|
|
if (v3d->camera->transflag & OB_TRANSFORM_ADJUST_ROOT_PARENT_FOR_VIEW_LOCK &&
|
|
|
|
|
(root_parent = v3d->camera->parent))
|
|
|
|
|
{
|
2018-01-28 14:44:42 +11:00
|
|
|
while (root_parent->parent) {
|
|
|
|
|
root_parent = root_parent->parent;
|
|
|
|
|
}
|
|
|
|
|
id_key = &root_parent->id;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
id_key = &v3d->camera->id;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-01-28 14:44:42 +11:00
|
|
|
return ED_view3d_camera_autokey(scene, id_key, C, do_rotate, do_translate);
|
|
|
|
|
}
|
2020-07-03 17:18:56 +02:00
|
|
|
return false;
|
2018-01-28 14:44:42 +11:00
|
|
|
}
|
|
|
|
|
|
2023-06-03 08:36:28 +10:00
|
|
|
bool ED_view3d_camera_lock_undo_test(const View3D *v3d, const RegionView3D *rv3d, bContext *C)
|
2022-08-09 09:31:18 +10:00
|
|
|
{
|
|
|
|
|
if (ED_view3d_camera_lock_check(v3d, rv3d)) {
|
|
|
|
|
if (ED_undo_is_memfile_compatible(C)) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2022-08-05 15:53:04 +10:00
|
|
|
/**
|
|
|
|
|
* Create a MEMFILE undo-step for locked camera movement when transforming the view.
|
|
|
|
|
* Edit and texture paint mode don't use MEMFILE undo so undo push is skipped for them.
|
2023-12-15 22:54:55 +11:00
|
|
|
* NDOF and trackpad navigation would create an undo step on every gesture and we may end up with
|
2022-08-19 21:04:57 +10:00
|
|
|
* unnecessary undo steps so undo push for them is not supported for now.
|
|
|
|
|
* Operators that use smooth view for navigation are supported via an optional parameter field,
|
|
|
|
|
* see: #V3D_SmoothParams.undo_str.
|
2022-08-05 15:53:04 +10:00
|
|
|
*/
|
2022-08-11 10:05:21 +10:00
|
|
|
static bool view3d_camera_lock_undo_ex(const char *str,
|
|
|
|
|
const View3D *v3d,
|
|
|
|
|
const RegionView3D *rv3d,
|
2023-06-03 08:36:28 +10:00
|
|
|
bContext *C,
|
2022-08-11 10:05:21 +10:00
|
|
|
const bool undo_group)
|
2022-08-05 15:53:04 +10:00
|
|
|
{
|
2022-08-09 09:31:18 +10:00
|
|
|
if (ED_view3d_camera_lock_undo_test(v3d, rv3d, C)) {
|
|
|
|
|
if (undo_group) {
|
|
|
|
|
ED_undo_grouped_push(C, str);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
ED_undo_push(C, str);
|
2022-08-05 15:53:04 +10:00
|
|
|
}
|
2022-08-09 09:31:18 +10:00
|
|
|
return true;
|
2022-08-05 15:53:04 +10:00
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2022-08-11 10:05:21 +10:00
|
|
|
bool ED_view3d_camera_lock_undo_push(const char *str,
|
|
|
|
|
const View3D *v3d,
|
|
|
|
|
const RegionView3D *rv3d,
|
|
|
|
|
bContext *C)
|
2022-08-05 15:53:04 +10:00
|
|
|
{
|
|
|
|
|
return view3d_camera_lock_undo_ex(str, v3d, rv3d, C, false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool ED_view3d_camera_lock_undo_grouped_push(const char *str,
|
2022-08-11 10:05:21 +10:00
|
|
|
const View3D *v3d,
|
|
|
|
|
const RegionView3D *rv3d,
|
2022-08-05 15:53:04 +10:00
|
|
|
bContext *C)
|
|
|
|
|
{
|
|
|
|
|
return view3d_camera_lock_undo_ex(str, v3d, rv3d, C, true);
|
|
|
|
|
}
|
|
|
|
|
|
2018-01-28 14:44:42 +11:00
|
|
|
/** \} */
|
|
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name Box View Support
|
|
|
|
|
*
|
|
|
|
|
* Use with quad-split so each view is clipped by the bounds of each view axis.
|
|
|
|
|
* \{ */
|
|
|
|
|
|
2020-04-03 13:25:03 +02:00
|
|
|
static void view3d_boxview_clip(ScrArea *area)
|
2018-01-28 14:44:42 +11:00
|
|
|
{
|
2023-07-12 18:02:56 +02:00
|
|
|
BoundBox *bb = static_cast<BoundBox *>(MEM_callocN(sizeof(BoundBox), "clipbb"));
|
2018-01-28 14:44:42 +11:00
|
|
|
float clip[6][4];
|
|
|
|
|
float x1 = 0.0f, y1 = 0.0f, z1 = 0.0f, ofs[3] = {0.0f, 0.0f, 0.0f};
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-01-28 14:44:42 +11:00
|
|
|
/* create bounding box */
|
2021-01-25 17:22:52 -06:00
|
|
|
LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
|
2020-03-06 16:56:42 +01:00
|
|
|
if (region->regiontype == RGN_TYPE_WINDOW) {
|
2023-07-12 18:02:56 +02:00
|
|
|
RegionView3D *rv3d = static_cast<RegionView3D *>(region->regiondata);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
VR: Initial Virtual Reality support - Milestone 1, Scene Inspection
NOTE: While most of the milestone 1 goals are there, a few smaller features and
improvements are still to be done.
Big picture of this milestone: Initial, OpenXR-based virtual reality support
for users and foundation for advanced use cases.
Maniphest Task: https://developer.blender.org/T71347
The tasks contains more information about this milestone.
To be clear: This is not a feature rich VR implementation, it's focused on the
initial scene inspection use case. We intentionally focused on that, further
features like controller support are part of the next milestone.
- How to use?
Instructions on how to use this are here:
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/How_to_Test
These will be updated and moved to a more official place (likely the manual) soon.
Currently Windows Mixed Reality and Oculus devices are usable. Valve/HTC
headsets don't support the OpenXR standard yet and hence, do not work with this
implementation.
---------------
This is the C-side implementation of the features added for initial VR
support as per milestone 1. A "VR Scene Inspection" Add-on will be
committed separately, to expose the VR functionality in the UI. It also
adds some further features for milestone 1, namely a landmarking system
(stored view locations in the VR space)
Main additions/features:
* Support for rendering viewports to an HMD, with good performance.
* Option to sync the VR view perspective with a fully interactive,
regular 3D View (VR-Mirror).
* Option to disable positional tracking. Keeps the current position (calculated
based on the VR eye center pose) when enabled while a VR session is running.
* Some regular viewport settings for the VR view
* RNA/Python-API to query and set VR session state information.
* WM-XR: Layer tying Ghost-XR to the Blender specific APIs/data
* wmSurface API: drawable, non-window container (manages Ghost-OpenGL and GPU
context)
* DNA/RNA for management of VR session settings
* `--debug-xr` and `--debug-xr-time` commandline options
* Utility batch & config file for using the Oculus runtime on Windows.
* Most VR data is runtime only. The exception is user settings which are saved
to files (`XrSessionSettings`).
* VR support can be disabled through the `WITH_XR_OPENXR` compiler flag.
For architecture and code documentation, see
https://wiki.blender.org/wiki/Source/Interface/XR.
---------------
A few thank you's:
* A huge shoutout to Ray Molenkamp for his help during the project - it would
have not been that successful without him!
* Sebastian Koenig and Simeon Conzendorf for testing and feedback!
* The reviewers, especially Brecht Van Lommel!
* Dalai Felinto for pushing and managing me to get this done ;)
* The OpenXR working group for providing an open standard. I think we're the
first bigger application to adopt OpenXR. Congratulations to them and
ourselves :)
This project started as a Google Summer of Code 2019 project - "Core Support of
Virtual Reality Headsets through OpenXR" (see
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/).
Some further information, including ideas for further improvements can be found
in the final GSoC report:
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/Final_Report
Differential Revisions: D6193, D7098
Reviewed by: Brecht Van Lommel, Jeroen Bakker
2020-03-17 20:20:55 +01:00
|
|
|
if (RV3D_LOCK_FLAGS(rv3d) & RV3D_BOXCLIP) {
|
2018-01-28 14:44:42 +11:00
|
|
|
if (ELEM(rv3d->view, RV3D_VIEW_TOP, RV3D_VIEW_BOTTOM)) {
|
2020-03-06 16:56:42 +01:00
|
|
|
if (region->winx > region->winy) {
|
2019-03-26 21:16:47 +11:00
|
|
|
x1 = rv3d->dist;
|
|
|
|
|
}
|
|
|
|
|
else {
|
2020-03-06 16:56:42 +01:00
|
|
|
x1 = region->winx * rv3d->dist / region->winy;
|
2019-03-26 21:16:47 +11:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-03-06 16:56:42 +01:00
|
|
|
if (region->winx > region->winy) {
|
|
|
|
|
y1 = region->winy * rv3d->dist / region->winx;
|
2019-03-26 21:16:47 +11:00
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
y1 = rv3d->dist;
|
|
|
|
|
}
|
2018-01-28 14:44:42 +11:00
|
|
|
copy_v2_v2(ofs, rv3d->ofs);
|
|
|
|
|
}
|
|
|
|
|
else if (ELEM(rv3d->view, RV3D_VIEW_FRONT, RV3D_VIEW_BACK)) {
|
|
|
|
|
ofs[2] = rv3d->ofs[2];
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-03-06 16:56:42 +01:00
|
|
|
if (region->winx > region->winy) {
|
|
|
|
|
z1 = region->winy * rv3d->dist / region->winx;
|
2019-03-26 21:16:47 +11:00
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
z1 = rv3d->dist;
|
|
|
|
|
}
|
2018-01-28 14:44:42 +11:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2021-01-25 17:22:52 -06:00
|
|
|
for (int val = 0; val < 8; val++) {
|
2019-03-26 21:16:47 +11:00
|
|
|
if (ELEM(val, 0, 3, 4, 7)) {
|
2018-01-28 14:44:42 +11:00
|
|
|
bb->vec[val][0] = -x1 - ofs[0];
|
2019-03-26 21:16:47 +11:00
|
|
|
}
|
|
|
|
|
else {
|
2018-01-28 14:44:42 +11:00
|
|
|
bb->vec[val][0] = x1 - ofs[0];
|
2019-03-26 21:16:47 +11:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-03-26 21:16:47 +11:00
|
|
|
if (ELEM(val, 0, 1, 4, 5)) {
|
2018-01-28 14:44:42 +11:00
|
|
|
bb->vec[val][1] = -y1 - ofs[1];
|
2019-03-26 21:16:47 +11:00
|
|
|
}
|
|
|
|
|
else {
|
2018-01-28 14:44:42 +11:00
|
|
|
bb->vec[val][1] = y1 - ofs[1];
|
2019-03-26 21:16:47 +11:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-03-26 21:16:47 +11:00
|
|
|
if (val > 3) {
|
2018-01-28 14:44:42 +11:00
|
|
|
bb->vec[val][2] = -z1 - ofs[2];
|
2019-03-26 21:16:47 +11:00
|
|
|
}
|
|
|
|
|
else {
|
2018-01-28 14:44:42 +11:00
|
|
|
bb->vec[val][2] = z1 - ofs[2];
|
2019-03-26 21:16:47 +11:00
|
|
|
}
|
2018-01-28 14:44:42 +11:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-01-28 14:44:42 +11:00
|
|
|
/* normals for plane equations */
|
|
|
|
|
normal_tri_v3(clip[0], bb->vec[0], bb->vec[1], bb->vec[4]);
|
|
|
|
|
normal_tri_v3(clip[1], bb->vec[1], bb->vec[2], bb->vec[5]);
|
|
|
|
|
normal_tri_v3(clip[2], bb->vec[2], bb->vec[3], bb->vec[6]);
|
|
|
|
|
normal_tri_v3(clip[3], bb->vec[3], bb->vec[0], bb->vec[7]);
|
|
|
|
|
normal_tri_v3(clip[4], bb->vec[4], bb->vec[5], bb->vec[6]);
|
|
|
|
|
normal_tri_v3(clip[5], bb->vec[0], bb->vec[2], bb->vec[1]);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-01-28 14:44:42 +11:00
|
|
|
/* then plane equations */
|
2021-01-25 17:22:52 -06:00
|
|
|
for (int val = 0; val < 6; val++) {
|
2018-01-28 14:44:42 +11:00
|
|
|
clip[val][3] = -dot_v3v3(clip[val], bb->vec[val % 5]);
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-01-28 14:44:42 +11:00
|
|
|
/* create bounding box */
|
2021-01-25 17:22:52 -06:00
|
|
|
LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
|
2020-03-06 16:56:42 +01:00
|
|
|
if (region->regiontype == RGN_TYPE_WINDOW) {
|
2023-07-12 18:02:56 +02:00
|
|
|
RegionView3D *rv3d = static_cast<RegionView3D *>(region->regiondata);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
VR: Initial Virtual Reality support - Milestone 1, Scene Inspection
NOTE: While most of the milestone 1 goals are there, a few smaller features and
improvements are still to be done.
Big picture of this milestone: Initial, OpenXR-based virtual reality support
for users and foundation for advanced use cases.
Maniphest Task: https://developer.blender.org/T71347
The tasks contains more information about this milestone.
To be clear: This is not a feature rich VR implementation, it's focused on the
initial scene inspection use case. We intentionally focused on that, further
features like controller support are part of the next milestone.
- How to use?
Instructions on how to use this are here:
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/How_to_Test
These will be updated and moved to a more official place (likely the manual) soon.
Currently Windows Mixed Reality and Oculus devices are usable. Valve/HTC
headsets don't support the OpenXR standard yet and hence, do not work with this
implementation.
---------------
This is the C-side implementation of the features added for initial VR
support as per milestone 1. A "VR Scene Inspection" Add-on will be
committed separately, to expose the VR functionality in the UI. It also
adds some further features for milestone 1, namely a landmarking system
(stored view locations in the VR space)
Main additions/features:
* Support for rendering viewports to an HMD, with good performance.
* Option to sync the VR view perspective with a fully interactive,
regular 3D View (VR-Mirror).
* Option to disable positional tracking. Keeps the current position (calculated
based on the VR eye center pose) when enabled while a VR session is running.
* Some regular viewport settings for the VR view
* RNA/Python-API to query and set VR session state information.
* WM-XR: Layer tying Ghost-XR to the Blender specific APIs/data
* wmSurface API: drawable, non-window container (manages Ghost-OpenGL and GPU
context)
* DNA/RNA for management of VR session settings
* `--debug-xr` and `--debug-xr-time` commandline options
* Utility batch & config file for using the Oculus runtime on Windows.
* Most VR data is runtime only. The exception is user settings which are saved
to files (`XrSessionSettings`).
* VR support can be disabled through the `WITH_XR_OPENXR` compiler flag.
For architecture and code documentation, see
https://wiki.blender.org/wiki/Source/Interface/XR.
---------------
A few thank you's:
* A huge shoutout to Ray Molenkamp for his help during the project - it would
have not been that successful without him!
* Sebastian Koenig and Simeon Conzendorf for testing and feedback!
* The reviewers, especially Brecht Van Lommel!
* Dalai Felinto for pushing and managing me to get this done ;)
* The OpenXR working group for providing an open standard. I think we're the
first bigger application to adopt OpenXR. Congratulations to them and
ourselves :)
This project started as a Google Summer of Code 2019 project - "Core Support of
Virtual Reality Headsets through OpenXR" (see
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/).
Some further information, including ideas for further improvements can be found
in the final GSoC report:
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/Final_Report
Differential Revisions: D6193, D7098
Reviewed by: Brecht Van Lommel, Jeroen Bakker
2020-03-17 20:20:55 +01:00
|
|
|
if (RV3D_LOCK_FLAGS(rv3d) & RV3D_BOXCLIP) {
|
2018-01-28 14:44:42 +11:00
|
|
|
rv3d->rflag |= RV3D_CLIPPING;
|
|
|
|
|
memcpy(rv3d->clip, clip, sizeof(clip));
|
2019-03-26 21:16:47 +11:00
|
|
|
if (rv3d->clipbb) {
|
|
|
|
|
MEM_freeN(rv3d->clipbb);
|
|
|
|
|
}
|
2023-07-12 18:02:56 +02:00
|
|
|
rv3d->clipbb = static_cast<BoundBox *>(MEM_dupallocN(bb));
|
2018-01-28 14:44:42 +11:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
MEM_freeN(bb);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Find which axis values are shared between both views and copy to \a rv3d_dst
|
|
|
|
|
* taking axis flipping into account.
|
|
|
|
|
*/
|
|
|
|
|
static void view3d_boxview_sync_axis(RegionView3D *rv3d_dst, RegionView3D *rv3d_src)
|
|
|
|
|
{
|
|
|
|
|
/* absolute axis values above this are considered to be set (will be ~1.0f) */
|
|
|
|
|
const float axis_eps = 0.5f;
|
|
|
|
|
float viewinv[4];
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-01-28 14:44:42 +11:00
|
|
|
/* use the view rotation to identify which axis to sync on */
|
|
|
|
|
float view_axis_all[4][3] = {
|
|
|
|
|
{1.0f, 0.0f, 0.0f}, {0.0f, 1.0f, 0.0f}, {1.0f, 0.0f, 0.0f}, {0.0f, 1.0f, 0.0f}};
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-01-28 14:44:42 +11:00
|
|
|
float *view_src_x = &view_axis_all[0][0];
|
|
|
|
|
float *view_src_y = &view_axis_all[1][0];
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-01-28 14:44:42 +11:00
|
|
|
float *view_dst_x = &view_axis_all[2][0];
|
|
|
|
|
float *view_dst_y = &view_axis_all[3][0];
|
|
|
|
|
int i;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-01-28 14:44:42 +11:00
|
|
|
/* we could use rv3d->viewinv, but better not depend on view matrix being updated */
|
2020-02-09 11:50:25 +11:00
|
|
|
if (UNLIKELY(ED_view3d_quat_from_axis_view(rv3d_src->view, rv3d_src->view_axis_roll, viewinv) ==
|
|
|
|
|
false))
|
|
|
|
|
{
|
2018-01-28 14:44:42 +11:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
invert_qt_normalized(viewinv);
|
|
|
|
|
mul_qt_v3(viewinv, view_src_x);
|
|
|
|
|
mul_qt_v3(viewinv, view_src_y);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-02-09 11:50:25 +11:00
|
|
|
if (UNLIKELY(ED_view3d_quat_from_axis_view(rv3d_dst->view, rv3d_dst->view_axis_roll, viewinv) ==
|
|
|
|
|
false))
|
|
|
|
|
{
|
2018-01-28 14:44:42 +11:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
invert_qt_normalized(viewinv);
|
|
|
|
|
mul_qt_v3(viewinv, view_dst_x);
|
|
|
|
|
mul_qt_v3(viewinv, view_dst_y);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-05-20 21:17:09 +10:00
|
|
|
/* Check source and destination have a matching axis. */
|
2018-01-28 14:44:42 +11:00
|
|
|
for (i = 0; i < 3; i++) {
|
|
|
|
|
if (((fabsf(view_src_x[i]) > axis_eps) || (fabsf(view_src_y[i]) > axis_eps)) &&
|
|
|
|
|
((fabsf(view_dst_x[i]) > axis_eps) || (fabsf(view_dst_y[i]) > axis_eps)))
|
|
|
|
|
{
|
|
|
|
|
rv3d_dst->ofs[i] = rv3d_src->ofs[i];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-03 13:25:03 +02:00
|
|
|
void view3d_boxview_sync(ScrArea *area, ARegion *region)
|
2018-01-28 14:44:42 +11:00
|
|
|
{
|
2023-07-12 18:02:56 +02:00
|
|
|
RegionView3D *rv3d = static_cast<RegionView3D *>(region->regiondata);
|
2018-01-28 14:44:42 +11:00
|
|
|
short clip = 0;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-11-29 18:10:47 -05:00
|
|
|
LISTBASE_FOREACH (ARegion *, region_test, &area->regionbase) {
|
|
|
|
|
if (region_test != region && region_test->regiontype == RGN_TYPE_WINDOW) {
|
2023-07-12 18:02:56 +02:00
|
|
|
RegionView3D *rv3dtest = static_cast<RegionView3D *>(region_test->regiondata);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
VR: Initial Virtual Reality support - Milestone 1, Scene Inspection
NOTE: While most of the milestone 1 goals are there, a few smaller features and
improvements are still to be done.
Big picture of this milestone: Initial, OpenXR-based virtual reality support
for users and foundation for advanced use cases.
Maniphest Task: https://developer.blender.org/T71347
The tasks contains more information about this milestone.
To be clear: This is not a feature rich VR implementation, it's focused on the
initial scene inspection use case. We intentionally focused on that, further
features like controller support are part of the next milestone.
- How to use?
Instructions on how to use this are here:
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/How_to_Test
These will be updated and moved to a more official place (likely the manual) soon.
Currently Windows Mixed Reality and Oculus devices are usable. Valve/HTC
headsets don't support the OpenXR standard yet and hence, do not work with this
implementation.
---------------
This is the C-side implementation of the features added for initial VR
support as per milestone 1. A "VR Scene Inspection" Add-on will be
committed separately, to expose the VR functionality in the UI. It also
adds some further features for milestone 1, namely a landmarking system
(stored view locations in the VR space)
Main additions/features:
* Support for rendering viewports to an HMD, with good performance.
* Option to sync the VR view perspective with a fully interactive,
regular 3D View (VR-Mirror).
* Option to disable positional tracking. Keeps the current position (calculated
based on the VR eye center pose) when enabled while a VR session is running.
* Some regular viewport settings for the VR view
* RNA/Python-API to query and set VR session state information.
* WM-XR: Layer tying Ghost-XR to the Blender specific APIs/data
* wmSurface API: drawable, non-window container (manages Ghost-OpenGL and GPU
context)
* DNA/RNA for management of VR session settings
* `--debug-xr` and `--debug-xr-time` commandline options
* Utility batch & config file for using the Oculus runtime on Windows.
* Most VR data is runtime only. The exception is user settings which are saved
to files (`XrSessionSettings`).
* VR support can be disabled through the `WITH_XR_OPENXR` compiler flag.
For architecture and code documentation, see
https://wiki.blender.org/wiki/Source/Interface/XR.
---------------
A few thank you's:
* A huge shoutout to Ray Molenkamp for his help during the project - it would
have not been that successful without him!
* Sebastian Koenig and Simeon Conzendorf for testing and feedback!
* The reviewers, especially Brecht Van Lommel!
* Dalai Felinto for pushing and managing me to get this done ;)
* The OpenXR working group for providing an open standard. I think we're the
first bigger application to adopt OpenXR. Congratulations to them and
ourselves :)
This project started as a Google Summer of Code 2019 project - "Core Support of
Virtual Reality Headsets through OpenXR" (see
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/).
Some further information, including ideas for further improvements can be found
in the final GSoC report:
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/Final_Report
Differential Revisions: D6193, D7098
Reviewed by: Brecht Van Lommel, Jeroen Bakker
2020-03-17 20:20:55 +01:00
|
|
|
if (RV3D_LOCK_FLAGS(rv3dtest) & RV3D_LOCK_ROTATION) {
|
2018-01-28 14:44:42 +11:00
|
|
|
rv3dtest->dist = rv3d->dist;
|
|
|
|
|
view3d_boxview_sync_axis(rv3dtest, rv3d);
|
VR: Initial Virtual Reality support - Milestone 1, Scene Inspection
NOTE: While most of the milestone 1 goals are there, a few smaller features and
improvements are still to be done.
Big picture of this milestone: Initial, OpenXR-based virtual reality support
for users and foundation for advanced use cases.
Maniphest Task: https://developer.blender.org/T71347
The tasks contains more information about this milestone.
To be clear: This is not a feature rich VR implementation, it's focused on the
initial scene inspection use case. We intentionally focused on that, further
features like controller support are part of the next milestone.
- How to use?
Instructions on how to use this are here:
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/How_to_Test
These will be updated and moved to a more official place (likely the manual) soon.
Currently Windows Mixed Reality and Oculus devices are usable. Valve/HTC
headsets don't support the OpenXR standard yet and hence, do not work with this
implementation.
---------------
This is the C-side implementation of the features added for initial VR
support as per milestone 1. A "VR Scene Inspection" Add-on will be
committed separately, to expose the VR functionality in the UI. It also
adds some further features for milestone 1, namely a landmarking system
(stored view locations in the VR space)
Main additions/features:
* Support for rendering viewports to an HMD, with good performance.
* Option to sync the VR view perspective with a fully interactive,
regular 3D View (VR-Mirror).
* Option to disable positional tracking. Keeps the current position (calculated
based on the VR eye center pose) when enabled while a VR session is running.
* Some regular viewport settings for the VR view
* RNA/Python-API to query and set VR session state information.
* WM-XR: Layer tying Ghost-XR to the Blender specific APIs/data
* wmSurface API: drawable, non-window container (manages Ghost-OpenGL and GPU
context)
* DNA/RNA for management of VR session settings
* `--debug-xr` and `--debug-xr-time` commandline options
* Utility batch & config file for using the Oculus runtime on Windows.
* Most VR data is runtime only. The exception is user settings which are saved
to files (`XrSessionSettings`).
* VR support can be disabled through the `WITH_XR_OPENXR` compiler flag.
For architecture and code documentation, see
https://wiki.blender.org/wiki/Source/Interface/XR.
---------------
A few thank you's:
* A huge shoutout to Ray Molenkamp for his help during the project - it would
have not been that successful without him!
* Sebastian Koenig and Simeon Conzendorf for testing and feedback!
* The reviewers, especially Brecht Van Lommel!
* Dalai Felinto for pushing and managing me to get this done ;)
* The OpenXR working group for providing an open standard. I think we're the
first bigger application to adopt OpenXR. Congratulations to them and
ourselves :)
This project started as a Google Summer of Code 2019 project - "Core Support of
Virtual Reality Headsets through OpenXR" (see
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/).
Some further information, including ideas for further improvements can be found
in the final GSoC report:
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/Final_Report
Differential Revisions: D6193, D7098
Reviewed by: Brecht Van Lommel, Jeroen Bakker
2020-03-17 20:20:55 +01:00
|
|
|
clip |= RV3D_LOCK_FLAGS(rv3dtest) & RV3D_BOXCLIP;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-11-29 18:10:47 -05:00
|
|
|
ED_region_tag_redraw(region_test);
|
2018-01-28 14:44:42 +11:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-01-28 14:44:42 +11:00
|
|
|
if (clip) {
|
2020-04-03 13:25:03 +02:00
|
|
|
view3d_boxview_clip(area);
|
2018-01-28 14:44:42 +11:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-03 13:25:03 +02:00
|
|
|
void view3d_boxview_copy(ScrArea *area, ARegion *region)
|
2018-01-28 14:44:42 +11:00
|
|
|
{
|
2023-07-12 18:02:56 +02:00
|
|
|
RegionView3D *rv3d = static_cast<RegionView3D *>(region->regiondata);
|
2018-01-28 14:44:42 +11:00
|
|
|
bool clip = false;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-11-29 18:10:47 -05:00
|
|
|
LISTBASE_FOREACH (ARegion *, region_test, &area->regionbase) {
|
|
|
|
|
if (region_test != region && region_test->regiontype == RGN_TYPE_WINDOW) {
|
2023-07-12 18:02:56 +02:00
|
|
|
RegionView3D *rv3dtest = static_cast<RegionView3D *>(region_test->regiondata);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
VR: Initial Virtual Reality support - Milestone 1, Scene Inspection
NOTE: While most of the milestone 1 goals are there, a few smaller features and
improvements are still to be done.
Big picture of this milestone: Initial, OpenXR-based virtual reality support
for users and foundation for advanced use cases.
Maniphest Task: https://developer.blender.org/T71347
The tasks contains more information about this milestone.
To be clear: This is not a feature rich VR implementation, it's focused on the
initial scene inspection use case. We intentionally focused on that, further
features like controller support are part of the next milestone.
- How to use?
Instructions on how to use this are here:
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/How_to_Test
These will be updated and moved to a more official place (likely the manual) soon.
Currently Windows Mixed Reality and Oculus devices are usable. Valve/HTC
headsets don't support the OpenXR standard yet and hence, do not work with this
implementation.
---------------
This is the C-side implementation of the features added for initial VR
support as per milestone 1. A "VR Scene Inspection" Add-on will be
committed separately, to expose the VR functionality in the UI. It also
adds some further features for milestone 1, namely a landmarking system
(stored view locations in the VR space)
Main additions/features:
* Support for rendering viewports to an HMD, with good performance.
* Option to sync the VR view perspective with a fully interactive,
regular 3D View (VR-Mirror).
* Option to disable positional tracking. Keeps the current position (calculated
based on the VR eye center pose) when enabled while a VR session is running.
* Some regular viewport settings for the VR view
* RNA/Python-API to query and set VR session state information.
* WM-XR: Layer tying Ghost-XR to the Blender specific APIs/data
* wmSurface API: drawable, non-window container (manages Ghost-OpenGL and GPU
context)
* DNA/RNA for management of VR session settings
* `--debug-xr` and `--debug-xr-time` commandline options
* Utility batch & config file for using the Oculus runtime on Windows.
* Most VR data is runtime only. The exception is user settings which are saved
to files (`XrSessionSettings`).
* VR support can be disabled through the `WITH_XR_OPENXR` compiler flag.
For architecture and code documentation, see
https://wiki.blender.org/wiki/Source/Interface/XR.
---------------
A few thank you's:
* A huge shoutout to Ray Molenkamp for his help during the project - it would
have not been that successful without him!
* Sebastian Koenig and Simeon Conzendorf for testing and feedback!
* The reviewers, especially Brecht Van Lommel!
* Dalai Felinto for pushing and managing me to get this done ;)
* The OpenXR working group for providing an open standard. I think we're the
first bigger application to adopt OpenXR. Congratulations to them and
ourselves :)
This project started as a Google Summer of Code 2019 project - "Core Support of
Virtual Reality Headsets through OpenXR" (see
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/).
Some further information, including ideas for further improvements can be found
in the final GSoC report:
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/Final_Report
Differential Revisions: D6193, D7098
Reviewed by: Brecht Van Lommel, Jeroen Bakker
2020-03-17 20:20:55 +01:00
|
|
|
if (RV3D_LOCK_FLAGS(rv3dtest)) {
|
2018-01-28 14:44:42 +11:00
|
|
|
rv3dtest->dist = rv3d->dist;
|
|
|
|
|
copy_v3_v3(rv3dtest->ofs, rv3d->ofs);
|
2020-11-29 18:10:47 -05:00
|
|
|
ED_region_tag_redraw(region_test);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
VR: Initial Virtual Reality support - Milestone 1, Scene Inspection
NOTE: While most of the milestone 1 goals are there, a few smaller features and
improvements are still to be done.
Big picture of this milestone: Initial, OpenXR-based virtual reality support
for users and foundation for advanced use cases.
Maniphest Task: https://developer.blender.org/T71347
The tasks contains more information about this milestone.
To be clear: This is not a feature rich VR implementation, it's focused on the
initial scene inspection use case. We intentionally focused on that, further
features like controller support are part of the next milestone.
- How to use?
Instructions on how to use this are here:
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/How_to_Test
These will be updated and moved to a more official place (likely the manual) soon.
Currently Windows Mixed Reality and Oculus devices are usable. Valve/HTC
headsets don't support the OpenXR standard yet and hence, do not work with this
implementation.
---------------
This is the C-side implementation of the features added for initial VR
support as per milestone 1. A "VR Scene Inspection" Add-on will be
committed separately, to expose the VR functionality in the UI. It also
adds some further features for milestone 1, namely a landmarking system
(stored view locations in the VR space)
Main additions/features:
* Support for rendering viewports to an HMD, with good performance.
* Option to sync the VR view perspective with a fully interactive,
regular 3D View (VR-Mirror).
* Option to disable positional tracking. Keeps the current position (calculated
based on the VR eye center pose) when enabled while a VR session is running.
* Some regular viewport settings for the VR view
* RNA/Python-API to query and set VR session state information.
* WM-XR: Layer tying Ghost-XR to the Blender specific APIs/data
* wmSurface API: drawable, non-window container (manages Ghost-OpenGL and GPU
context)
* DNA/RNA for management of VR session settings
* `--debug-xr` and `--debug-xr-time` commandline options
* Utility batch & config file for using the Oculus runtime on Windows.
* Most VR data is runtime only. The exception is user settings which are saved
to files (`XrSessionSettings`).
* VR support can be disabled through the `WITH_XR_OPENXR` compiler flag.
For architecture and code documentation, see
https://wiki.blender.org/wiki/Source/Interface/XR.
---------------
A few thank you's:
* A huge shoutout to Ray Molenkamp for his help during the project - it would
have not been that successful without him!
* Sebastian Koenig and Simeon Conzendorf for testing and feedback!
* The reviewers, especially Brecht Van Lommel!
* Dalai Felinto for pushing and managing me to get this done ;)
* The OpenXR working group for providing an open standard. I think we're the
first bigger application to adopt OpenXR. Congratulations to them and
ourselves :)
This project started as a Google Summer of Code 2019 project - "Core Support of
Virtual Reality Headsets through OpenXR" (see
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/).
Some further information, including ideas for further improvements can be found
in the final GSoC report:
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/Final_Report
Differential Revisions: D6193, D7098
Reviewed by: Brecht Van Lommel, Jeroen Bakker
2020-03-17 20:20:55 +01:00
|
|
|
clip |= ((RV3D_LOCK_FLAGS(rv3dtest) & RV3D_BOXCLIP) != 0);
|
2018-01-28 14:44:42 +11:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-01-28 14:44:42 +11:00
|
|
|
if (clip) {
|
2020-04-03 13:25:03 +02:00
|
|
|
view3d_boxview_clip(area);
|
2018-01-28 14:44:42 +11:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-03 13:25:03 +02:00
|
|
|
void ED_view3d_quadview_update(ScrArea *area, ARegion *region, bool do_clip)
|
2018-01-28 14:44:42 +11:00
|
|
|
{
|
2023-07-12 18:02:56 +02:00
|
|
|
ARegion *region_sync = nullptr;
|
|
|
|
|
RegionView3D *rv3d = static_cast<RegionView3D *>(region->regiondata);
|
2018-01-28 14:44:42 +11:00
|
|
|
/* this function copies flags from the first of the 3 other quadview
|
|
|
|
|
* regions to the 2 other, so it assumes this is the region whose
|
|
|
|
|
* properties are always being edited, weak */
|
2021-01-25 17:22:52 -06:00
|
|
|
short viewlock = rv3d->viewlock;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
VR: Initial Virtual Reality support - Milestone 1, Scene Inspection
NOTE: While most of the milestone 1 goals are there, a few smaller features and
improvements are still to be done.
Big picture of this milestone: Initial, OpenXR-based virtual reality support
for users and foundation for advanced use cases.
Maniphest Task: https://developer.blender.org/T71347
The tasks contains more information about this milestone.
To be clear: This is not a feature rich VR implementation, it's focused on the
initial scene inspection use case. We intentionally focused on that, further
features like controller support are part of the next milestone.
- How to use?
Instructions on how to use this are here:
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/How_to_Test
These will be updated and moved to a more official place (likely the manual) soon.
Currently Windows Mixed Reality and Oculus devices are usable. Valve/HTC
headsets don't support the OpenXR standard yet and hence, do not work with this
implementation.
---------------
This is the C-side implementation of the features added for initial VR
support as per milestone 1. A "VR Scene Inspection" Add-on will be
committed separately, to expose the VR functionality in the UI. It also
adds some further features for milestone 1, namely a landmarking system
(stored view locations in the VR space)
Main additions/features:
* Support for rendering viewports to an HMD, with good performance.
* Option to sync the VR view perspective with a fully interactive,
regular 3D View (VR-Mirror).
* Option to disable positional tracking. Keeps the current position (calculated
based on the VR eye center pose) when enabled while a VR session is running.
* Some regular viewport settings for the VR view
* RNA/Python-API to query and set VR session state information.
* WM-XR: Layer tying Ghost-XR to the Blender specific APIs/data
* wmSurface API: drawable, non-window container (manages Ghost-OpenGL and GPU
context)
* DNA/RNA for management of VR session settings
* `--debug-xr` and `--debug-xr-time` commandline options
* Utility batch & config file for using the Oculus runtime on Windows.
* Most VR data is runtime only. The exception is user settings which are saved
to files (`XrSessionSettings`).
* VR support can be disabled through the `WITH_XR_OPENXR` compiler flag.
For architecture and code documentation, see
https://wiki.blender.org/wiki/Source/Interface/XR.
---------------
A few thank you's:
* A huge shoutout to Ray Molenkamp for his help during the project - it would
have not been that successful without him!
* Sebastian Koenig and Simeon Conzendorf for testing and feedback!
* The reviewers, especially Brecht Van Lommel!
* Dalai Felinto for pushing and managing me to get this done ;)
* The OpenXR working group for providing an open standard. I think we're the
first bigger application to adopt OpenXR. Congratulations to them and
ourselves :)
This project started as a Google Summer of Code 2019 project - "Core Support of
Virtual Reality Headsets through OpenXR" (see
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/).
Some further information, including ideas for further improvements can be found
in the final GSoC report:
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/Final_Report
Differential Revisions: D6193, D7098
Reviewed by: Brecht Van Lommel, Jeroen Bakker
2020-03-17 20:20:55 +01:00
|
|
|
if ((viewlock & RV3D_LOCK_ROTATION) == 0) {
|
2018-01-28 14:44:42 +11:00
|
|
|
do_clip = (viewlock & RV3D_BOXCLIP) != 0;
|
|
|
|
|
viewlock = 0;
|
|
|
|
|
}
|
|
|
|
|
else if ((viewlock & RV3D_BOXVIEW) == 0 && (viewlock & RV3D_BOXCLIP) != 0) {
|
|
|
|
|
do_clip = true;
|
|
|
|
|
viewlock &= ~RV3D_BOXCLIP;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-03-06 16:56:42 +01:00
|
|
|
for (; region; region = region->prev) {
|
|
|
|
|
if (region->alignment == RGN_ALIGN_QSPLIT) {
|
2023-07-12 18:02:56 +02:00
|
|
|
rv3d = static_cast<RegionView3D *>(region->regiondata);
|
2018-01-28 14:44:42 +11:00
|
|
|
rv3d->viewlock = viewlock;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-01-28 14:44:42 +11:00
|
|
|
if (do_clip && (viewlock & RV3D_BOXCLIP) == 0) {
|
|
|
|
|
rv3d->rflag &= ~RV3D_BOXCLIP;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-04-03 12:51:03 +02:00
|
|
|
/* use region_sync so we sync with one of the aligned views below
|
2018-01-28 14:44:42 +11:00
|
|
|
* else the view jumps on changing view settings like 'clip'
|
|
|
|
|
* since it copies from the perspective view */
|
2020-04-03 12:51:03 +02:00
|
|
|
region_sync = region;
|
2018-01-28 14:44:42 +11:00
|
|
|
}
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
VR: Initial Virtual Reality support - Milestone 1, Scene Inspection
NOTE: While most of the milestone 1 goals are there, a few smaller features and
improvements are still to be done.
Big picture of this milestone: Initial, OpenXR-based virtual reality support
for users and foundation for advanced use cases.
Maniphest Task: https://developer.blender.org/T71347
The tasks contains more information about this milestone.
To be clear: This is not a feature rich VR implementation, it's focused on the
initial scene inspection use case. We intentionally focused on that, further
features like controller support are part of the next milestone.
- How to use?
Instructions on how to use this are here:
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/How_to_Test
These will be updated and moved to a more official place (likely the manual) soon.
Currently Windows Mixed Reality and Oculus devices are usable. Valve/HTC
headsets don't support the OpenXR standard yet and hence, do not work with this
implementation.
---------------
This is the C-side implementation of the features added for initial VR
support as per milestone 1. A "VR Scene Inspection" Add-on will be
committed separately, to expose the VR functionality in the UI. It also
adds some further features for milestone 1, namely a landmarking system
(stored view locations in the VR space)
Main additions/features:
* Support for rendering viewports to an HMD, with good performance.
* Option to sync the VR view perspective with a fully interactive,
regular 3D View (VR-Mirror).
* Option to disable positional tracking. Keeps the current position (calculated
based on the VR eye center pose) when enabled while a VR session is running.
* Some regular viewport settings for the VR view
* RNA/Python-API to query and set VR session state information.
* WM-XR: Layer tying Ghost-XR to the Blender specific APIs/data
* wmSurface API: drawable, non-window container (manages Ghost-OpenGL and GPU
context)
* DNA/RNA for management of VR session settings
* `--debug-xr` and `--debug-xr-time` commandline options
* Utility batch & config file for using the Oculus runtime on Windows.
* Most VR data is runtime only. The exception is user settings which are saved
to files (`XrSessionSettings`).
* VR support can be disabled through the `WITH_XR_OPENXR` compiler flag.
For architecture and code documentation, see
https://wiki.blender.org/wiki/Source/Interface/XR.
---------------
A few thank you's:
* A huge shoutout to Ray Molenkamp for his help during the project - it would
have not been that successful without him!
* Sebastian Koenig and Simeon Conzendorf for testing and feedback!
* The reviewers, especially Brecht Van Lommel!
* Dalai Felinto for pushing and managing me to get this done ;)
* The OpenXR working group for providing an open standard. I think we're the
first bigger application to adopt OpenXR. Congratulations to them and
ourselves :)
This project started as a Google Summer of Code 2019 project - "Core Support of
Virtual Reality Headsets through OpenXR" (see
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/).
Some further information, including ideas for further improvements can be found
in the final GSoC report:
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/Final_Report
Differential Revisions: D6193, D7098
Reviewed by: Brecht Van Lommel, Jeroen Bakker
2020-03-17 20:20:55 +01:00
|
|
|
if (RV3D_LOCK_FLAGS(rv3d) & RV3D_BOXVIEW) {
|
2023-07-12 18:02:56 +02:00
|
|
|
view3d_boxview_sync(area,
|
|
|
|
|
static_cast<ARegion *>(region_sync ? region_sync : area->regionbase.last));
|
2018-01-28 14:44:42 +11:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-01-28 14:44:42 +11:00
|
|
|
/* ensure locked regions have an axis, locked user views don't make much sense */
|
VR: Initial Virtual Reality support - Milestone 1, Scene Inspection
NOTE: While most of the milestone 1 goals are there, a few smaller features and
improvements are still to be done.
Big picture of this milestone: Initial, OpenXR-based virtual reality support
for users and foundation for advanced use cases.
Maniphest Task: https://developer.blender.org/T71347
The tasks contains more information about this milestone.
To be clear: This is not a feature rich VR implementation, it's focused on the
initial scene inspection use case. We intentionally focused on that, further
features like controller support are part of the next milestone.
- How to use?
Instructions on how to use this are here:
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/How_to_Test
These will be updated and moved to a more official place (likely the manual) soon.
Currently Windows Mixed Reality and Oculus devices are usable. Valve/HTC
headsets don't support the OpenXR standard yet and hence, do not work with this
implementation.
---------------
This is the C-side implementation of the features added for initial VR
support as per milestone 1. A "VR Scene Inspection" Add-on will be
committed separately, to expose the VR functionality in the UI. It also
adds some further features for milestone 1, namely a landmarking system
(stored view locations in the VR space)
Main additions/features:
* Support for rendering viewports to an HMD, with good performance.
* Option to sync the VR view perspective with a fully interactive,
regular 3D View (VR-Mirror).
* Option to disable positional tracking. Keeps the current position (calculated
based on the VR eye center pose) when enabled while a VR session is running.
* Some regular viewport settings for the VR view
* RNA/Python-API to query and set VR session state information.
* WM-XR: Layer tying Ghost-XR to the Blender specific APIs/data
* wmSurface API: drawable, non-window container (manages Ghost-OpenGL and GPU
context)
* DNA/RNA for management of VR session settings
* `--debug-xr` and `--debug-xr-time` commandline options
* Utility batch & config file for using the Oculus runtime on Windows.
* Most VR data is runtime only. The exception is user settings which are saved
to files (`XrSessionSettings`).
* VR support can be disabled through the `WITH_XR_OPENXR` compiler flag.
For architecture and code documentation, see
https://wiki.blender.org/wiki/Source/Interface/XR.
---------------
A few thank you's:
* A huge shoutout to Ray Molenkamp for his help during the project - it would
have not been that successful without him!
* Sebastian Koenig and Simeon Conzendorf for testing and feedback!
* The reviewers, especially Brecht Van Lommel!
* Dalai Felinto for pushing and managing me to get this done ;)
* The OpenXR working group for providing an open standard. I think we're the
first bigger application to adopt OpenXR. Congratulations to them and
ourselves :)
This project started as a Google Summer of Code 2019 project - "Core Support of
Virtual Reality Headsets through OpenXR" (see
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/).
Some further information, including ideas for further improvements can be found
in the final GSoC report:
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/Final_Report
Differential Revisions: D6193, D7098
Reviewed by: Brecht Van Lommel, Jeroen Bakker
2020-03-17 20:20:55 +01:00
|
|
|
if (viewlock & RV3D_LOCK_ROTATION) {
|
2018-01-28 14:44:42 +11:00
|
|
|
int index_qsplit = 0;
|
2024-04-09 14:06:38 +10:00
|
|
|
LISTBASE_FOREACH (ARegion *, region_iter, &area->regionbase) {
|
|
|
|
|
if (region_iter->alignment == RGN_ALIGN_QSPLIT) {
|
|
|
|
|
rv3d = static_cast<RegionView3D *>(region_iter->regiondata);
|
2018-01-28 14:44:42 +11:00
|
|
|
if (rv3d->viewlock) {
|
2020-02-09 11:50:25 +11:00
|
|
|
if (!RV3D_VIEW_IS_AXIS(rv3d->view) || (rv3d->view_axis_roll != RV3D_VIEW_AXIS_ROLL_0)) {
|
2018-01-28 14:44:42 +11:00
|
|
|
rv3d->view = ED_view3d_lock_view_from_index(index_qsplit);
|
2020-02-09 11:50:25 +11:00
|
|
|
rv3d->view_axis_roll = RV3D_VIEW_AXIS_ROLL_0;
|
2018-01-28 14:44:42 +11:00
|
|
|
rv3d->persp = RV3D_ORTHO;
|
|
|
|
|
ED_view3d_lock(rv3d);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
index_qsplit++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-04-03 13:25:03 +02:00
|
|
|
ED_area_tag_redraw(area);
|
2018-01-28 14:44:42 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** \} */
|
|
|
|
|
|
2023-03-17 14:40:43 +11:00
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name View Auto-Depth Last State Access
|
|
|
|
|
*
|
2023-12-15 22:54:55 +11:00
|
|
|
* Calling consecutive trackpad gestures reuses the previous offset to prevent
|
|
|
|
|
* each trackpad event using a different offset, see: #103263.
|
2023-03-17 14:40:43 +11:00
|
|
|
* \{ */
|
|
|
|
|
|
|
|
|
|
static const char *view3d_autodepth_last_id = "view3d_autodist_last";
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Auto-depth values for #ED_view3d_autodist_last_check and related functions.
|
|
|
|
|
*/
|
2023-07-12 18:02:56 +02:00
|
|
|
struct View3D_AutoDistLast {
|
2023-03-17 14:40:43 +11:00
|
|
|
float ofs[3];
|
|
|
|
|
bool has_depth;
|
2023-07-12 18:02:56 +02:00
|
|
|
};
|
2023-03-17 14:40:43 +11:00
|
|
|
|
|
|
|
|
bool ED_view3d_autodist_last_check(wmWindow *win, const wmEvent *event)
|
|
|
|
|
{
|
|
|
|
|
if (event->flag & WM_EVENT_IS_CONSECUTIVE) {
|
2023-07-12 18:02:56 +02:00
|
|
|
const View3D_AutoDistLast *autodepth_last = static_cast<const View3D_AutoDistLast *>(
|
|
|
|
|
WM_event_consecutive_data_get(win, view3d_autodepth_last_id));
|
2023-03-17 14:40:43 +11:00
|
|
|
if (autodepth_last) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ED_view3d_autodist_last_clear(wmWindow *win)
|
|
|
|
|
{
|
|
|
|
|
WM_event_consecutive_data_free(win);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ED_view3d_autodist_last_set(wmWindow *win,
|
|
|
|
|
const wmEvent *event,
|
|
|
|
|
const float ofs[3],
|
|
|
|
|
const bool has_depth)
|
|
|
|
|
{
|
|
|
|
|
ED_view3d_autodist_last_clear(win);
|
|
|
|
|
|
|
|
|
|
if (WM_event_consecutive_gesture_test(event)) {
|
2023-07-12 18:02:56 +02:00
|
|
|
View3D_AutoDistLast *autodepth_last = static_cast<View3D_AutoDistLast *>(
|
|
|
|
|
MEM_callocN(sizeof(*autodepth_last), __func__));
|
2023-03-17 14:40:43 +11:00
|
|
|
|
|
|
|
|
autodepth_last->has_depth = has_depth;
|
|
|
|
|
copy_v3_v3(autodepth_last->ofs, ofs);
|
|
|
|
|
|
|
|
|
|
WM_event_consecutive_data_set(win, view3d_autodepth_last_id, autodepth_last);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool ED_view3d_autodist_last_get(wmWindow *win, float r_ofs[3])
|
|
|
|
|
{
|
2023-07-12 18:02:56 +02:00
|
|
|
const View3D_AutoDistLast *autodepth_last = static_cast<const View3D_AutoDistLast *>(
|
|
|
|
|
WM_event_consecutive_data_get(win, view3d_autodepth_last_id));
|
2023-03-17 14:40:43 +11:00
|
|
|
/* #ED_view3d_autodist_last_check should be called first. */
|
|
|
|
|
BLI_assert(autodepth_last);
|
2023-07-12 18:02:56 +02:00
|
|
|
if (autodepth_last == nullptr) {
|
2023-03-17 14:40:43 +11:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (autodepth_last->has_depth == false) {
|
|
|
|
|
zero_v3(r_ofs);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
copy_v3_v3(r_ofs, autodepth_last->ofs);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** \} */
|
|
|
|
|
|
2018-01-28 14:44:42 +11:00
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name View Auto-Depth Utilities
|
|
|
|
|
* \{ */
|
|
|
|
|
|
2020-03-06 16:56:42 +01:00
|
|
|
static float view_autodist_depth_margin(ARegion *region, const int mval[2], int margin)
|
2018-01-28 14:44:42 +11:00
|
|
|
{
|
|
|
|
|
rcti rect;
|
|
|
|
|
if (margin == 0) {
|
|
|
|
|
/* Get Z Depths, needed for perspective, nice for ortho */
|
|
|
|
|
rect.xmin = mval[0];
|
|
|
|
|
rect.ymin = mval[1];
|
|
|
|
|
rect.xmax = mval[0] + 1;
|
|
|
|
|
rect.ymax = mval[1] + 1;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
BLI_rcti_init_pt_radius(&rect, mval, margin);
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2021-01-25 17:22:52 -06:00
|
|
|
ViewDepths depth_temp = {0};
|
2021-06-21 16:25:53 -03:00
|
|
|
view3d_depths_rect_create(region, &rect, &depth_temp);
|
2021-01-25 17:22:52 -06:00
|
|
|
float depth_close = view3d_depth_near(&depth_temp);
|
2021-06-22 08:12:59 -03:00
|
|
|
MEM_SAFE_FREE(depth_temp.depths);
|
2018-01-28 14:44:42 +11:00
|
|
|
return depth_close;
|
|
|
|
|
}
|
|
|
|
|
|
2024-03-07 15:16:41 +01:00
|
|
|
bool ED_view3d_autodist(ARegion *region,
|
2018-06-08 14:38:57 +02:00
|
|
|
View3D *v3d,
|
2018-01-28 14:44:42 +11:00
|
|
|
const int mval[2],
|
|
|
|
|
float mouse_worldloc[3],
|
|
|
|
|
const float fallback_depth_pt[3])
|
|
|
|
|
{
|
|
|
|
|
float depth_close;
|
|
|
|
|
int margin_arr[] = {0, 2, 4};
|
|
|
|
|
bool depth_ok = false;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-01-28 14:44:42 +11:00
|
|
|
/* Attempt with low margin's first */
|
2021-01-25 17:22:52 -06:00
|
|
|
int i = 0;
|
2018-01-28 14:44:42 +11:00
|
|
|
do {
|
2020-03-06 16:56:42 +01:00
|
|
|
depth_close = view_autodist_depth_margin(region, mval, margin_arr[i++] * U.pixelsize);
|
2018-01-28 14:44:42 +11:00
|
|
|
depth_ok = (depth_close != FLT_MAX);
|
|
|
|
|
} while ((depth_ok == false) && (i < ARRAY_SIZE(margin_arr)));
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-01-28 14:44:42 +11:00
|
|
|
if (depth_ok) {
|
2023-07-14 12:23:37 +10:00
|
|
|
float centx = float(mval[0]) + 0.5f;
|
|
|
|
|
float centy = float(mval[1]) + 0.5f;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2021-06-01 12:49:20 +10:00
|
|
|
if (ED_view3d_unproject_v3(region, centx, centy, depth_close, mouse_worldloc)) {
|
2018-01-28 14:44:42 +11:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-01-28 14:44:42 +11:00
|
|
|
if (fallback_depth_pt) {
|
2020-03-06 16:56:42 +01:00
|
|
|
ED_view3d_win_to_3d_int(v3d, region, fallback_depth_pt, mval, mouse_worldloc);
|
2018-01-28 14:44:42 +11:00
|
|
|
return true;
|
|
|
|
|
}
|
2020-07-03 17:18:56 +02:00
|
|
|
return false;
|
2018-01-28 14:44:42 +11:00
|
|
|
}
|
|
|
|
|
|
2020-07-13 11:27:09 +02:00
|
|
|
bool ED_view3d_autodist_simple(ARegion *region,
|
|
|
|
|
const int mval[2],
|
|
|
|
|
float mouse_worldloc[3],
|
|
|
|
|
int margin,
|
|
|
|
|
const float *force_depth)
|
2018-01-28 14:44:42 +11:00
|
|
|
{
|
|
|
|
|
/* Get Z Depths, needed for perspective, nice for ortho */
|
2021-01-25 17:22:52 -06:00
|
|
|
float depth;
|
2019-03-26 21:16:47 +11:00
|
|
|
if (force_depth) {
|
2018-01-28 14:44:42 +11:00
|
|
|
depth = *force_depth;
|
2019-03-26 21:16:47 +11:00
|
|
|
}
|
|
|
|
|
else {
|
2020-03-06 16:56:42 +01:00
|
|
|
depth = view_autodist_depth_margin(region, mval, margin);
|
2019-03-26 21:16:47 +11:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-03-26 21:16:47 +11:00
|
|
|
if (depth == FLT_MAX) {
|
2018-01-28 14:44:42 +11:00
|
|
|
return false;
|
2019-03-26 21:16:47 +11:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-07-14 12:23:37 +10:00
|
|
|
float centx = float(mval[0]) + 0.5f;
|
|
|
|
|
float centy = float(mval[1]) + 0.5f;
|
2021-06-01 12:49:20 +10:00
|
|
|
return ED_view3d_unproject_v3(region, centx, centy, depth, mouse_worldloc);
|
2018-01-28 14:44:42 +11:00
|
|
|
}
|
|
|
|
|
|
2023-07-27 12:04:18 +10:00
|
|
|
static bool depth_segment_cb(int x, int y, void *user_data)
|
2018-01-28 14:44:42 +11:00
|
|
|
{
|
2023-07-12 18:02:56 +02:00
|
|
|
struct UserData {
|
2021-11-02 12:33:28 -03:00
|
|
|
const ViewDepths *vd;
|
2018-01-28 14:44:42 +11:00
|
|
|
int margin;
|
|
|
|
|
float depth;
|
2023-07-27 12:04:18 +10:00
|
|
|
} *data = static_cast<UserData *>(user_data);
|
2018-01-28 14:44:42 +11:00
|
|
|
int mval[2];
|
|
|
|
|
float depth;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-01-28 14:44:42 +11:00
|
|
|
mval[0] = x;
|
|
|
|
|
mval[1] = y;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2021-11-02 12:33:28 -03:00
|
|
|
if (ED_view3d_depth_read_cached(data->vd, mval, data->margin, &depth)) {
|
2018-01-28 14:44:42 +11:00
|
|
|
data->depth = depth;
|
2020-09-02 19:10:18 +02:00
|
|
|
return false;
|
2018-01-28 14:44:42 +11:00
|
|
|
}
|
2020-09-02 19:10:18 +02:00
|
|
|
return true;
|
2018-01-28 14:44:42 +11:00
|
|
|
}
|
|
|
|
|
|
2021-11-02 12:33:28 -03:00
|
|
|
bool ED_view3d_depth_read_cached_seg(
|
2024-09-26 15:02:59 +10:00
|
|
|
const ViewDepths *vd, const int mval_sta[2], const int mval_end[2], int margin, float *r_depth)
|
2018-01-28 14:44:42 +11:00
|
|
|
{
|
|
|
|
|
struct {
|
2021-11-02 12:33:28 -03:00
|
|
|
const ViewDepths *vd;
|
2018-01-28 14:44:42 +11:00
|
|
|
int margin;
|
|
|
|
|
float depth;
|
2023-07-12 18:02:56 +02:00
|
|
|
} data = {nullptr};
|
2018-01-28 14:44:42 +11:00
|
|
|
int p1[2];
|
|
|
|
|
int p2[2];
|
|
|
|
|
|
2021-11-02 12:33:28 -03:00
|
|
|
data.vd = vd;
|
2018-01-28 14:44:42 +11:00
|
|
|
data.margin = margin;
|
2021-11-25 10:17:31 -03:00
|
|
|
data.depth = 1.0f;
|
2018-01-28 14:44:42 +11:00
|
|
|
|
|
|
|
|
copy_v2_v2_int(p1, mval_sta);
|
|
|
|
|
copy_v2_v2_int(p2, mval_end);
|
|
|
|
|
|
|
|
|
|
BLI_bitmap_draw_2d_line_v2v2i(p1, p2, depth_segment_cb, &data);
|
|
|
|
|
|
2024-09-26 15:02:59 +10:00
|
|
|
*r_depth = data.depth;
|
2018-01-28 14:44:42 +11:00
|
|
|
|
2024-09-26 15:02:59 +10:00
|
|
|
return (*r_depth != 1.0f);
|
2018-01-28 14:44:42 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** \} */
|
|
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name View Radius/Distance Utilities
|
|
|
|
|
*
|
|
|
|
|
* Use to calculate a distance to a point based on its radius.
|
|
|
|
|
* \{ */
|
|
|
|
|
|
|
|
|
|
float ED_view3d_radius_to_dist_persp(const float angle, const float radius)
|
|
|
|
|
{
|
|
|
|
|
return radius * (1.0f / tanf(angle / 2.0f));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
float ED_view3d_radius_to_dist_ortho(const float lens, const float radius)
|
|
|
|
|
{
|
|
|
|
|
return radius / (DEFAULT_SENSOR_WIDTH / lens);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
float ED_view3d_radius_to_dist(const View3D *v3d,
|
2020-03-06 16:56:42 +01:00
|
|
|
const ARegion *region,
|
2023-06-03 08:36:28 +10:00
|
|
|
const Depsgraph *depsgraph,
|
2018-01-28 14:44:42 +11:00
|
|
|
const char persp,
|
|
|
|
|
const bool use_aspect,
|
|
|
|
|
const float radius)
|
|
|
|
|
{
|
|
|
|
|
float dist;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-01-28 14:44:42 +11:00
|
|
|
BLI_assert(ELEM(persp, RV3D_ORTHO, RV3D_PERSP, RV3D_CAMOB));
|
|
|
|
|
BLI_assert((persp != RV3D_CAMOB) || v3d->camera);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-01-28 14:44:42 +11:00
|
|
|
if (persp == RV3D_ORTHO) {
|
|
|
|
|
dist = ED_view3d_radius_to_dist_ortho(v3d->lens, radius);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
float lens, sensor_size, zoom;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-01-28 14:44:42 +11:00
|
|
|
if (persp == RV3D_CAMOB) {
|
|
|
|
|
CameraParams params;
|
|
|
|
|
BKE_camera_params_init(¶ms);
|
2019-02-16 12:21:44 +11:00
|
|
|
params.clip_start = v3d->clip_start;
|
|
|
|
|
params.clip_end = v3d->clip_end;
|
2018-05-25 11:05:51 +02:00
|
|
|
Object *camera_eval = DEG_get_evaluated_object(depsgraph, v3d->camera);
|
|
|
|
|
BKE_camera_params_from_object(¶ms, camera_eval);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-01-28 14:44:42 +11:00
|
|
|
lens = params.lens;
|
|
|
|
|
sensor_size = BKE_camera_sensor_size(params.sensor_fit, params.sensor_x, params.sensor_y);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-01-28 14:44:42 +11:00
|
|
|
/* ignore 'rv3d->camzoom' because we want to fit to the cameras frame */
|
|
|
|
|
zoom = CAMERA_PARAM_ZOOM_INIT_CAMOB;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
lens = v3d->lens;
|
|
|
|
|
sensor_size = DEFAULT_SENSOR_WIDTH;
|
|
|
|
|
zoom = CAMERA_PARAM_ZOOM_INIT_PERSP;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2021-01-25 17:22:52 -06:00
|
|
|
float angle = focallength_to_fov(lens, sensor_size);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-01-15 23:24:20 +11:00
|
|
|
/* zoom influences lens, correct this by scaling the angle as a distance
|
|
|
|
|
* (by the zoom-level) */
|
2018-01-28 14:44:42 +11:00
|
|
|
angle = atanf(tanf(angle / 2.0f) * zoom) * 2.0f;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-01-28 14:44:42 +11:00
|
|
|
dist = ED_view3d_radius_to_dist_persp(angle, radius);
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-01-28 14:44:42 +11:00
|
|
|
if (use_aspect) {
|
2023-07-12 18:02:56 +02:00
|
|
|
const RegionView3D *rv3d = static_cast<const RegionView3D *>(region->regiondata);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-01-28 14:44:42 +11:00
|
|
|
float winx, winy;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-01-28 14:44:42 +11:00
|
|
|
if (persp == RV3D_CAMOB) {
|
|
|
|
|
/* camera frame x/y in pixels */
|
2020-03-06 16:56:42 +01:00
|
|
|
winx = region->winx / rv3d->viewcamtexcofac[0];
|
|
|
|
|
winy = region->winy / rv3d->viewcamtexcofac[1];
|
2018-01-28 14:44:42 +11:00
|
|
|
}
|
|
|
|
|
else {
|
2020-03-06 16:56:42 +01:00
|
|
|
winx = region->winx;
|
|
|
|
|
winy = region->winy;
|
2018-01-28 14:44:42 +11:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-01-28 14:44:42 +11:00
|
|
|
if (winx && winy) {
|
|
|
|
|
float aspect = winx / winy;
|
|
|
|
|
if (aspect < 1.0f) {
|
|
|
|
|
aspect = 1.0f / aspect;
|
|
|
|
|
}
|
|
|
|
|
dist *= aspect;
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-01-28 14:44:42 +11:00
|
|
|
return dist;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** \} */
|
|
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name View Distance Utilities
|
|
|
|
|
* \{ */
|
|
|
|
|
|
2020-08-02 17:17:31 +10:00
|
|
|
float ED_view3d_offset_distance(const float mat[4][4],
|
|
|
|
|
const float ofs[3],
|
|
|
|
|
const float fallback_dist)
|
2018-01-28 14:44:42 +11:00
|
|
|
{
|
|
|
|
|
float pos[4] = {0.0f, 0.0f, 0.0f, 1.0f};
|
|
|
|
|
float dir[4] = {0.0f, 0.0f, 1.0f, 0.0f};
|
|
|
|
|
|
|
|
|
|
mul_m4_v4(mat, pos);
|
|
|
|
|
add_v3_v3(pos, ofs);
|
|
|
|
|
mul_m4_v4(mat, dir);
|
|
|
|
|
normalize_v3(dir);
|
|
|
|
|
|
2021-01-25 17:22:52 -06:00
|
|
|
float dist = dot_v3v3(pos, dir);
|
2018-01-28 14:44:42 +11:00
|
|
|
|
|
|
|
|
if ((dist < FLT_EPSILON) && (fallback_dist != 0.0f)) {
|
|
|
|
|
dist = fallback_dist;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return dist;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ED_view3d_distance_set(RegionView3D *rv3d, const float dist)
|
|
|
|
|
{
|
|
|
|
|
float viewinv[4];
|
|
|
|
|
float tvec[3];
|
|
|
|
|
|
|
|
|
|
BLI_assert(dist >= 0.0f);
|
|
|
|
|
|
|
|
|
|
copy_v3_fl3(tvec, 0.0f, 0.0f, rv3d->dist - dist);
|
2023-07-12 18:02:56 +02:00
|
|
|
/* rv3d->viewinv isn't always valid */
|
2018-01-28 14:44:42 +11:00
|
|
|
#if 0
|
|
|
|
|
mul_mat3_m4_v3(rv3d->viewinv, tvec);
|
|
|
|
|
#else
|
|
|
|
|
invert_qt_qt_normalized(viewinv, rv3d->viewquat);
|
|
|
|
|
mul_qt_v3(viewinv, tvec);
|
|
|
|
|
#endif
|
|
|
|
|
sub_v3_v3(rv3d->ofs, tvec);
|
|
|
|
|
|
|
|
|
|
rv3d->dist = dist;
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-07 18:27:21 +10:00
|
|
|
bool ED_view3d_distance_set_from_location(RegionView3D *rv3d,
|
|
|
|
|
const float dist_co[3],
|
|
|
|
|
const float dist_min)
|
|
|
|
|
{
|
|
|
|
|
float viewinv[4];
|
|
|
|
|
invert_qt_qt_normalized(viewinv, rv3d->viewquat);
|
|
|
|
|
|
|
|
|
|
float tvec[3] = {0.0f, 0.0f, -1.0f};
|
|
|
|
|
mul_qt_v3(viewinv, tvec);
|
|
|
|
|
|
|
|
|
|
float dist_co_local[3];
|
|
|
|
|
negate_v3_v3(dist_co_local, rv3d->ofs);
|
|
|
|
|
sub_v3_v3v3(dist_co_local, dist_co, dist_co_local);
|
|
|
|
|
const float delta = dot_v3v3(tvec, dist_co_local);
|
|
|
|
|
const float dist_new = rv3d->dist + delta;
|
|
|
|
|
if (dist_new >= dist_min) {
|
|
|
|
|
madd_v3_v3fl(rv3d->ofs, tvec, -delta);
|
|
|
|
|
rv3d->dist = dist_new;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2018-01-28 14:44:42 +11:00
|
|
|
/** \} */
|
|
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name View Axis Utilities
|
|
|
|
|
* \{ */
|
2020-02-09 11:50:25 +11:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Lookup by axis-view, axis-roll.
|
|
|
|
|
*/
|
|
|
|
|
static float view3d_quat_axis[6][4][4] = {
|
|
|
|
|
/* RV3D_VIEW_FRONT */
|
|
|
|
|
{
|
|
|
|
|
{M_SQRT1_2, -M_SQRT1_2, 0.0f, 0.0f},
|
|
|
|
|
{0.5f, -0.5f, -0.5f, 0.5f},
|
|
|
|
|
{0, 0, -M_SQRT1_2, M_SQRT1_2},
|
|
|
|
|
{-0.5f, 0.5f, -0.5f, 0.5f},
|
2023-07-12 18:02:56 +02:00
|
|
|
}, /* RV3D_VIEW_BACK */
|
2020-02-09 11:50:25 +11:00
|
|
|
{
|
|
|
|
|
{0.0f, 0.0f, -M_SQRT1_2, -M_SQRT1_2},
|
|
|
|
|
{0.5f, 0.5f, -0.5f, -0.5f},
|
|
|
|
|
{M_SQRT1_2, M_SQRT1_2, 0, 0},
|
|
|
|
|
{0.5f, 0.5f, 0.5f, 0.5f},
|
2023-07-12 18:02:56 +02:00
|
|
|
}, /* RV3D_VIEW_LEFT */
|
2020-02-09 11:50:25 +11:00
|
|
|
{
|
|
|
|
|
{0.5f, -0.5f, 0.5f, 0.5f},
|
|
|
|
|
{0, -M_SQRT1_2, 0.0f, M_SQRT1_2},
|
|
|
|
|
{-0.5f, -0.5f, -0.5f, 0.5f},
|
|
|
|
|
{-M_SQRT1_2, 0, -M_SQRT1_2, 0},
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
/* RV3D_VIEW_RIGHT */
|
|
|
|
|
{
|
|
|
|
|
{0.5f, -0.5f, -0.5f, -0.5f},
|
|
|
|
|
{M_SQRT1_2, 0, -M_SQRT1_2, 0},
|
|
|
|
|
{0.5f, 0.5f, -0.5f, 0.5f},
|
|
|
|
|
{0, M_SQRT1_2, 0, M_SQRT1_2},
|
2023-07-12 18:02:56 +02:00
|
|
|
}, /* RV3D_VIEW_TOP */
|
2020-02-09 11:50:25 +11:00
|
|
|
{
|
|
|
|
|
{1.0f, 0.0f, 0.0f, 0.0f},
|
|
|
|
|
{M_SQRT1_2, 0, 0, M_SQRT1_2},
|
|
|
|
|
{0, 0, 0, 1},
|
|
|
|
|
{-M_SQRT1_2, 0, 0, M_SQRT1_2},
|
2023-07-12 18:02:56 +02:00
|
|
|
}, /* RV3D_VIEW_BOTTOM */
|
2020-02-09 11:50:25 +11:00
|
|
|
{
|
|
|
|
|
{0.0f, -1.0f, 0.0f, 0.0f},
|
|
|
|
|
{0, -M_SQRT1_2, -M_SQRT1_2, 0},
|
|
|
|
|
{0, 0, -1, 0},
|
|
|
|
|
{0, M_SQRT1_2, -M_SQRT1_2, 0},
|
|
|
|
|
},
|
|
|
|
|
|
2018-01-28 14:44:42 +11:00
|
|
|
};
|
|
|
|
|
|
2020-08-02 17:17:31 +10:00
|
|
|
bool ED_view3d_quat_from_axis_view(const char view, const char view_axis_roll, float r_quat[4])
|
2018-01-28 14:44:42 +11:00
|
|
|
{
|
2020-02-09 11:50:25 +11:00
|
|
|
BLI_assert(view_axis_roll <= RV3D_VIEW_AXIS_ROLL_270);
|
2018-01-28 14:44:42 +11:00
|
|
|
if (RV3D_VIEW_IS_AXIS(view)) {
|
2020-08-02 17:17:31 +10:00
|
|
|
copy_qt_qt(r_quat, view3d_quat_axis[view - RV3D_VIEW_FRONT][view_axis_roll]);
|
2018-01-28 14:44:42 +11:00
|
|
|
return true;
|
|
|
|
|
}
|
2020-07-03 17:18:56 +02:00
|
|
|
return false;
|
2018-01-28 14:44:42 +11:00
|
|
|
}
|
|
|
|
|
|
2020-02-09 11:50:25 +11:00
|
|
|
bool ED_view3d_quat_to_axis_view(const float quat[4],
|
|
|
|
|
const float epsilon,
|
|
|
|
|
char *r_view,
|
|
|
|
|
char *r_view_axis_roll)
|
2018-01-28 14:44:42 +11:00
|
|
|
{
|
2020-02-09 11:50:25 +11:00
|
|
|
*r_view = RV3D_VIEW_USER;
|
|
|
|
|
*r_view_axis_roll = RV3D_VIEW_AXIS_ROLL_0;
|
2018-01-28 14:44:42 +11:00
|
|
|
|
2022-05-19 13:44:36 +10:00
|
|
|
/* Quaternion values are all unit length. */
|
|
|
|
|
|
|
|
|
|
if (epsilon < M_PI_4) {
|
|
|
|
|
/* Under 45 degrees, just pick the closest value. */
|
|
|
|
|
for (int view = RV3D_VIEW_FRONT; view <= RV3D_VIEW_BOTTOM; view++) {
|
|
|
|
|
for (int view_axis_roll = RV3D_VIEW_AXIS_ROLL_0; view_axis_roll <= RV3D_VIEW_AXIS_ROLL_270;
|
|
|
|
|
view_axis_roll++)
|
|
|
|
|
{
|
|
|
|
|
if (fabsf(angle_signed_qtqt(
|
|
|
|
|
quat, view3d_quat_axis[view - RV3D_VIEW_FRONT][view_axis_roll])) < epsilon)
|
|
|
|
|
{
|
|
|
|
|
*r_view = view;
|
|
|
|
|
*r_view_axis_roll = view_axis_roll;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
/* Epsilon over 45 degrees, check all & find use the closest. */
|
|
|
|
|
float delta_best = FLT_MAX;
|
|
|
|
|
for (int view = RV3D_VIEW_FRONT; view <= RV3D_VIEW_BOTTOM; view++) {
|
|
|
|
|
for (int view_axis_roll = RV3D_VIEW_AXIS_ROLL_0; view_axis_roll <= RV3D_VIEW_AXIS_ROLL_270;
|
|
|
|
|
view_axis_roll++)
|
|
|
|
|
{
|
|
|
|
|
const float delta_test = fabsf(
|
|
|
|
|
angle_signed_qtqt(quat, view3d_quat_axis[view - RV3D_VIEW_FRONT][view_axis_roll]));
|
|
|
|
|
if (delta_best > delta_test) {
|
|
|
|
|
delta_best = delta_test;
|
|
|
|
|
*r_view = view;
|
|
|
|
|
*r_view_axis_roll = view_axis_roll;
|
|
|
|
|
}
|
2020-02-09 11:50:25 +11:00
|
|
|
}
|
2018-01-28 14:44:42 +11:00
|
|
|
}
|
2022-05-19 13:44:36 +10:00
|
|
|
if (*r_view != RV3D_VIEW_USER) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2018-01-28 14:44:42 +11:00
|
|
|
}
|
|
|
|
|
|
2020-02-09 11:50:25 +11:00
|
|
|
return false;
|
2020-02-09 11:32:08 +11:00
|
|
|
}
|
|
|
|
|
|
2022-05-19 13:06:45 +10:00
|
|
|
bool ED_view3d_quat_to_axis_view_and_reset_quat(float quat[4],
|
|
|
|
|
const float epsilon,
|
|
|
|
|
char *r_view,
|
|
|
|
|
char *r_view_axis_roll)
|
|
|
|
|
{
|
|
|
|
|
const bool is_axis_view = ED_view3d_quat_to_axis_view(quat, epsilon, r_view, r_view_axis_roll);
|
|
|
|
|
if (is_axis_view) {
|
|
|
|
|
/* Reset `quat` to it's view axis, so axis-aligned views are always *exactly* aligned. */
|
|
|
|
|
BLI_assert(*r_view != RV3D_VIEW_USER);
|
|
|
|
|
ED_view3d_quat_from_axis_view(*r_view, *r_view_axis_roll, quat);
|
|
|
|
|
}
|
|
|
|
|
return is_axis_view;
|
|
|
|
|
}
|
|
|
|
|
|
2018-01-28 14:44:42 +11:00
|
|
|
char ED_view3d_lock_view_from_index(int index)
|
|
|
|
|
{
|
|
|
|
|
switch (index) {
|
|
|
|
|
case 0:
|
|
|
|
|
return RV3D_VIEW_FRONT;
|
|
|
|
|
case 1:
|
|
|
|
|
return RV3D_VIEW_TOP;
|
|
|
|
|
case 2:
|
|
|
|
|
return RV3D_VIEW_RIGHT;
|
|
|
|
|
default:
|
|
|
|
|
return RV3D_VIEW_USER;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
char ED_view3d_axis_view_opposite(char view)
|
|
|
|
|
{
|
|
|
|
|
switch (view) {
|
|
|
|
|
case RV3D_VIEW_FRONT:
|
|
|
|
|
return RV3D_VIEW_BACK;
|
|
|
|
|
case RV3D_VIEW_BACK:
|
|
|
|
|
return RV3D_VIEW_FRONT;
|
|
|
|
|
case RV3D_VIEW_LEFT:
|
|
|
|
|
return RV3D_VIEW_RIGHT;
|
|
|
|
|
case RV3D_VIEW_RIGHT:
|
|
|
|
|
return RV3D_VIEW_LEFT;
|
|
|
|
|
case RV3D_VIEW_TOP:
|
|
|
|
|
return RV3D_VIEW_BOTTOM;
|
|
|
|
|
case RV3D_VIEW_BOTTOM:
|
|
|
|
|
return RV3D_VIEW_TOP;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-01-28 14:44:42 +11:00
|
|
|
return RV3D_VIEW_USER;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool ED_view3d_lock(RegionView3D *rv3d)
|
|
|
|
|
{
|
2020-02-09 11:50:25 +11:00
|
|
|
return ED_view3d_quat_from_axis_view(rv3d->view, rv3d->view_axis_roll, rv3d->viewquat);
|
2018-01-28 14:44:42 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** \} */
|
|
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name View Transform Utilities
|
|
|
|
|
* \{ */
|
|
|
|
|
|
2020-07-13 11:27:09 +02:00
|
|
|
void ED_view3d_from_m4(const float mat[4][4], float ofs[3], float quat[4], const float *dist)
|
2018-01-28 14:44:42 +11:00
|
|
|
{
|
|
|
|
|
float nmat[3][3];
|
|
|
|
|
|
|
|
|
|
/* dist depends on offset */
|
2023-07-12 18:02:56 +02:00
|
|
|
BLI_assert(dist == nullptr || ofs != nullptr);
|
2018-01-28 14:44:42 +11:00
|
|
|
|
|
|
|
|
copy_m3_m4(nmat, mat);
|
|
|
|
|
normalize_m3(nmat);
|
|
|
|
|
|
|
|
|
|
/* Offset */
|
2019-03-26 21:16:47 +11:00
|
|
|
if (ofs) {
|
2018-01-28 14:44:42 +11:00
|
|
|
negate_v3_v3(ofs, mat[3]);
|
2019-03-26 21:16:47 +11:00
|
|
|
}
|
2018-01-28 14:44:42 +11:00
|
|
|
|
|
|
|
|
/* Quat */
|
|
|
|
|
if (quat) {
|
|
|
|
|
mat3_normalized_to_quat(quat, nmat);
|
|
|
|
|
invert_qt_normalized(quat);
|
|
|
|
|
}
|
2022-08-25 12:45:43 +10:00
|
|
|
|
|
|
|
|
if (ofs && dist) {
|
|
|
|
|
madd_v3_v3fl(ofs, nmat[2], *dist);
|
|
|
|
|
}
|
2018-01-28 14:44:42 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ED_view3d_to_m4(float mat[4][4], const float ofs[3], const float quat[4], const float dist)
|
|
|
|
|
{
|
2020-08-07 22:36:11 +10:00
|
|
|
const float iviewquat[4] = {-quat[0], quat[1], quat[2], quat[3]};
|
2018-01-28 14:44:42 +11:00
|
|
|
float dvec[3] = {0.0f, 0.0f, dist};
|
|
|
|
|
|
|
|
|
|
quat_to_mat4(mat, iviewquat);
|
|
|
|
|
mul_mat3_m4_v3(mat, dvec);
|
|
|
|
|
sub_v3_v3v3(mat[3], dvec, ofs);
|
|
|
|
|
}
|
|
|
|
|
|
2024-03-28 20:57:47 +11:00
|
|
|
void ED_view3d_from_object(
|
|
|
|
|
const Object *ob, float ofs[3], float quat[4], const float *dist, float *lens)
|
2018-01-28 14:44:42 +11:00
|
|
|
{
|
2024-02-14 16:14:49 +01:00
|
|
|
ED_view3d_from_m4(ob->object_to_world().ptr(), ofs, quat, dist);
|
2018-01-28 14:44:42 +11:00
|
|
|
|
|
|
|
|
if (lens) {
|
|
|
|
|
CameraParams params;
|
|
|
|
|
|
|
|
|
|
BKE_camera_params_init(¶ms);
|
|
|
|
|
BKE_camera_params_from_object(¶ms, ob);
|
|
|
|
|
*lens = params.lens;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-05-21 20:29:00 +02:00
|
|
|
void ED_view3d_to_object(const Depsgraph *depsgraph,
|
|
|
|
|
Object *ob,
|
|
|
|
|
const float ofs[3],
|
|
|
|
|
const float quat[4],
|
|
|
|
|
const float dist)
|
2018-01-28 14:44:42 +11:00
|
|
|
{
|
|
|
|
|
float mat[4][4];
|
|
|
|
|
ED_view3d_to_m4(mat, ofs, quat, dist);
|
2018-05-21 20:29:00 +02:00
|
|
|
|
|
|
|
|
Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
|
2018-05-22 07:31:11 +02:00
|
|
|
BKE_object_apply_mat4_ex(ob, mat, ob_eval->parent, ob_eval->parentinv, true);
|
2018-01-28 14:44:42 +11:00
|
|
|
}
|
|
|
|
|
|
2023-07-20 11:30:25 +10:00
|
|
|
static bool view3d_camera_to_view_selected_impl(Main *bmain,
|
2022-04-04 16:16:36 -03:00
|
|
|
Depsgraph *depsgraph,
|
|
|
|
|
const Scene *scene,
|
|
|
|
|
Object *camera_ob,
|
|
|
|
|
float *r_clip_start,
|
|
|
|
|
float *r_clip_end)
|
2020-12-14 12:48:16 +01:00
|
|
|
{
|
|
|
|
|
Object *camera_ob_eval = DEG_get_evaluated_object(depsgraph, camera_ob);
|
|
|
|
|
float co[3]; /* the new location to apply */
|
|
|
|
|
float scale; /* only for ortho cameras */
|
|
|
|
|
|
2022-04-04 16:16:36 -03:00
|
|
|
if (BKE_camera_view_frame_fit_to_scene(
|
|
|
|
|
depsgraph, scene, camera_ob_eval, co, &scale, r_clip_start, r_clip_end))
|
|
|
|
|
{
|
2020-12-14 12:48:16 +01:00
|
|
|
ObjectTfmProtectedChannels obtfm;
|
|
|
|
|
float obmat_new[4][4];
|
2022-07-13 16:18:14 +10:00
|
|
|
bool is_ortho_camera = false;
|
2020-12-14 12:48:16 +01:00
|
|
|
|
|
|
|
|
if ((camera_ob_eval->type == OB_CAMERA) &&
|
2024-01-02 18:12:54 +01:00
|
|
|
(((Camera *)camera_ob_eval->data)->type == CAM_ORTHO))
|
|
|
|
|
{
|
2020-12-14 12:48:16 +01:00
|
|
|
((Camera *)camera_ob->data)->ortho_scale = scale;
|
2022-07-13 16:18:14 +10:00
|
|
|
is_ortho_camera = true;
|
2020-12-14 12:48:16 +01:00
|
|
|
}
|
|
|
|
|
|
2024-02-14 16:14:49 +01:00
|
|
|
copy_m4_m4(obmat_new, camera_ob_eval->object_to_world().ptr());
|
2020-12-14 12:48:16 +01:00
|
|
|
copy_v3_v3(obmat_new[3], co);
|
|
|
|
|
|
|
|
|
|
/* only touch location */
|
|
|
|
|
BKE_object_tfm_protected_backup(camera_ob, &obtfm);
|
|
|
|
|
BKE_object_apply_mat4(camera_ob, obmat_new, true, true);
|
|
|
|
|
BKE_object_tfm_protected_restore(camera_ob, &obtfm, OB_LOCK_SCALE | OB_LOCK_ROT4D);
|
|
|
|
|
|
|
|
|
|
/* notifiers */
|
|
|
|
|
DEG_id_tag_update_ex(bmain, &camera_ob->id, ID_RECALC_TRANSFORM);
|
2022-07-13 16:18:14 +10:00
|
|
|
if (is_ortho_camera) {
|
2023-07-12 18:02:56 +02:00
|
|
|
DEG_id_tag_update_ex(bmain, static_cast<ID *>(camera_ob->data), ID_RECALC_PARAMETERS);
|
2022-07-13 16:18:14 +10:00
|
|
|
}
|
2020-12-14 12:48:16 +01:00
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-20 11:30:25 +10:00
|
|
|
bool ED_view3d_camera_to_view_selected(Main *bmain,
|
2022-04-04 16:16:36 -03:00
|
|
|
Depsgraph *depsgraph,
|
|
|
|
|
const Scene *scene,
|
|
|
|
|
Object *camera_ob)
|
|
|
|
|
{
|
2023-07-12 18:02:56 +02:00
|
|
|
return view3d_camera_to_view_selected_impl(bmain, depsgraph, scene, camera_ob, nullptr, nullptr);
|
2022-04-04 16:16:36 -03:00
|
|
|
}
|
|
|
|
|
|
2023-07-20 11:30:25 +10:00
|
|
|
bool ED_view3d_camera_to_view_selected_with_set_clipping(Main *bmain,
|
2022-04-04 16:16:36 -03:00
|
|
|
Depsgraph *depsgraph,
|
|
|
|
|
const Scene *scene,
|
|
|
|
|
Object *camera_ob)
|
|
|
|
|
{
|
|
|
|
|
float clip_start;
|
|
|
|
|
float clip_end;
|
|
|
|
|
if (view3d_camera_to_view_selected_impl(
|
|
|
|
|
bmain, depsgraph, scene, camera_ob, &clip_start, &clip_end))
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
((Camera *)camera_ob->data)->clip_start = clip_start;
|
|
|
|
|
((Camera *)camera_ob->data)->clip_end = clip_end;
|
|
|
|
|
|
|
|
|
|
/* TODO: Support update via #ID_RECALC_PARAMETERS. */
|
|
|
|
|
Object *camera_ob_eval = DEG_get_evaluated_object(depsgraph, camera_ob);
|
|
|
|
|
((Camera *)camera_ob_eval->data)->clip_start = clip_start;
|
|
|
|
|
((Camera *)camera_ob_eval->data)->clip_end = clip_end;
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2018-01-28 14:44:42 +11:00
|
|
|
/** \} */
|
|
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name Depth Buffer Utilities
|
|
|
|
|
* \{ */
|
|
|
|
|
|
2021-04-17 13:51:33 -03:00
|
|
|
struct ReadData {
|
|
|
|
|
int count;
|
|
|
|
|
int count_max;
|
|
|
|
|
float r_depth;
|
|
|
|
|
};
|
|
|
|
|
|
2021-04-05 10:48:28 -03:00
|
|
|
static bool depth_read_test_fn(const void *value, void *userdata)
|
2018-01-28 14:44:42 +11:00
|
|
|
{
|
2023-07-20 11:30:25 +10:00
|
|
|
ReadData *data = static_cast<ReadData *>(userdata);
|
2021-04-05 10:48:28 -03:00
|
|
|
float depth = *(float *)value;
|
2025-01-26 20:08:00 +01:00
|
|
|
data->r_depth = std::min(depth, data->r_depth);
|
2021-04-17 13:51:33 -03:00
|
|
|
|
|
|
|
|
if ((++data->count) >= data->count_max) {
|
|
|
|
|
/* Outside the margin. */
|
|
|
|
|
return true;
|
2021-04-05 10:48:28 -03:00
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool ED_view3d_depth_read_cached(const ViewDepths *vd,
|
|
|
|
|
const int mval[2],
|
|
|
|
|
int margin,
|
|
|
|
|
float *r_depth)
|
|
|
|
|
{
|
2021-11-25 10:17:31 -03:00
|
|
|
*r_depth = 1.0f;
|
|
|
|
|
|
2021-04-05 10:48:28 -03:00
|
|
|
if (!vd || !vd->depths) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2024-04-04 10:55:08 +11:00
|
|
|
BLI_assert(1.0 <= vd->depth_range[1]);
|
2018-01-28 14:44:42 +11:00
|
|
|
int x = mval[0];
|
|
|
|
|
int y = mval[1];
|
2021-04-05 10:48:28 -03:00
|
|
|
if (x < 0 || y < 0 || x >= vd->w || y >= vd->h) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2021-04-05 10:48:28 -03:00
|
|
|
float depth = 1.0f;
|
|
|
|
|
if (margin) {
|
|
|
|
|
int shape[2] = {vd->w, vd->h};
|
2021-04-17 13:51:33 -03:00
|
|
|
int pixel_count = (min_ii(x + margin + 1, shape[1]) - max_ii(x - margin, 0)) *
|
|
|
|
|
(min_ii(y + margin + 1, shape[0]) - max_ii(y - margin, 0));
|
|
|
|
|
|
2023-07-20 11:30:25 +10:00
|
|
|
ReadData data;
|
2021-04-17 13:51:33 -03:00
|
|
|
data.count = 0;
|
|
|
|
|
data.count_max = pixel_count;
|
|
|
|
|
data.r_depth = 1.0f;
|
|
|
|
|
|
|
|
|
|
/* TODO: No need to go spiral. */
|
|
|
|
|
BLI_array_iter_spiral_square(vd->depths, shape, mval, depth_read_test_fn, &data);
|
|
|
|
|
depth = data.r_depth;
|
2021-04-05 10:48:28 -03:00
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
depth = vd->depths[y * vd->w + x];
|
2018-01-28 14:44:42 +11:00
|
|
|
}
|
2020-07-03 17:18:56 +02:00
|
|
|
|
2021-04-05 10:48:28 -03:00
|
|
|
if (depth != 1.0f) {
|
|
|
|
|
*r_depth = depth;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
2018-01-28 14:44:42 +11:00
|
|
|
}
|
|
|
|
|
|
2021-06-21 16:25:53 -03:00
|
|
|
bool ED_view3d_depth_read_cached_normal(const ARegion *region,
|
|
|
|
|
const ViewDepths *depths,
|
2018-01-28 15:20:19 +11:00
|
|
|
const int mval[2],
|
2018-01-28 14:44:42 +11:00
|
|
|
float r_normal[3])
|
|
|
|
|
{
|
2021-07-03 23:08:40 +10:00
|
|
|
/* NOTE: we could support passing in a radius.
|
2018-01-28 14:44:42 +11:00
|
|
|
* For now just read 9 pixels. */
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-01-28 14:44:42 +11:00
|
|
|
/* pixels surrounding */
|
|
|
|
|
bool depths_valid[9] = {false};
|
|
|
|
|
float coords[9][3] = {{0}};
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-01-28 14:44:42 +11:00
|
|
|
for (int x = 0, i = 0; x < 2; x++) {
|
|
|
|
|
for (int y = 0; y < 2; y++) {
|
|
|
|
|
const int mval_ofs[2] = {mval[0] + (x - 1), mval[1] + (y - 1)};
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2021-04-05 10:48:28 -03:00
|
|
|
float depth_fl = 1.0f;
|
|
|
|
|
ED_view3d_depth_read_cached(depths, mval_ofs, 0, &depth_fl);
|
2023-07-13 09:54:02 +10:00
|
|
|
const double depth = double(depth_fl);
|
2018-01-28 14:44:42 +11:00
|
|
|
if ((depth > depths->depth_range[0]) && (depth < depths->depth_range[1])) {
|
2021-06-01 12:49:20 +10:00
|
|
|
if (ED_view3d_depth_unproject_v3(region, mval_ofs, depth, coords[i])) {
|
2018-01-28 14:44:42 +11:00
|
|
|
depths_valid[i] = true;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2018-01-28 14:44:42 +11:00
|
|
|
i++;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
|
2018-01-28 14:44:42 +11:00
|
|
|
const int edges[2][6][2] = {
|
|
|
|
|
/* x edges */
|
2023-07-12 18:02:56 +02:00
|
|
|
{{0, 1}, {1, 2}, {3, 4}, {4, 5}, {6, 7}, {7, 8}}, /* y edges */
|
2018-01-28 14:44:42 +11:00
|
|
|
{{0, 3}, {3, 6}, {1, 4}, {4, 7}, {2, 5}, {5, 8}},
|
|
|
|
|
};
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-01-28 14:44:42 +11:00
|
|
|
float cross[2][3] = {{0.0f}};
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-01-28 14:44:42 +11:00
|
|
|
for (int i = 0; i < 6; i++) {
|
|
|
|
|
for (int axis = 0; axis < 2; axis++) {
|
|
|
|
|
if (depths_valid[edges[axis][i][0]] && depths_valid[edges[axis][i][1]]) {
|
|
|
|
|
float delta[3];
|
|
|
|
|
sub_v3_v3v3(delta, coords[edges[axis][i][0]], coords[edges[axis][i][1]]);
|
|
|
|
|
add_v3_v3(cross[axis], delta);
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2018-01-28 14:44:42 +11:00
|
|
|
}
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-01-28 14:44:42 +11:00
|
|
|
cross_v3_v3v3(r_normal, cross[0], cross[1]);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-01-28 14:44:42 +11:00
|
|
|
if (normalize_v3(r_normal) != 0.0f) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2020-07-03 17:18:56 +02:00
|
|
|
return false;
|
2018-01-28 14:44:42 +11:00
|
|
|
}
|
|
|
|
|
|
2021-06-01 12:49:20 +10:00
|
|
|
bool ED_view3d_depth_unproject_v3(const ARegion *region,
|
|
|
|
|
const int mval[2],
|
|
|
|
|
const double depth,
|
|
|
|
|
float r_location_world[3])
|
2018-01-28 14:44:42 +11:00
|
|
|
{
|
2023-07-14 12:23:37 +10:00
|
|
|
float centx = float(mval[0]) + 0.5f;
|
|
|
|
|
float centy = float(mval[1]) + 0.5f;
|
2021-06-01 12:49:20 +10:00
|
|
|
return ED_view3d_unproject_v3(region, centx, centy, depth, r_location_world);
|
2018-01-28 14:44:42 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** \} */
|