mirror of
https://github.com/blender/blender
synced 2026-09-29 04:37:17 +03:00
VR: Location Scouting
This feature commit implements VR Location Scouting within Blender, allowing the user to block camera vantage points while immersed in VR. For feature design, see: - VR: Location Scouting (!141089): https://projects.blender.org/blender/blender/issues/141089 - VR Location Scouting - high fidelity UI (#143061): https://projects.blender.org/blender/blender/issues/143061 - Design Session on Devtalk: https://devtalk.blender.org/t/2025-06-19-design-session-vr-location-scouting/41135 For up to date screenshots, demos and discussion regarding the feature, see the following devtalk feedback thread: https://devtalk.blender.org/t/vr-location-scouting-feedback-and-discussion/44744 Pull Request: https://projects.blender.org/blender/blender/pulls/143945
This commit is contained in:
parent
a1228b3187
commit
0ee0341936
25 changed files with 4648 additions and 63 deletions
|
|
@ -1429,6 +1429,708 @@ actionconfig_data = [
|
|||
],
|
||||
},
|
||||
),
|
||||
(
|
||||
"viewfinder_capture",
|
||||
{
|
||||
"type": "FLOAT",
|
||||
"user_paths": ["/user/hand/left", "/user/hand/right"],
|
||||
"op": "view3d.vr_location_scouting_viewfinder_capture",
|
||||
"op_mode": "PRESS",
|
||||
"bimanual": "False",
|
||||
"haptic_name": "",
|
||||
"haptic_match_user_paths": "False",
|
||||
"haptic_duration": "0.0",
|
||||
"haptic_frequency": "0.0",
|
||||
"haptic_amplitude": "0.0",
|
||||
"haptic_mode": "PRESS",
|
||||
},
|
||||
{"op_properties": []},
|
||||
{
|
||||
"bindings": [
|
||||
(
|
||||
"huawei",
|
||||
{
|
||||
"profile": "/interaction_profiles/huawei/controller",
|
||||
"component_paths": [
|
||||
"/input/trigger/value",
|
||||
"/input/trigger/value",
|
||||
],
|
||||
"threshold": "0.5",
|
||||
"axis_region": "ANY",
|
||||
},
|
||||
),
|
||||
(
|
||||
"index",
|
||||
{
|
||||
"profile": "/interaction_profiles/valve/index_controller",
|
||||
"component_paths": [
|
||||
"/input/trigger/value",
|
||||
"/input/trigger/value",
|
||||
],
|
||||
"threshold": "0.5",
|
||||
"axis_region": "ANY",
|
||||
},
|
||||
),
|
||||
(
|
||||
"oculus",
|
||||
{
|
||||
"profile": "/interaction_profiles/oculus/touch_controller",
|
||||
"component_paths": [
|
||||
"/input/trigger/value",
|
||||
"/input/trigger/value",
|
||||
],
|
||||
"threshold": "0.5",
|
||||
"axis_region": "ANY",
|
||||
},
|
||||
),
|
||||
(
|
||||
"reverb_g2",
|
||||
{
|
||||
"profile": "/interaction_profiles/hp/mixed_reality_controller",
|
||||
"component_paths": [
|
||||
"/input/trigger/value",
|
||||
"/input/trigger/value",
|
||||
],
|
||||
"threshold": "0.5",
|
||||
"axis_region": "ANY",
|
||||
},
|
||||
),
|
||||
(
|
||||
"simple",
|
||||
{
|
||||
"profile": "/interaction_profiles/khr/simple_controller",
|
||||
"component_paths": [
|
||||
"/input/select/click",
|
||||
"/input/select/click",
|
||||
],
|
||||
"threshold": "0.5",
|
||||
"axis_region": "ANY",
|
||||
},
|
||||
),
|
||||
(
|
||||
"vive",
|
||||
{
|
||||
"profile": "/interaction_profiles/htc/vive_controller",
|
||||
"component_paths": [
|
||||
"/input/trigger/value",
|
||||
"/input/trigger/value",
|
||||
],
|
||||
"threshold": "0.5",
|
||||
"axis_region": "ANY",
|
||||
},
|
||||
),
|
||||
(
|
||||
"vive_cosmos",
|
||||
{
|
||||
"profile": "/interaction_profiles/htc/vive_cosmos_controller",
|
||||
"component_paths": [
|
||||
"/input/trigger/value",
|
||||
"/input/trigger/value",
|
||||
],
|
||||
"threshold": "0.5",
|
||||
"axis_region": "ANY",
|
||||
},
|
||||
),
|
||||
(
|
||||
"vive_focus",
|
||||
{
|
||||
"profile": "/interaction_profiles/htc/vive_focus3_controller",
|
||||
"component_paths": [
|
||||
"/input/trigger/value",
|
||||
"/input/trigger/value",
|
||||
],
|
||||
"threshold": "0.5",
|
||||
"axis_region": "ANY",
|
||||
},
|
||||
),
|
||||
(
|
||||
"wmr",
|
||||
{
|
||||
"profile": "/interaction_profiles/microsoft/motion_controller",
|
||||
"component_paths": [
|
||||
"/input/trigger/value",
|
||||
"/input/trigger/value",
|
||||
],
|
||||
"threshold": "0.5",
|
||||
"axis_region": "ANY",
|
||||
},
|
||||
),
|
||||
],
|
||||
},
|
||||
),
|
||||
(
|
||||
"viewfinder_cycle_mode",
|
||||
{
|
||||
"type": "FLOAT",
|
||||
"user_paths": ["/user/hand/left", "/user/hand/right"],
|
||||
"op": "view3d.vr_location_scouting_viewfinder_cycle_mode",
|
||||
"op_mode": "PRESS",
|
||||
"bimanual": "False",
|
||||
"haptic_name": "haptic",
|
||||
"haptic_match_user_paths": "True",
|
||||
"haptic_duration": "0.3",
|
||||
"haptic_frequency": "3000.0",
|
||||
"haptic_amplitude": "0.5",
|
||||
"haptic_mode": "PRESS",
|
||||
},
|
||||
{"op_properties": []},
|
||||
{
|
||||
"bindings": [
|
||||
(
|
||||
"huawei",
|
||||
{
|
||||
"profile": "/interaction_profiles/huawei/controller",
|
||||
"component_paths": [
|
||||
"/input/trackpad/click",
|
||||
"/input/trackpad/click",
|
||||
],
|
||||
"threshold": "0.5",
|
||||
"axis_region": "ANY",
|
||||
},
|
||||
),
|
||||
(
|
||||
"index",
|
||||
{
|
||||
"profile": "/interaction_profiles/valve/index_controller",
|
||||
"component_paths": [
|
||||
"/input/squeeze/force",
|
||||
"/input/squeeze/force",
|
||||
],
|
||||
"threshold": "0.5",
|
||||
"axis_region": "ANY",
|
||||
},
|
||||
),
|
||||
(
|
||||
"oculus",
|
||||
{
|
||||
"profile": "/interaction_profiles/oculus/touch_controller",
|
||||
"component_paths": [
|
||||
"/input/squeeze/value",
|
||||
"/input/squeeze/value",
|
||||
],
|
||||
"threshold": "0.5",
|
||||
"axis_region": "ANY",
|
||||
},
|
||||
),
|
||||
(
|
||||
"reverb_g2",
|
||||
{
|
||||
"profile": "/interaction_profiles/hp/mixed_reality_controller",
|
||||
"component_paths": [
|
||||
"/input/squeeze/value",
|
||||
"/input/squeeze/value",
|
||||
],
|
||||
"threshold": "0.5",
|
||||
"axis_region": "ANY",
|
||||
},
|
||||
),
|
||||
(
|
||||
"simple",
|
||||
{
|
||||
"profile": "/interaction_profiles/khr/simple_controller",
|
||||
"component_paths": [
|
||||
"/input/menu/click",
|
||||
"/input/menu/click",
|
||||
],
|
||||
"threshold": "0.5",
|
||||
"axis_region": "ANY",
|
||||
},
|
||||
),
|
||||
(
|
||||
"vive",
|
||||
{
|
||||
"profile": "/interaction_profiles/htc/vive_controller",
|
||||
"component_paths": [
|
||||
"/input/squeeze/click",
|
||||
"/input/squeeze/click",
|
||||
],
|
||||
"threshold": "0.5",
|
||||
"axis_region": "ANY",
|
||||
},
|
||||
),
|
||||
(
|
||||
"vive_cosmos",
|
||||
{
|
||||
"profile": "/interaction_profiles/htc/vive_cosmos_controller",
|
||||
"component_paths": [
|
||||
"/input/squeeze/click",
|
||||
"/input/squeeze/click",
|
||||
],
|
||||
"threshold": "0.5",
|
||||
"axis_region": "ANY",
|
||||
},
|
||||
),
|
||||
(
|
||||
"vive_focus",
|
||||
{
|
||||
"profile": "/interaction_profiles/htc/vive_focus3_controller",
|
||||
"component_paths": [
|
||||
"/input/squeeze/click",
|
||||
"/input/squeeze/click",
|
||||
],
|
||||
"threshold": "0.5",
|
||||
"axis_region": "ANY",
|
||||
},
|
||||
),
|
||||
(
|
||||
"wmr",
|
||||
{
|
||||
"profile": "/interaction_profiles/microsoft/motion_controller",
|
||||
"component_paths": [
|
||||
"/input/squeeze/click",
|
||||
"/input/squeeze/click",
|
||||
],
|
||||
"threshold": "0.5",
|
||||
"axis_region": "ANY",
|
||||
},
|
||||
),
|
||||
],
|
||||
},
|
||||
),
|
||||
(
|
||||
"viewfinder_cycle_action",
|
||||
{
|
||||
"type": "FLOAT",
|
||||
"user_paths": ["/user/hand/left", "/user/hand/right"],
|
||||
"op": "view3d.vr_location_scouting_viewfinder_cycle_action",
|
||||
"op_mode": "PRESS",
|
||||
"bimanual": "False",
|
||||
"haptic_name": "",
|
||||
"haptic_match_user_paths": "False",
|
||||
"haptic_duration": "0.0",
|
||||
"haptic_frequency": "0.0",
|
||||
"haptic_amplitude": "0.0",
|
||||
"haptic_mode": "PRESS",
|
||||
},
|
||||
{"op_properties": []},
|
||||
{
|
||||
"bindings": [
|
||||
(
|
||||
"huawei",
|
||||
{
|
||||
"profile": "/interaction_profiles/huawei/controller",
|
||||
"component_paths": ["/input/trackpad/x", "/input/trackpad/x"],
|
||||
"threshold": "0.65",
|
||||
"axis_region": "ANY",
|
||||
},
|
||||
),
|
||||
(
|
||||
"index",
|
||||
{
|
||||
"profile": "/interaction_profiles/valve/index_controller",
|
||||
"component_paths": ["/input/thumbstick/x", "/input/thumbstick/x"],
|
||||
"threshold": "0.65",
|
||||
"axis_region": "ANY",
|
||||
},
|
||||
),
|
||||
(
|
||||
"oculus",
|
||||
{
|
||||
"profile": "/interaction_profiles/oculus/touch_controller",
|
||||
"component_paths": ["/input/thumbstick/x", "/input/thumbstick/x"],
|
||||
"threshold": "0.65",
|
||||
"axis_region": "ANY",
|
||||
},
|
||||
),
|
||||
(
|
||||
"reverb_g2",
|
||||
{
|
||||
"profile": "/interaction_profiles/hp/mixed_reality_controller",
|
||||
"component_paths": ["/input/thumbstick/x", "/input/thumbstick/x"],
|
||||
"threshold": "0.65",
|
||||
"axis_region": "ANY",
|
||||
},
|
||||
),
|
||||
(
|
||||
"vive",
|
||||
{
|
||||
"profile": "/interaction_profiles/htc/vive_controller",
|
||||
"component_paths": ["/input/trackpad/x", "/input/trackpad/x"],
|
||||
"threshold": "0.65",
|
||||
"axis_region": "ANY",
|
||||
},
|
||||
),
|
||||
(
|
||||
"vive_cosmos",
|
||||
{
|
||||
"profile": "/interaction_profiles/htc/vive_cosmos_controller",
|
||||
"component_paths": ["/input/thumbstick/x", "/input/thumbstick/x"],
|
||||
"threshold": "0.65",
|
||||
"axis_region": "ANY",
|
||||
},
|
||||
),
|
||||
(
|
||||
"vive_focus",
|
||||
{
|
||||
"profile": "/interaction_profiles/htc/vive_focus3_controller",
|
||||
"component_paths": ["/input/thumbstick/x", "/input/thumbstick/x"],
|
||||
"threshold": "0.65",
|
||||
"axis_region": "ANY",
|
||||
},
|
||||
),
|
||||
(
|
||||
"wmr",
|
||||
{
|
||||
"profile": "/interaction_profiles/microsoft/motion_controller",
|
||||
"component_paths": ["/input/thumbstick/x", "/input/thumbstick/x"],
|
||||
"threshold": "0.65",
|
||||
"axis_region": "ANY",
|
||||
},
|
||||
),
|
||||
],
|
||||
},
|
||||
),
|
||||
(
|
||||
"viewfinder_apply_action_up",
|
||||
{
|
||||
"type": "FLOAT",
|
||||
"user_paths": ["/user/hand/left", "/user/hand/right"],
|
||||
"op": "view3d.vr_location_scouting_viewfinder_apply_action",
|
||||
"op_mode": "PRESS",
|
||||
"bimanual": "False",
|
||||
"haptic_name": "haptic",
|
||||
"haptic_match_user_paths": "True",
|
||||
"haptic_duration": "0.3",
|
||||
"haptic_frequency": "3000.0",
|
||||
"haptic_amplitude": "0.5",
|
||||
"haptic_mode": "PRESS",
|
||||
},
|
||||
{"op_properties": [("action_up", True)]},
|
||||
{
|
||||
"bindings": [
|
||||
(
|
||||
"huawei",
|
||||
{
|
||||
"profile": "/interaction_profiles/huawei/controller",
|
||||
"component_paths": [
|
||||
"/input/home/click",
|
||||
"/input/home/click",
|
||||
],
|
||||
"threshold": "0.3",
|
||||
"axis_region": "ANY",
|
||||
},
|
||||
),
|
||||
(
|
||||
"index",
|
||||
{
|
||||
"profile": "/interaction_profiles/valve/index_controller",
|
||||
"component_paths": [
|
||||
"/input/b/click",
|
||||
"/input/b/click",
|
||||
],
|
||||
"threshold": "0.3",
|
||||
"axis_region": "ANY",
|
||||
},
|
||||
),
|
||||
(
|
||||
"oculus",
|
||||
{
|
||||
"profile": "/interaction_profiles/oculus/touch_controller",
|
||||
"component_paths": [
|
||||
"/input/y/click",
|
||||
"/input/b/click",
|
||||
],
|
||||
"threshold": "0.3",
|
||||
"axis_region": "ANY",
|
||||
},
|
||||
),
|
||||
(
|
||||
"reverb_g2",
|
||||
{
|
||||
"profile": "/interaction_profiles/hp/mixed_reality_controller",
|
||||
"component_paths": [
|
||||
"/input/y/click",
|
||||
"/input/b/click",
|
||||
],
|
||||
"threshold": "0.3",
|
||||
"axis_region": "ANY",
|
||||
},
|
||||
),
|
||||
(
|
||||
"vive",
|
||||
{
|
||||
"profile": "/interaction_profiles/htc/vive_controller",
|
||||
"component_paths": [
|
||||
"/input/menu/click",
|
||||
"/input/menu/click",
|
||||
],
|
||||
"threshold": "0.3",
|
||||
"axis_region": "ANY",
|
||||
},
|
||||
),
|
||||
(
|
||||
"vive_cosmos",
|
||||
{
|
||||
"profile": "/interaction_profiles/htc/vive_cosmos_controller",
|
||||
"component_paths": [
|
||||
"/input/y/click",
|
||||
"/input/b/click",
|
||||
],
|
||||
"threshold": "0.3",
|
||||
"axis_region": "ANY",
|
||||
},
|
||||
),
|
||||
(
|
||||
"vive_focus",
|
||||
{
|
||||
"profile": "/interaction_profiles/htc/vive_focus3_controller",
|
||||
"component_paths": [
|
||||
"/input/y/click",
|
||||
"/input/b/click",
|
||||
],
|
||||
"threshold": "0.3",
|
||||
"axis_region": "ANY",
|
||||
},
|
||||
),
|
||||
(
|
||||
"wmr",
|
||||
{
|
||||
"profile": "/interaction_profiles/microsoft/motion_controller",
|
||||
"component_paths": [
|
||||
"/input/menu/click",
|
||||
"/input/menu/click",
|
||||
],
|
||||
"threshold": "0.3",
|
||||
"axis_region": "ANY",
|
||||
},
|
||||
),
|
||||
],
|
||||
},
|
||||
),
|
||||
(
|
||||
"viewfinder_apply_action_down",
|
||||
{
|
||||
"type": "FLOAT",
|
||||
"user_paths": ["/user/hand/left", "/user/hand/right"],
|
||||
"op": "view3d.vr_location_scouting_viewfinder_apply_action",
|
||||
"op_mode": "PRESS",
|
||||
"bimanual": "False",
|
||||
"haptic_name": "haptic",
|
||||
"haptic_match_user_paths": "True",
|
||||
"haptic_duration": "0.3",
|
||||
"haptic_frequency": "3000.0",
|
||||
"haptic_amplitude": "0.5",
|
||||
"haptic_mode": "PRESS",
|
||||
},
|
||||
{"op_properties": [("action_up", False)]},
|
||||
{
|
||||
"bindings": [
|
||||
(
|
||||
"huawei",
|
||||
{
|
||||
"profile": "/interaction_profiles/huawei/controller",
|
||||
"component_paths": [
|
||||
"/input/back/click",
|
||||
"/input/back/click",
|
||||
],
|
||||
"threshold": "0.3",
|
||||
"axis_region": "ANY",
|
||||
},
|
||||
),
|
||||
(
|
||||
"index",
|
||||
{
|
||||
"profile": "/interaction_profiles/valve/index_controller",
|
||||
"component_paths": [
|
||||
"/input/a/click",
|
||||
"/input/a/click",
|
||||
],
|
||||
"threshold": "0.3",
|
||||
"axis_region": "ANY",
|
||||
},
|
||||
),
|
||||
(
|
||||
"oculus",
|
||||
{
|
||||
"profile": "/interaction_profiles/oculus/touch_controller",
|
||||
"component_paths": [
|
||||
"/input/x/click",
|
||||
"/input/a/click",
|
||||
],
|
||||
"threshold": "0.3",
|
||||
"axis_region": "ANY",
|
||||
},
|
||||
),
|
||||
(
|
||||
"reverb_g2",
|
||||
{
|
||||
"profile": "/interaction_profiles/hp/mixed_reality_controller",
|
||||
"component_paths": [
|
||||
"/input/x/click",
|
||||
"/input/a/click",
|
||||
],
|
||||
"threshold": "0.3",
|
||||
"axis_region": "ANY",
|
||||
},
|
||||
),
|
||||
(
|
||||
"vive",
|
||||
{
|
||||
"profile": "/interaction_profiles/htc/vive_controller",
|
||||
"component_paths": [
|
||||
"/input/menu/click",
|
||||
"/input/menu/click",
|
||||
],
|
||||
"threshold": "0.3",
|
||||
"axis_region": "ANY",
|
||||
},
|
||||
),
|
||||
(
|
||||
"vive_cosmos",
|
||||
{
|
||||
"profile": "/interaction_profiles/htc/vive_cosmos_controller",
|
||||
"component_paths": [
|
||||
"/input/x/click",
|
||||
"/input/a/click",
|
||||
],
|
||||
"threshold": "0.3",
|
||||
"axis_region": "ANY",
|
||||
},
|
||||
),
|
||||
(
|
||||
"vive_focus",
|
||||
{
|
||||
"profile": "/interaction_profiles/htc/vive_focus3_controller",
|
||||
"component_paths": [
|
||||
"/input/x/click",
|
||||
"/input/a/click",
|
||||
],
|
||||
"threshold": "0.3",
|
||||
"axis_region": "ANY",
|
||||
},
|
||||
),
|
||||
(
|
||||
"wmr",
|
||||
{
|
||||
"profile": "/interaction_profiles/microsoft/motion_controller",
|
||||
"component_paths": [
|
||||
"/input/menu/click",
|
||||
"/input/menu/click",
|
||||
],
|
||||
"threshold": "0.3",
|
||||
"axis_region": "ANY",
|
||||
},
|
||||
),
|
||||
],
|
||||
},
|
||||
),
|
||||
(
|
||||
"viewfinder_swap_hands",
|
||||
{
|
||||
"type": "FLOAT",
|
||||
"user_paths": ["/user/hand/left", "/user/hand/right"],
|
||||
"op": "view3d.vr_location_scouting_viewfinder_swap_hands",
|
||||
"op_mode": "PRESS",
|
||||
"bimanual": "False",
|
||||
"haptic_name": "haptic",
|
||||
"haptic_match_user_paths": "True",
|
||||
"haptic_duration": "0.3",
|
||||
"haptic_frequency": "3000.0",
|
||||
"haptic_amplitude": "0.5",
|
||||
"haptic_mode": "PRESS",
|
||||
},
|
||||
{"op_properties": []},
|
||||
{
|
||||
"bindings": [
|
||||
(
|
||||
"huawei",
|
||||
{
|
||||
"profile": "/interaction_profiles/huawei/controller",
|
||||
"component_paths": [
|
||||
"/input/trackpad/click",
|
||||
"/input/trackpad/click",
|
||||
],
|
||||
"threshold": "0.3",
|
||||
"axis_region": "ANY",
|
||||
},
|
||||
),
|
||||
(
|
||||
"index",
|
||||
{
|
||||
"profile": "/interaction_profiles/valve/index_controller",
|
||||
"component_paths": [
|
||||
"/input/thumbstick/click",
|
||||
"/input/thumbstick/click",
|
||||
],
|
||||
"threshold": "0.3",
|
||||
"axis_region": "ANY",
|
||||
},
|
||||
),
|
||||
(
|
||||
"oculus",
|
||||
{
|
||||
"profile": "/interaction_profiles/oculus/touch_controller",
|
||||
"component_paths": [
|
||||
"/input/thumbstick/click",
|
||||
"/input/thumbstick/click",
|
||||
],
|
||||
"threshold": "0.3",
|
||||
"axis_region": "ANY",
|
||||
},
|
||||
),
|
||||
(
|
||||
"reverb_g2",
|
||||
{
|
||||
"profile": "/interaction_profiles/hp/mixed_reality_controller",
|
||||
"component_paths": [
|
||||
"/input/thumbstick/click",
|
||||
"/input/thumbstick/click",
|
||||
],
|
||||
"threshold": "0.3",
|
||||
"axis_region": "ANY",
|
||||
},
|
||||
),
|
||||
(
|
||||
"vive",
|
||||
{
|
||||
"profile": "/interaction_profiles/htc/vive_controller",
|
||||
"component_paths": [
|
||||
"/input/trackpad/click",
|
||||
"/input/trackpad/click",
|
||||
],
|
||||
"threshold": "0.3",
|
||||
"axis_region": "ANY",
|
||||
},
|
||||
),
|
||||
(
|
||||
"vive_cosmos",
|
||||
{
|
||||
"profile": "/interaction_profiles/htc/vive_cosmos_controller",
|
||||
"component_paths": [
|
||||
"/input/thumbstick/click",
|
||||
"/input/thumbstick/click",
|
||||
],
|
||||
"threshold": "0.3",
|
||||
"axis_region": "ANY",
|
||||
},
|
||||
),
|
||||
(
|
||||
"vive_focus",
|
||||
{
|
||||
"profile": "/interaction_profiles/htc/vive_focus3_controller",
|
||||
"component_paths": [
|
||||
"/input/thumbstick/click",
|
||||
"/input/thumbstick/click",
|
||||
],
|
||||
"threshold": "0.3",
|
||||
"axis_region": "ANY",
|
||||
},
|
||||
),
|
||||
(
|
||||
"wmr",
|
||||
{
|
||||
"profile": "/interaction_profiles/microsoft/motion_controller",
|
||||
"component_paths": [
|
||||
"/input/thumbstick/click",
|
||||
"/input/thumbstick/click",
|
||||
],
|
||||
"threshold": "0.3",
|
||||
"axis_region": "ANY",
|
||||
},
|
||||
),
|
||||
],
|
||||
},
|
||||
),
|
||||
(
|
||||
"haptic",
|
||||
{
|
||||
|
|
@ -1991,7 +2693,6 @@ actionconfig_data = [
|
|||
),
|
||||
]
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Only add keywords that are supported.
|
||||
from bpy.app import version as blender_version
|
||||
|
|
|
|||
|
|
@ -37,6 +37,12 @@ class VRDefaultActions(Enum):
|
|||
FLY_TURNLEFT = "fly_turnleft"
|
||||
FLY_TURNRIGHT = "fly_turnright"
|
||||
NAV_RESET = "nav_reset"
|
||||
VIEWFINDER_CAPTURE = "viewfinder_capture"
|
||||
VIEWFINDER_CYCLE_MODE = "viewfinder_cycle_mode"
|
||||
VIEWFINDER_CYCLE_ACTION = "viewfinder_cycle_action"
|
||||
VIEWFINDER_APPLY_ACTION_UP = "viewfinder_apply_action_up"
|
||||
VIEWFINDER_APPLY_ACTION_DOWN = "viewfinder_apply_action_down"
|
||||
VIEWFINDER_SWAP_HANDS = "viewfinder_swap_hands"
|
||||
SWAP_HANDS = "swap_hands"
|
||||
HAPTIC = "haptic"
|
||||
HAPTIC_LEFT = "haptic_left"
|
||||
|
|
@ -1147,6 +1153,497 @@ def vr_defaults_create_default(session_state):
|
|||
'ANY',
|
||||
'ANY')
|
||||
|
||||
# Viewfinder actions.
|
||||
ami = vr_defaults_action_add(am,
|
||||
VRDefaultActions.VIEWFINDER_CAPTURE.value,
|
||||
["/user/hand/left",
|
||||
"/user/hand/right"],
|
||||
"view3d.vr_location_scouting_viewfinder_capture",
|
||||
'PRESS',
|
||||
False,
|
||||
"",
|
||||
False,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
'PRESS')
|
||||
if ami:
|
||||
vr_defaults_actionbinding_add(ami,
|
||||
VRDefaultActionbindings.HUAWEI.value,
|
||||
VRDefaultActionprofiles.HUAWEI.value,
|
||||
["/input/trigger/value",
|
||||
"/input/trigger/value"],
|
||||
0.5,
|
||||
'ANY',
|
||||
'ANY')
|
||||
vr_defaults_actionbinding_add(ami,
|
||||
VRDefaultActionbindings.INDEX.value,
|
||||
VRDefaultActionprofiles.INDEX.value,
|
||||
["/input/trigger/value",
|
||||
"/input/trigger/value"],
|
||||
0.5,
|
||||
'ANY',
|
||||
'ANY')
|
||||
vr_defaults_actionbinding_add(ami,
|
||||
VRDefaultActionbindings.OCULUS.value,
|
||||
VRDefaultActionprofiles.OCULUS.value,
|
||||
["/input/trigger/value",
|
||||
"/input/trigger/value"],
|
||||
0.5,
|
||||
'ANY',
|
||||
'ANY')
|
||||
vr_defaults_actionbinding_add(ami,
|
||||
VRDefaultActionbindings.REVERB_G2.value,
|
||||
VRDefaultActionprofiles.REVERB_G2.value,
|
||||
["/input/trigger/value",
|
||||
"/input/trigger/value"],
|
||||
0.5,
|
||||
'ANY',
|
||||
'ANY')
|
||||
vr_defaults_actionbinding_add(ami,
|
||||
VRDefaultActionbindings.SIMPLE.value,
|
||||
VRDefaultActionprofiles.SIMPLE.value,
|
||||
["/input/select/click",
|
||||
"/input/select/click"],
|
||||
0.5,
|
||||
'ANY',
|
||||
'ANY')
|
||||
vr_defaults_actionbinding_add(ami,
|
||||
VRDefaultActionbindings.VIVE.value,
|
||||
VRDefaultActionprofiles.VIVE.value,
|
||||
["/input/trigger/value",
|
||||
"/input/trigger/value"],
|
||||
0.5,
|
||||
'ANY',
|
||||
'ANY')
|
||||
vr_defaults_actionbinding_add(ami,
|
||||
VRDefaultActionbindings.VIVE_COSMOS.value,
|
||||
VRDefaultActionprofiles.VIVE_COSMOS.value,
|
||||
["/input/trigger/value",
|
||||
"/input/trigger/value"],
|
||||
0.5,
|
||||
'ANY',
|
||||
'ANY')
|
||||
vr_defaults_actionbinding_add(ami,
|
||||
VRDefaultActionbindings.VIVE_FOCUS.value,
|
||||
VRDefaultActionprofiles.VIVE_FOCUS.value,
|
||||
["/input/trigger/value",
|
||||
"/input/trigger/value"],
|
||||
0.5,
|
||||
'ANY',
|
||||
'ANY')
|
||||
vr_defaults_actionbinding_add(ami,
|
||||
VRDefaultActionbindings.WMR.value,
|
||||
VRDefaultActionprofiles.WMR.value,
|
||||
["/input/trigger/value",
|
||||
"/input/trigger/value"],
|
||||
0.5,
|
||||
'ANY',
|
||||
'ANY')
|
||||
|
||||
ami = vr_defaults_action_add(am,
|
||||
VRDefaultActions.VIEWFINDER_CYCLE_MODE.value,
|
||||
["/user/hand/left",
|
||||
"/user/hand/right"],
|
||||
"view3d.vr_location_scouting_viewfinder_cycle_mode",
|
||||
'PRESS',
|
||||
False,
|
||||
"haptic",
|
||||
True,
|
||||
0.3,
|
||||
3000.0,
|
||||
0.5,
|
||||
'PRESS')
|
||||
if ami:
|
||||
vr_defaults_actionbinding_add(ami,
|
||||
VRDefaultActionbindings.HUAWEI.value,
|
||||
VRDefaultActionprofiles.HUAWEI.value,
|
||||
["/input/trackpad/click",
|
||||
"/input/trackpad/click"],
|
||||
0.5,
|
||||
'ANY',
|
||||
'ANY')
|
||||
vr_defaults_actionbinding_add(ami,
|
||||
VRDefaultActionbindings.INDEX.value,
|
||||
VRDefaultActionprofiles.INDEX.value,
|
||||
["/input/squeeze/force",
|
||||
"/input/squeeze/force"],
|
||||
0.5,
|
||||
'ANY',
|
||||
'ANY')
|
||||
vr_defaults_actionbinding_add(ami,
|
||||
VRDefaultActionbindings.OCULUS.value,
|
||||
VRDefaultActionprofiles.OCULUS.value,
|
||||
["/input/squeeze/value",
|
||||
"/input/squeeze/value"],
|
||||
0.5,
|
||||
'ANY',
|
||||
'ANY')
|
||||
vr_defaults_actionbinding_add(ami,
|
||||
VRDefaultActionbindings.REVERB_G2.value,
|
||||
VRDefaultActionprofiles.REVERB_G2.value,
|
||||
["/input/squeeze/value",
|
||||
"/input/squeeze/value"],
|
||||
0.5,
|
||||
'ANY',
|
||||
'ANY')
|
||||
vr_defaults_actionbinding_add(ami,
|
||||
VRDefaultActionbindings.SIMPLE.value,
|
||||
VRDefaultActionprofiles.SIMPLE.value,
|
||||
["/input/menu/click",
|
||||
"/input/menu/click"],
|
||||
0.5,
|
||||
'ANY',
|
||||
'ANY')
|
||||
vr_defaults_actionbinding_add(ami,
|
||||
VRDefaultActionbindings.VIVE.value,
|
||||
VRDefaultActionprofiles.VIVE.value,
|
||||
["/input/squeeze/click",
|
||||
"/input/squeeze/click"],
|
||||
0.5,
|
||||
'ANY',
|
||||
'ANY')
|
||||
vr_defaults_actionbinding_add(ami,
|
||||
VRDefaultActionbindings.VIVE_COSMOS.value,
|
||||
VRDefaultActionprofiles.VIVE_COSMOS.value,
|
||||
["/input/squeeze/click",
|
||||
"/input/squeeze/click"],
|
||||
0.5,
|
||||
'ANY',
|
||||
'ANY')
|
||||
vr_defaults_actionbinding_add(ami,
|
||||
VRDefaultActionbindings.VIVE_FOCUS.value,
|
||||
VRDefaultActionprofiles.VIVE_FOCUS.value,
|
||||
["/input/squeeze/click",
|
||||
"/input/squeeze/click"],
|
||||
0.5,
|
||||
'ANY',
|
||||
'ANY')
|
||||
vr_defaults_actionbinding_add(ami,
|
||||
VRDefaultActionbindings.WMR.value,
|
||||
VRDefaultActionprofiles.WMR.value,
|
||||
["/input/squeeze/click",
|
||||
"/input/squeeze/click"],
|
||||
0.5,
|
||||
'ANY',
|
||||
'ANY')
|
||||
|
||||
ami = vr_defaults_action_add(am,
|
||||
VRDefaultActions.VIEWFINDER_CYCLE_ACTION.value,
|
||||
["/user/hand/left",
|
||||
"/user/hand/right"],
|
||||
"view3d.vr_location_scouting_viewfinder_cycle_action",
|
||||
'PRESS',
|
||||
False,
|
||||
"haptic",
|
||||
True,
|
||||
0.3,
|
||||
3000.0,
|
||||
0.5,
|
||||
'PRESS')
|
||||
if ami:
|
||||
vr_defaults_actionbinding_add(ami,
|
||||
VRDefaultActionbindings.HUAWEI.value,
|
||||
VRDefaultActionprofiles.HUAWEI.value,
|
||||
["/input/trackpad/x",
|
||||
"/input/trackpad/x"],
|
||||
0.65,
|
||||
'ANY',
|
||||
'ANY')
|
||||
vr_defaults_actionbinding_add(ami,
|
||||
VRDefaultActionbindings.INDEX.value,
|
||||
VRDefaultActionprofiles.INDEX.value,
|
||||
["/input/thumbstick/x",
|
||||
"/input/thumbstick/x"],
|
||||
0.65,
|
||||
'ANY',
|
||||
'ANY')
|
||||
vr_defaults_actionbinding_add(ami,
|
||||
VRDefaultActionbindings.OCULUS.value,
|
||||
VRDefaultActionprofiles.OCULUS.value,
|
||||
["/input/thumbstick/x",
|
||||
"/input/thumbstick/x"],
|
||||
0.65,
|
||||
'ANY',
|
||||
'ANY')
|
||||
vr_defaults_actionbinding_add(ami,
|
||||
VRDefaultActionbindings.REVERB_G2.value,
|
||||
VRDefaultActionprofiles.REVERB_G2.value,
|
||||
["/input/thumbstick/x",
|
||||
"/input/thumbstick/x"],
|
||||
0.65,
|
||||
'ANY',
|
||||
'ANY')
|
||||
vr_defaults_actionbinding_add(ami,
|
||||
VRDefaultActionbindings.VIVE.value,
|
||||
VRDefaultActionprofiles.VIVE.value,
|
||||
["/input/trackpad/x",
|
||||
"/input/trackpad/x"],
|
||||
0.65,
|
||||
'ANY',
|
||||
'ANY')
|
||||
vr_defaults_actionbinding_add(ami,
|
||||
VRDefaultActionbindings.VIVE_COSMOS.value,
|
||||
VRDefaultActionprofiles.VIVE_COSMOS.value,
|
||||
["/input/thumbstick/x",
|
||||
"/input/thumbstick/x"],
|
||||
0.65,
|
||||
'ANY',
|
||||
'ANY')
|
||||
vr_defaults_actionbinding_add(ami,
|
||||
VRDefaultActionbindings.VIVE_FOCUS.value,
|
||||
VRDefaultActionprofiles.VIVE_FOCUS.value,
|
||||
["/input/thumbstick/x",
|
||||
"/input/thumbstick/x"],
|
||||
0.65,
|
||||
'ANY',
|
||||
'ANY')
|
||||
vr_defaults_actionbinding_add(ami,
|
||||
VRDefaultActionbindings.WMR.value,
|
||||
VRDefaultActionprofiles.WMR.value,
|
||||
["/input/thumbstick/x",
|
||||
"/input/thumbstick/x"],
|
||||
0.65,
|
||||
'ANY',
|
||||
'ANY')
|
||||
|
||||
ami = vr_defaults_action_add(am,
|
||||
VRDefaultActions.VIEWFINDER_APPLY_ACTION_UP.value,
|
||||
["/user/hand/left",
|
||||
"/user/hand/right"],
|
||||
"view3d.vr_location_scouting_viewfinder_apply_action",
|
||||
'PRESS',
|
||||
False,
|
||||
"haptic",
|
||||
True,
|
||||
0.3,
|
||||
3000.0,
|
||||
0.5,
|
||||
'PRESS')
|
||||
if ami:
|
||||
vr_defaults_actionbinding_add(ami,
|
||||
VRDefaultActionbindings.HUAWEI.value,
|
||||
VRDefaultActionprofiles.HUAWEI.value,
|
||||
["/input/home/click",
|
||||
"/input/home/click"],
|
||||
0.3,
|
||||
'ANY',
|
||||
'ANY')
|
||||
vr_defaults_actionbinding_add(ami,
|
||||
VRDefaultActionbindings.INDEX.value,
|
||||
VRDefaultActionprofiles.INDEX.value,
|
||||
["/input/b/click",
|
||||
"/input/b/click"],
|
||||
0.3,
|
||||
'ANY',
|
||||
'ANY')
|
||||
vr_defaults_actionbinding_add(ami,
|
||||
VRDefaultActionbindings.OCULUS.value,
|
||||
VRDefaultActionprofiles.OCULUS.value,
|
||||
["/input/y/click",
|
||||
"/input/b/click"],
|
||||
0.3,
|
||||
'ANY',
|
||||
'ANY')
|
||||
vr_defaults_actionbinding_add(ami,
|
||||
VRDefaultActionbindings.REVERB_G2.value,
|
||||
VRDefaultActionprofiles.REVERB_G2.value,
|
||||
["/input/y/click",
|
||||
"/input/b/click"],
|
||||
0.3,
|
||||
'ANY',
|
||||
'ANY')
|
||||
vr_defaults_actionbinding_add(ami,
|
||||
VRDefaultActionbindings.VIVE.value,
|
||||
VRDefaultActionprofiles.VIVE.value,
|
||||
["/input/menu/click",
|
||||
"/input/menu/click"],
|
||||
0.3,
|
||||
'ANY',
|
||||
'ANY')
|
||||
vr_defaults_actionbinding_add(ami,
|
||||
VRDefaultActionbindings.VIVE_COSMOS.value,
|
||||
VRDefaultActionprofiles.VIVE_COSMOS.value,
|
||||
["/input/y/click",
|
||||
"/input/b/click"],
|
||||
0.3,
|
||||
'ANY',
|
||||
'ANY')
|
||||
vr_defaults_actionbinding_add(ami,
|
||||
VRDefaultActionbindings.VIVE_FOCUS.value,
|
||||
VRDefaultActionprofiles.VIVE_FOCUS.value,
|
||||
["/input/y/click",
|
||||
"/input/b/click"],
|
||||
0.3,
|
||||
'ANY',
|
||||
'ANY')
|
||||
vr_defaults_actionbinding_add(ami,
|
||||
VRDefaultActionbindings.WMR.value,
|
||||
VRDefaultActionprofiles.WMR.value,
|
||||
["/input/menu/click",
|
||||
"/input/menu/click"],
|
||||
0.3,
|
||||
'ANY',
|
||||
'ANY')
|
||||
|
||||
ami = vr_defaults_action_add(am,
|
||||
VRDefaultActions.VIEWFINDER_APPLY_ACTION_DOWN.value,
|
||||
["/user/hand/left",
|
||||
"/user/hand/right"],
|
||||
"view3d.vr_location_scouting_viewfinder_apply_action",
|
||||
'PRESS',
|
||||
False,
|
||||
"haptic",
|
||||
True,
|
||||
0.3,
|
||||
3000.0,
|
||||
0.5,
|
||||
'PRESS')
|
||||
if ami:
|
||||
vr_defaults_actionbinding_add(ami,
|
||||
VRDefaultActionbindings.HUAWEI.value,
|
||||
VRDefaultActionprofiles.HUAWEI.value,
|
||||
["/input/back/click",
|
||||
"/input/back/click"],
|
||||
0.3,
|
||||
'ANY',
|
||||
'ANY')
|
||||
vr_defaults_actionbinding_add(ami,
|
||||
VRDefaultActionbindings.INDEX.value,
|
||||
VRDefaultActionprofiles.INDEX.value,
|
||||
["/input/a/click",
|
||||
"/input/a/click"],
|
||||
0.3,
|
||||
'ANY',
|
||||
'ANY')
|
||||
vr_defaults_actionbinding_add(ami,
|
||||
VRDefaultActionbindings.OCULUS.value,
|
||||
VRDefaultActionprofiles.OCULUS.value,
|
||||
["/input/x/click",
|
||||
"/input/a/click"],
|
||||
0.3,
|
||||
'ANY',
|
||||
'ANY')
|
||||
vr_defaults_actionbinding_add(ami,
|
||||
VRDefaultActionbindings.REVERB_G2.value,
|
||||
VRDefaultActionprofiles.REVERB_G2.value,
|
||||
["/input/x/click",
|
||||
"/input/a/click"],
|
||||
0.3,
|
||||
'ANY',
|
||||
'ANY')
|
||||
vr_defaults_actionbinding_add(ami,
|
||||
VRDefaultActionbindings.VIVE.value,
|
||||
VRDefaultActionprofiles.VIVE.value,
|
||||
["/input/menu/click",
|
||||
"/input/menu/click"],
|
||||
0.3,
|
||||
'ANY',
|
||||
'ANY')
|
||||
vr_defaults_actionbinding_add(ami,
|
||||
VRDefaultActionbindings.VIVE_COSMOS.value,
|
||||
VRDefaultActionprofiles.VIVE_COSMOS.value,
|
||||
["/input/x/click",
|
||||
"/input/a/click"],
|
||||
0.3,
|
||||
'ANY',
|
||||
'ANY')
|
||||
vr_defaults_actionbinding_add(ami,
|
||||
VRDefaultActionbindings.VIVE_FOCUS.value,
|
||||
VRDefaultActionprofiles.VIVE_FOCUS.value,
|
||||
["/input/x/click",
|
||||
"/input/a/click"],
|
||||
0.3,
|
||||
'ANY',
|
||||
'ANY')
|
||||
vr_defaults_actionbinding_add(ami,
|
||||
VRDefaultActionbindings.WMR.value,
|
||||
VRDefaultActionprofiles.WMR.value,
|
||||
["/input/menu/click",
|
||||
"/input/menu/click"],
|
||||
0.3,
|
||||
'ANY',
|
||||
'ANY')
|
||||
|
||||
ami = vr_defaults_action_add(am,
|
||||
VRDefaultActions.VIEWFINDER_SWAP_HANDS.value,
|
||||
["/user/hand/left",
|
||||
"/user/hand/right"],
|
||||
"view3d.vr_location_scouting_viewfinder_swap_hands",
|
||||
'PRESS',
|
||||
False,
|
||||
"haptic",
|
||||
True,
|
||||
0.3,
|
||||
3000.0,
|
||||
0.5,
|
||||
'PRESS')
|
||||
if ami:
|
||||
vr_defaults_actionbinding_add(ami,
|
||||
VRDefaultActionbindings.HUAWEI.value,
|
||||
VRDefaultActionprofiles.HUAWEI.value,
|
||||
["/input/trackpad/click",
|
||||
"/input/trackpad/click"],
|
||||
0.3,
|
||||
'ANY',
|
||||
'ANY')
|
||||
vr_defaults_actionbinding_add(ami,
|
||||
VRDefaultActionbindings.INDEX.value,
|
||||
VRDefaultActionprofiles.INDEX.value,
|
||||
["/input/thumbstick/click",
|
||||
"/input/thumbstick/click"],
|
||||
0.3,
|
||||
'ANY',
|
||||
'ANY')
|
||||
vr_defaults_actionbinding_add(ami,
|
||||
VRDefaultActionbindings.OCULUS.value,
|
||||
VRDefaultActionprofiles.OCULUS.value,
|
||||
["/input/thumbstick/click",
|
||||
"/input/thumbstick/click"],
|
||||
0.3,
|
||||
'ANY',
|
||||
'ANY')
|
||||
vr_defaults_actionbinding_add(ami,
|
||||
VRDefaultActionbindings.REVERB_G2.value,
|
||||
VRDefaultActionprofiles.REVERB_G2.value,
|
||||
["/input/thumbstick/click",
|
||||
"/input/thumbstick/click"],
|
||||
0.3,
|
||||
'ANY',
|
||||
'ANY')
|
||||
vr_defaults_actionbinding_add(ami,
|
||||
VRDefaultActionbindings.VIVE.value,
|
||||
VRDefaultActionprofiles.VIVE.value,
|
||||
["/input/trackpad/click",
|
||||
"/input/trackpad/click"],
|
||||
0.3,
|
||||
'ANY',
|
||||
'ANY')
|
||||
vr_defaults_actionbinding_add(ami,
|
||||
VRDefaultActionbindings.VIVE_COSMOS.value,
|
||||
VRDefaultActionprofiles.VIVE_COSMOS.value,
|
||||
["/input/thumbstick/click",
|
||||
"/input/thumbstick/click"],
|
||||
0.3,
|
||||
'ANY',
|
||||
'ANY')
|
||||
vr_defaults_actionbinding_add(ami,
|
||||
VRDefaultActionbindings.VIVE_FOCUS.value,
|
||||
VRDefaultActionprofiles.VIVE_FOCUS.value,
|
||||
["/input/thumbstick/click",
|
||||
"/input/thumbstick/click"],
|
||||
0.3,
|
||||
'ANY',
|
||||
'ANY')
|
||||
vr_defaults_actionbinding_add(ami,
|
||||
VRDefaultActionbindings.WMR.value,
|
||||
VRDefaultActionprofiles.WMR.value,
|
||||
["/input/thumbstick/click",
|
||||
"/input/thumbstick/click"],
|
||||
0.3,
|
||||
'ANY',
|
||||
'ANY')
|
||||
|
||||
ami = vr_defaults_action_add(am,
|
||||
VRDefaultActions.SWAP_HANDS.value,
|
||||
["/user/hand/left",
|
||||
|
|
|
|||
|
|
@ -26,11 +26,14 @@ sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '../../s
|
|||
from space_view3d import VIEW3D_PT_object_type_visibility
|
||||
|
||||
|
||||
# Session.
|
||||
class VIEW3D_PT_vr_session(Panel):
|
||||
class VRButtonsPanel:
|
||||
bl_space_type = 'VIEW_3D'
|
||||
bl_region_type = 'UI'
|
||||
bl_category = "VR"
|
||||
|
||||
|
||||
# Session.
|
||||
class VIEW3D_PT_vr_session(VRButtonsPanel, Panel):
|
||||
bl_label = "VR Session"
|
||||
|
||||
def draw(self, context):
|
||||
|
|
@ -61,10 +64,7 @@ class VIEW3D_PT_vr_session(Panel):
|
|||
|
||||
|
||||
# View.
|
||||
class VIEW3D_PT_vr_session_view(Panel):
|
||||
bl_space_type = 'VIEW_3D'
|
||||
bl_region_type = 'UI'
|
||||
bl_category = "VR"
|
||||
class VIEW3D_PT_vr_session_view(VRButtonsPanel, Panel):
|
||||
bl_label = "View"
|
||||
|
||||
def draw(self, context):
|
||||
|
|
@ -112,6 +112,104 @@ class VIEW3D_PT_vr_session_view_object_type_visibility(VIEW3D_PT_object_type_vis
|
|||
self.draw_ex(context, session_settings, False) # Pass session settings instead of 3D view.
|
||||
|
||||
|
||||
# Location Scouting.
|
||||
class VIEW3D_UL_vr_captures(UIList):
|
||||
def draw_item(self, context, layout, _data, item, icon, _active_data, _active_propname, index):
|
||||
capture = item
|
||||
|
||||
layout.emboss = 'NONE'
|
||||
|
||||
layout.label(icon='OUTLINER_OB_CAMERA')
|
||||
layout.prop(capture, "name", text="")
|
||||
|
||||
|
||||
class VIEW3D_PT_vr_location_scouting(VRButtonsPanel, Panel):
|
||||
bl_label = "Location Scouting"
|
||||
bl_options = {'DEFAULT_CLOSED'}
|
||||
|
||||
def draw(self, context):
|
||||
pass
|
||||
|
||||
|
||||
class VIEW3D_PT_vr_location_scouting_captures(VRButtonsPanel, Panel):
|
||||
bl_label = "Captured Shots"
|
||||
bl_parent_id = "VIEW3D_PT_vr_location_scouting"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
scene = context.scene
|
||||
|
||||
row = layout.row()
|
||||
row.template_list("VIEW3D_UL_vr_captures", "", scene, "vr_captures", scene, "vr_captures_selected", rows=5)
|
||||
|
||||
col = row.column(align=True)
|
||||
|
||||
col.operator("view3d.vr_location_scouting_remove_capture", icon='REMOVE', text="")
|
||||
|
||||
col.separator()
|
||||
|
||||
col.operator("view3d.vr_location_scouting_add_camera_from_capture", icon='OUTLINER_OB_CAMERA', text="")
|
||||
col.operator("view3d.vr_location_scouting_add_marker_from_capture", icon='MARKER', text="")
|
||||
|
||||
col.separator()
|
||||
|
||||
col.operator("view3d.vr_location_scouting_browse_captures", icon='TRIA_UP', text="").backward = True
|
||||
col.operator("view3d.vr_location_scouting_browse_captures", icon='TRIA_DOWN', text="").backward = False
|
||||
|
||||
is_reviewing = context.window_manager.vr_capture_review_running
|
||||
capture_review_text = "Review VR Captures" if not is_reviewing else "Exit Review"
|
||||
capture_review_icon = 'HIDE_OFF' if not is_reviewing else 'CANCEL'
|
||||
layout.operator(
|
||||
"view3d.vr_location_scouting_capture_review",
|
||||
text=capture_review_text,
|
||||
icon=capture_review_icon,
|
||||
depress=is_reviewing)
|
||||
|
||||
|
||||
class VIEW3D_PT_vr_location_scouting_viewfinder(VRButtonsPanel, Panel):
|
||||
bl_label = "VR Viewfinder"
|
||||
bl_parent_id = "VIEW3D_PT_vr_location_scouting"
|
||||
|
||||
def draw_header(self, context):
|
||||
layout = self.layout
|
||||
session_settings = context.window_manager.xr_session_settings
|
||||
|
||||
layout.prop(session_settings, "viewfinder_enabled", text="")
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
session_settings = context.window_manager.xr_session_settings
|
||||
|
||||
layout.enabled = session_settings.viewfinder_enabled
|
||||
session_settings = context.window_manager.xr_session_settings
|
||||
|
||||
layout.use_property_split = True
|
||||
|
||||
layout.prop(session_settings, "viewfinder_hand", text="Hand", expand=True)
|
||||
layout.prop(session_settings, "viewfinder_scale", text="Scale")
|
||||
|
||||
col = layout.column(align=True, heading="Display")
|
||||
col.prop(session_settings, "viewfinder_crosshair_enabled", text="Crosshair")
|
||||
|
||||
|
||||
class VIEW3D_PT_vr_location_scouting_viewfinder_passepartout(VRButtonsPanel, Panel):
|
||||
bl_label = "Passepartout"
|
||||
bl_parent_id = "VIEW3D_PT_vr_location_scouting_viewfinder"
|
||||
bl_options = {'DEFAULT_CLOSED'}
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
session_settings = context.window_manager.xr_session_settings
|
||||
|
||||
layout.enabled = session_settings.viewfinder_enabled
|
||||
session_settings = context.window_manager.xr_session_settings
|
||||
|
||||
layout.use_property_split = True
|
||||
|
||||
layout.prop(session_settings, "viewfinder_passepartout_overscan", text="Overscan")
|
||||
layout.prop(session_settings, "viewfinder_passepartout_opacity", text="Opacity")
|
||||
|
||||
|
||||
# Landmarks.
|
||||
class VIEW3D_MT_vr_landmark_menu(Menu):
|
||||
bl_label = "Landmark Controls"
|
||||
|
|
@ -146,10 +244,7 @@ class VIEW3D_UL_vr_landmarks(UIList):
|
|||
props.index = index
|
||||
|
||||
|
||||
class VIEW3D_PT_vr_landmarks(Panel):
|
||||
bl_space_type = 'VIEW_3D'
|
||||
bl_region_type = 'UI'
|
||||
bl_category = "VR"
|
||||
class VIEW3D_PT_vr_landmarks(VRButtonsPanel, Panel):
|
||||
bl_label = "Landmarks"
|
||||
bl_options = {'DEFAULT_CLOSED'}
|
||||
|
||||
|
|
@ -189,10 +284,7 @@ class VIEW3D_PT_vr_landmarks(Panel):
|
|||
|
||||
|
||||
# Actions.
|
||||
class VIEW3D_PT_vr_actionmaps(Panel):
|
||||
bl_space_type = 'VIEW_3D'
|
||||
bl_region_type = 'UI'
|
||||
bl_category = "VR"
|
||||
class VIEW3D_PT_vr_actionmaps(VRButtonsPanel, Panel):
|
||||
bl_label = "Action Maps"
|
||||
bl_options = {'DEFAULT_CLOSED'}
|
||||
|
||||
|
|
@ -214,17 +306,13 @@ class VIEW3D_PT_vr_actionmaps(Panel):
|
|||
|
||||
|
||||
# Viewport feedback.
|
||||
class VIEW3D_PT_vr_viewport_feedback(Panel):
|
||||
bl_space_type = 'VIEW_3D'
|
||||
bl_region_type = 'UI'
|
||||
bl_category = "VR"
|
||||
class VIEW3D_PT_vr_viewport_feedback(VRButtonsPanel, Panel):
|
||||
bl_label = "Viewport Feedback"
|
||||
bl_options = {'DEFAULT_CLOSED'}
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
view3d = context.space_data
|
||||
session_settings = context.window_manager.xr_session_settings
|
||||
|
||||
col = layout.column(align=True)
|
||||
col.label(icon='ERROR', text="Note:")
|
||||
|
|
@ -236,14 +324,12 @@ class VIEW3D_PT_vr_viewport_feedback(Panel):
|
|||
layout.prop(view3d.shading, "vr_show_virtual_camera")
|
||||
layout.prop(view3d.shading, "vr_show_controllers")
|
||||
layout.prop(view3d.shading, "vr_show_landmarks")
|
||||
layout.prop(view3d.shading, "vr_show_captures")
|
||||
layout.prop(view3d, "mirror_xr_session")
|
||||
|
||||
|
||||
# Info.
|
||||
class VIEW3D_PT_vr_info(bpy.types.Panel):
|
||||
bl_space_type = 'VIEW_3D'
|
||||
bl_region_type = 'UI'
|
||||
bl_category = "VR"
|
||||
class VIEW3D_PT_vr_info(VRButtonsPanel, Panel):
|
||||
bl_label = "VR Info"
|
||||
|
||||
@classmethod
|
||||
|
|
@ -261,11 +347,16 @@ classes = (
|
|||
VIEW3D_PT_vr_session,
|
||||
VIEW3D_PT_vr_session_view,
|
||||
VIEW3D_PT_vr_session_view_object_type_visibility,
|
||||
VIEW3D_PT_vr_location_scouting,
|
||||
VIEW3D_PT_vr_location_scouting_captures,
|
||||
VIEW3D_PT_vr_location_scouting_viewfinder,
|
||||
VIEW3D_PT_vr_location_scouting_viewfinder_passepartout,
|
||||
VIEW3D_PT_vr_landmarks,
|
||||
VIEW3D_PT_vr_actionmaps,
|
||||
VIEW3D_PT_vr_viewport_feedback,
|
||||
|
||||
VIEW3D_UL_vr_landmarks,
|
||||
VIEW3D_UL_vr_captures,
|
||||
VIEW3D_MT_vr_landmark_menu,
|
||||
)
|
||||
|
||||
|
|
@ -277,13 +368,20 @@ def register():
|
|||
# View3DShading is the only per 3D-View struct with custom property
|
||||
# support, so "abusing" that to get a per 3D-View option.
|
||||
bpy.types.View3DShading.vr_show_virtual_camera = bpy.props.BoolProperty(
|
||||
name="Show VR Camera"
|
||||
name="Show VR Camera",
|
||||
default=False
|
||||
)
|
||||
bpy.types.View3DShading.vr_show_controllers = bpy.props.BoolProperty(
|
||||
name="Show VR Controllers"
|
||||
name="Show VR Controllers",
|
||||
default=False
|
||||
)
|
||||
bpy.types.View3DShading.vr_show_landmarks = bpy.props.BoolProperty(
|
||||
name="Show Landmarks"
|
||||
name="Show Landmarks",
|
||||
default=False
|
||||
)
|
||||
bpy.types.View3DShading.vr_show_captures = bpy.props.BoolProperty(
|
||||
name="Show Location Scouting Captures",
|
||||
default=True
|
||||
)
|
||||
|
||||
|
||||
|
|
@ -294,3 +392,4 @@ def unregister():
|
|||
del bpy.types.View3DShading.vr_show_virtual_camera
|
||||
del bpy.types.View3DShading.vr_show_controllers
|
||||
del bpy.types.View3DShading.vr_show_landmarks
|
||||
del bpy.types.View3DShading.vr_show_captures
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ from bpy.types import (
|
|||
)
|
||||
import math
|
||||
from math import radians
|
||||
from mathutils import Euler, Matrix, Quaternion, Vector
|
||||
from mathutils import Color, Euler, Matrix, Quaternion, Vector
|
||||
|
||||
|
||||
# Landmarks.
|
||||
|
|
@ -275,22 +275,567 @@ class VIEW3D_OT_vr_landmark_activate(Operator):
|
|||
return {'FINISHED'}
|
||||
|
||||
|
||||
# Location Scouting Viewfinder
|
||||
def viewfinder_camera_gizmo_view3d_redraw_workaround():
|
||||
# Workaround: After capturing or deleting a shot from the VR viewfinder, tag all View3D areas in the current context
|
||||
# window (parent XR window) for redraw to display the newly created/deleted captures.
|
||||
# The alternative to this is to give the capture camera Gizmo (VIEW3D_GGT_vr_captures) the VR_REDRAWS
|
||||
# option, however this makes it constantly redraw, causing performances to drop.
|
||||
|
||||
window = bpy.context.window
|
||||
|
||||
areas = [area for area in window.screen.areas if area.type == 'VIEW_3D']
|
||||
for area in areas:
|
||||
view3d_region = [region for region in area.regions if region.type == 'WINDOW'][0]
|
||||
with bpy.context.temp_override(
|
||||
window=window,
|
||||
area=area,
|
||||
region=view3d_region,
|
||||
screen=window.screen
|
||||
):
|
||||
bpy.context.region.tag_redraw()
|
||||
|
||||
|
||||
def xr_event_match_viewfinder_hand(xr_event, xr_settings):
|
||||
# Check if the current XR event matches with the Viewfinder hand. Equivalent to the internal
|
||||
# wm_xr_operator_event_match_viewfinder_hand C++ function.
|
||||
hand_user_path_map = {
|
||||
'LEFT': "/user/hand/left",
|
||||
'RIGHT': "/user/hand/right"
|
||||
}
|
||||
|
||||
return xr_event.user_path == hand_user_path_map[xr_settings.viewfinder_hand]
|
||||
|
||||
|
||||
class VIEW3D_OT_vr_location_scouting_viewfinder_capture(Operator):
|
||||
bl_idname = "view3d.vr_location_scouting_viewfinder_capture"
|
||||
bl_label = "Viewfinder Capture"
|
||||
bl_description = "Create a VR Capture from the Viewfinder pose and mark it as selected"
|
||||
bl_options = {'UNDO', 'INTERNAL'}
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
session_is_running = bpy.types.XrSessionState.is_running(context)
|
||||
|
||||
xr_settings = context.window_manager.xr_session_settings
|
||||
xr_viewfinder = context.window_manager.xr_session_state.viewfinder
|
||||
|
||||
viewfinder_enabled = xr_settings.viewfinder_enabled
|
||||
viewfinder_in_live_mode = xr_viewfinder.active_mode == "LIVE"
|
||||
|
||||
return session_is_running and viewfinder_enabled and viewfinder_in_live_mode
|
||||
|
||||
def execute(self, context):
|
||||
scene = context.scene
|
||||
captures = scene.vr_captures
|
||||
|
||||
wm = context.window_manager
|
||||
xr_viewfinder = wm.xr_session_state.viewfinder
|
||||
|
||||
# Returns the first available name in the style (Base_001, Base_002, Base_003, etc...).
|
||||
def unique_name(col, base: str) -> str:
|
||||
existing_indexes = set()
|
||||
|
||||
for item in col:
|
||||
name = item.name
|
||||
if name.startswith(base) and len(name) == len(base) + 4:
|
||||
suffix = name[len(base) + 1:]
|
||||
if suffix.isdigit():
|
||||
existing_indexes.add(int(suffix))
|
||||
|
||||
idx = 1
|
||||
while idx in existing_indexes:
|
||||
idx += 1
|
||||
|
||||
return f"{base}_{idx:03d}"
|
||||
|
||||
capture = captures.add()
|
||||
captures[-1].name = unique_name(captures, "Capture")
|
||||
scene.vr_captures_selected = len(captures) - 1
|
||||
|
||||
capture.location = xr_viewfinder.location
|
||||
capture.orientation = xr_viewfinder.orientation
|
||||
|
||||
capture.lens_focal = xr_viewfinder.capture_lens_focal
|
||||
capture.dof_enabled = xr_viewfinder.capture_dof_enabled
|
||||
capture.dof_distance = xr_viewfinder.capture_dof_distance
|
||||
capture.dof_fstop = xr_viewfinder.capture_dof_fstop
|
||||
|
||||
xr_viewfinder.trigger_flash()
|
||||
|
||||
viewfinder_camera_gizmo_view3d_redraw_workaround()
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
def invoke(self, context, event):
|
||||
xr_event = event.xr
|
||||
xr_settings = context.window_manager.xr_session_settings
|
||||
|
||||
if not xr_event_match_viewfinder_hand(xr_event, xr_settings):
|
||||
return {'CANCELLED'}
|
||||
|
||||
return self.execute(context)
|
||||
|
||||
|
||||
class VIEW3D_OT_vr_location_scouting_viewfinder_apply_action(Operator):
|
||||
bl_idname = "view3d.vr_location_scouting_viewfinder_apply_action"
|
||||
bl_label = "Viewfinder Apply Action"
|
||||
bl_description = "Apply the currently selected Viewfinder action (Zoom Control/Playback selection for now)"
|
||||
bl_options = {'INTERNAL'}
|
||||
|
||||
# Differentiate between an up and down action (two possible buttons).
|
||||
action_up: bpy.props.BoolProperty(
|
||||
name="Is Up Action",
|
||||
options={'HIDDEN'},
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def get_next_in_map(current, map_, up_dir) -> int:
|
||||
# Find the closest map idx to the `current` value.
|
||||
diff_list = [abs(elem - current) for elem in map_]
|
||||
current_idx = diff_list.index(min(diff_list))
|
||||
|
||||
# Find the next element going up or down, clamping at bounds.
|
||||
if up_dir:
|
||||
# Zoom in
|
||||
next_idx = min(current_idx + 1, len(map_) - 1)
|
||||
else:
|
||||
# Zoom out
|
||||
next_idx = max(current_idx - 1, 0)
|
||||
|
||||
return next_idx
|
||||
|
||||
@staticmethod
|
||||
def focus_distance_raycast(context, view_origin, view_quat):
|
||||
scene = context.scene
|
||||
depsgraph = context.evaluated_depsgraph_get()
|
||||
|
||||
direction = Vector((0.0, 0.0, -1.0))
|
||||
world_dir = view_quat @ direction
|
||||
world_dir.normalize()
|
||||
|
||||
hit_success, hit_location, _, _, _, _ = scene.ray_cast(depsgraph, view_origin, world_dir)
|
||||
|
||||
if hit_success:
|
||||
return (hit_location - view_origin).length
|
||||
|
||||
return None
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
session_is_running = bpy.types.XrSessionState.is_running(context)
|
||||
has_scene_camera = context.scene.camera is not None
|
||||
viewfinder_enabled = context.window_manager.xr_session_settings.viewfinder_enabled
|
||||
|
||||
return session_is_running and has_scene_camera and viewfinder_enabled
|
||||
|
||||
def execute(self, context):
|
||||
wm = context.window_manager
|
||||
scene = context.scene
|
||||
|
||||
xr_viewfinder = wm.xr_session_state.viewfinder
|
||||
captures = scene.vr_captures
|
||||
|
||||
if xr_viewfinder.active_mode == 'LIVE':
|
||||
focal_map = (18, 20, 24, 28, 35, 50, 70, 85, 100, 135, 200, 300)
|
||||
fstop_map = (0.1, 0.2, 0.4, 0.8, 1, 1.2, 1.4, 1.7, 2, 2.4, 2.8, 3.3,
|
||||
4, 4.8, 5.6, 6.7, 8, 9.5, 11, 13, 16, 19, 22, 27, 32)
|
||||
|
||||
match xr_viewfinder.active_action_live:
|
||||
# View Zoom Control.
|
||||
case 'LENS':
|
||||
current_focal = xr_viewfinder.capture_lens_focal
|
||||
|
||||
new_idx = self.get_next_in_map(current_focal, focal_map, self.action_up)
|
||||
xr_viewfinder.capture_lens_focal = focal_map[new_idx]
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
# Toggle DoF on/off.
|
||||
case 'DOF':
|
||||
xr_viewfinder.capture_dof_enabled = not xr_viewfinder.capture_dof_enabled
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
# Focus distance control (ray-cast autofocus).
|
||||
case 'FOCUS':
|
||||
raycast_hit = self.focus_distance_raycast(context,
|
||||
xr_viewfinder.location,
|
||||
xr_viewfinder.orientation)
|
||||
|
||||
if raycast_hit is not None:
|
||||
xr_viewfinder.capture_dof_distance = raycast_hit
|
||||
|
||||
xr_viewfinder.trigger_focus_indicator(raycast_hit is not None)
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
# F-Stop control.
|
||||
case 'APERTURE':
|
||||
current_fstop = xr_viewfinder.capture_dof_fstop
|
||||
|
||||
new_idx = self.get_next_in_map(current_fstop, fstop_map, self.action_up)
|
||||
xr_viewfinder.capture_dof_fstop = fstop_map[new_idx]
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
if xr_viewfinder.active_mode == 'PLAYBACK':
|
||||
# Playblack control.
|
||||
if len(captures) == 0:
|
||||
return {'FINISHED'}
|
||||
|
||||
match xr_viewfinder.active_action_playback:
|
||||
# Browse shots left/right.
|
||||
case 'BROWSE':
|
||||
incr = 1 if self.action_up else -1
|
||||
scene.vr_captures_selected = (scene.vr_captures_selected + incr) % len(captures)
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
# Preview the selected capture in space toggle.
|
||||
case 'PREVIEW':
|
||||
xr_viewfinder.playback_show_active_capture_in_space_enabled = not xr_viewfinder.playback_show_active_capture_in_space_enabled
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
# Delete, switch to Confirm mode to confirm capture deletion.
|
||||
case 'DELETE':
|
||||
xr_viewfinder.active_mode = 'CONFIRM'
|
||||
# Set base action to Cancel, user has to explicitly switch to the Confirm action.
|
||||
xr_viewfinder.active_action_confirm = 'CANCEL'
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
if xr_viewfinder.active_mode == 'CONFIRM':
|
||||
# Confirm mode, currently only used for capture deletion, and only
|
||||
# accessible from the 'DELETE' Playback action.
|
||||
match xr_viewfinder.active_action_confirm:
|
||||
# Cancel, simply switch back to Playback mode.
|
||||
case 'CANCEL':
|
||||
xr_viewfinder.active_mode = 'PLAYBACK'
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
# Confirm, delete the selected capture, switch back to Playback mode.
|
||||
case 'CONFIRM':
|
||||
captures.remove(scene.vr_captures_selected)
|
||||
if scene.vr_captures_selected > 0:
|
||||
scene.vr_captures_selected -= 1
|
||||
|
||||
viewfinder_camera_gizmo_view3d_redraw_workaround()
|
||||
|
||||
xr_viewfinder.active_mode = 'PLAYBACK'
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
return {'CANCELLED'}
|
||||
|
||||
def invoke(self, context, event):
|
||||
xr_event = event.xr
|
||||
xr_settings = context.window_manager.xr_session_settings
|
||||
|
||||
if not xr_event_match_viewfinder_hand(xr_event, xr_settings):
|
||||
return {'CANCELLED'}
|
||||
|
||||
return self.execute(context)
|
||||
|
||||
|
||||
class VIEW3D_OT_vr_location_scouting_viewfinder_cycle_mode(Operator):
|
||||
bl_idname = "view3d.vr_location_scouting_viewfinder_cycle_mode"
|
||||
bl_label = "Viewfinder Cycle Mode"
|
||||
bl_description = "Cycle the currently active Viewfinder mode"
|
||||
bl_options = {'INTERNAL'}
|
||||
|
||||
def execute(self, context):
|
||||
xr_viewfinder = context.window_manager.xr_session_state.viewfinder
|
||||
|
||||
# Limit cycling to Live and Playback, Confirm being an internal mode used for capture deletion.
|
||||
enum_values = ['LIVE', 'PLAYBACK']
|
||||
if xr_viewfinder.active_mode not in enum_values:
|
||||
return {'CANCELLED'}
|
||||
|
||||
current_mode_idx = enum_values.index(xr_viewfinder.active_mode)
|
||||
|
||||
xr_viewfinder.active_mode = enum_values[(current_mode_idx + 1) % len(enum_values)]
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
def invoke(self, context, event):
|
||||
xr_event = event.xr
|
||||
xr_settings = context.window_manager.xr_session_settings
|
||||
|
||||
if not xr_event_match_viewfinder_hand(xr_event, xr_settings):
|
||||
return {'CANCELLED'}
|
||||
|
||||
return self.execute(context)
|
||||
|
||||
|
||||
class VIEW3D_OT_vr_location_scouting_viewfinder_cycle_action(Operator):
|
||||
bl_idname = "view3d.vr_location_scouting_viewfinder_cycle_action"
|
||||
bl_label = "Viewfinder Cycle Action"
|
||||
bl_description = "Cycle the currently active Viewfinder action left or right"
|
||||
bl_options = {'INTERNAL'}
|
||||
|
||||
cycle_left: bpy.props.BoolProperty(
|
||||
name="Cycle Left",
|
||||
default=False,
|
||||
options={'HIDDEN', 'SKIP_SAVE'},
|
||||
)
|
||||
|
||||
def execute(self, context):
|
||||
xr_viewfinder = context.window_manager.xr_session_state.viewfinder
|
||||
|
||||
increment = -1 if self.cycle_left else 1
|
||||
|
||||
match xr_viewfinder.active_mode:
|
||||
case 'LIVE':
|
||||
action_rna_prop = xr_viewfinder.rna_type.properties["active_action_live"]
|
||||
enum_keys = action_rna_prop.enum_items.keys()
|
||||
current_action_idx = enum_keys.index(xr_viewfinder.active_action_live)
|
||||
|
||||
# Special case: only allow cycling to non-DoF action if DoF is not enabled
|
||||
enum_length = len(enum_keys) if xr_viewfinder.capture_dof_enabled else (enum_keys.index('DOF') + 1)
|
||||
new_action_idx = (current_action_idx + increment) % enum_length
|
||||
|
||||
xr_viewfinder.active_action_live = enum_keys[new_action_idx]
|
||||
|
||||
case 'PLAYBACK':
|
||||
action_rna_prop = xr_viewfinder.rna_type.properties["active_action_playback"]
|
||||
enum_keys = action_rna_prop.enum_items.keys()
|
||||
current_action_idx = enum_keys.index(xr_viewfinder.active_action_playback)
|
||||
new_action_idx = (current_action_idx + increment) % len(enum_keys)
|
||||
|
||||
xr_viewfinder.active_action_playback = enum_keys[new_action_idx]
|
||||
|
||||
case 'CONFIRM':
|
||||
action_rna_prop = xr_viewfinder.rna_type.properties["active_action_confirm"]
|
||||
enum_keys = action_rna_prop.enum_items.keys()
|
||||
current_action_idx = enum_keys.index(xr_viewfinder.active_action_confirm)
|
||||
new_action_idx = (current_action_idx + increment) % len(enum_keys)
|
||||
|
||||
xr_viewfinder.active_action_confirm = enum_keys[new_action_idx]
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
def invoke(self, context, event):
|
||||
xr_event = event.xr
|
||||
xr_settings = context.window_manager.xr_session_settings
|
||||
|
||||
if not xr_event_match_viewfinder_hand(xr_event, xr_settings):
|
||||
return {'CANCELLED'}
|
||||
|
||||
axis_value = xr_event.state[0]
|
||||
self.cycle_left = axis_value <= 0
|
||||
|
||||
return self.execute(context)
|
||||
|
||||
|
||||
class VIEW3D_OT_vr_location_scouting_viewfinder_swap_hands(Operator):
|
||||
bl_idname = "view3d.vr_location_scouting_viewfinder_swap_hands"
|
||||
bl_label = "Viewfinder Swap Hands"
|
||||
bl_description = "Swap user hand used to hold the Viewfinder"
|
||||
bl_options = {'INTERNAL'}
|
||||
|
||||
def execute(self, context):
|
||||
xr_viewfinder = context.window_manager.xr_session_state.viewfinder
|
||||
xr_settings = context.window_manager.xr_session_settings
|
||||
|
||||
viewfinder_hand_rna_prop = xr_settings.rna_type.properties['viewfinder_hand']
|
||||
enum_values = viewfinder_hand_rna_prop.enum_items.keys()
|
||||
current_hand_idx = enum_values.index(xr_settings.viewfinder_hand)
|
||||
|
||||
xr_settings.viewfinder_hand = enum_values[(current_hand_idx + 1) % len(enum_values)]
|
||||
|
||||
xr_viewfinder.reset_view_smoothing()
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
def invoke(self, context, _event):
|
||||
xr_settings = context.window_manager.xr_session_settings
|
||||
|
||||
if not xr_settings.viewfinder_enabled:
|
||||
return {'CANCELLED'}
|
||||
|
||||
return self.execute(context)
|
||||
|
||||
|
||||
# Location Scouting Captures
|
||||
def capture_camera_name(capture):
|
||||
return data_("Camera") + "_" + capture.name
|
||||
|
||||
|
||||
def add_camera_from_capture(scene, capture):
|
||||
cam = bpy.data.cameras.new(capture_camera_name(capture))
|
||||
new_cam = bpy.data.objects.new(capture_camera_name(capture), cam)
|
||||
scene.collection.objects.link(new_cam)
|
||||
|
||||
new_cam.location = capture.location
|
||||
new_cam.rotation_mode = 'QUATERNION'
|
||||
new_cam.rotation_quaternion = capture.orientation
|
||||
new_cam.rotation_mode = 'XYZ'
|
||||
|
||||
new_cam.data.lens = capture.lens_focal
|
||||
new_cam.data.dof.use_dof = capture.dof_enabled
|
||||
new_cam.data.dof.focus_distance = capture.dof_distance
|
||||
new_cam.data.dof.aperture_fstop = capture.dof_fstop
|
||||
|
||||
return new_cam
|
||||
|
||||
|
||||
class VIEW3D_OT_vr_location_scouting_add_camera_from_capture(Operator):
|
||||
bl_idname = "view3d.vr_location_scouting_add_camera_from_capture"
|
||||
bl_label = "Add Camera from VR Capture"
|
||||
bl_description = "Create a new Camera Object from the selected VR Capture"
|
||||
bl_options = {'UNDO', 'REGISTER'}
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return len(context.scene.vr_captures) > 0
|
||||
|
||||
def execute(self, context):
|
||||
scene = context.scene
|
||||
capture = properties.VRCapture.get_selected_capture(context)
|
||||
|
||||
add_camera_from_capture(scene, capture)
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
class VIEW3D_OT_vr_location_scouting_add_marker_from_capture(Operator):
|
||||
bl_idname = "view3d.vr_location_scouting_add_marker_from_capture"
|
||||
bl_label = "Add Camera Marker from VR Capture"
|
||||
bl_description = "Create a new Camera bound to a Marker from the selected VR Capture at the current frame"
|
||||
bl_options = {'UNDO', 'REGISTER'}
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return len(context.scene.vr_captures) > 0
|
||||
|
||||
def execute(self, context):
|
||||
scene = context.scene
|
||||
sel_capture = properties.VRCapture.get_selected_capture(context)
|
||||
|
||||
# Check if the selected capture camera already exist, if not create it.
|
||||
capture_cam = scene.objects.get(capture_camera_name(sel_capture))
|
||||
|
||||
def cam_matches_capture(camera, capture):
|
||||
if camera is None:
|
||||
return False
|
||||
|
||||
return camera.location == capture.location and camera.rotation_quaternion == capture.orientation
|
||||
|
||||
if not cam_matches_capture(capture_cam, sel_capture):
|
||||
capture_cam = add_camera_from_capture(scene, sel_capture)
|
||||
|
||||
marker = scene.timeline_markers.new(capture_cam.name, frame=scene.frame_current)
|
||||
marker.camera = capture_cam
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
class VIEW3D_OT_vr_location_scouting_active_camera_to_capture(Operator):
|
||||
bl_idname = "view3d.vr_location_scouting_active_camera_to_capture"
|
||||
bl_label = "Set Active Camera from VR Capture"
|
||||
bl_description = "Set the active Scene Camera settings from the selected VR Capture"
|
||||
bl_options = {'UNDO', 'REGISTER'}
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return len(context.scene.vr_captures) > 0
|
||||
|
||||
def execute(self, context):
|
||||
capture = properties.VRCapture.get_selected_capture(context)
|
||||
|
||||
cam = context.scene.camera
|
||||
cam.location = capture.location
|
||||
cam.rotation_mode = 'QUATERNION'
|
||||
cam.rotation_quaternion = capture.orientation
|
||||
cam.rotation_mode = 'XYZ'
|
||||
|
||||
cam.data.shift_x = 0
|
||||
cam.data.shift_y = 0
|
||||
|
||||
cam.data.sensor_fit = 'AUTO'
|
||||
cam.data.sensor_width = 36
|
||||
|
||||
cam.data.lens = capture.lens_focal
|
||||
cam.data.dof.use_dof = capture.dof_enabled
|
||||
cam.data.dof.focus_distance = capture.dof_distance
|
||||
cam.data.dof.aperture_fstop = capture.dof_fstop
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
class VIEW3D_OT_vr_location_scouting_remove_capture(Operator):
|
||||
bl_idname = "view3d.vr_location_scouting_remove_capture"
|
||||
bl_label = "Remove Location Scouting Capture"
|
||||
bl_description = "Remove the selected Location Scouting Capture"
|
||||
bl_options = {'UNDO', 'REGISTER'}
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return len(context.scene.vr_captures) > 0
|
||||
|
||||
def execute(self, context):
|
||||
scene = context.scene
|
||||
captures = scene.vr_captures
|
||||
|
||||
capture_selected_idx = scene.vr_captures_selected
|
||||
captures.remove(capture_selected_idx)
|
||||
|
||||
if scene.vr_captures_selected > 0:
|
||||
scene.vr_captures_selected -= 1
|
||||
|
||||
viewfinder_camera_gizmo_view3d_redraw_workaround()
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
class VIEW3D_OT_vr_location_scouting_browse_captures(Operator):
|
||||
bl_idname = "view3d.vr_location_scouting_browse_captures"
|
||||
bl_label = "Browse Location Scouting Captures"
|
||||
bl_description = "Browse Location Scouting Captures forward or backward"
|
||||
|
||||
backward: bpy.props.BoolProperty(
|
||||
name="Browse Backward",
|
||||
default=False,
|
||||
options={'HIDDEN', 'SKIP_SAVE'},
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return len(context.scene.vr_captures) > 0
|
||||
|
||||
def execute(self, context):
|
||||
scene = context.scene
|
||||
|
||||
incr = -1 if self.backward else 1
|
||||
scene.vr_captures_selected = (scene.vr_captures_selected + incr) % len(scene.vr_captures)
|
||||
|
||||
viewfinder_camera_gizmo_view3d_redraw_workaround()
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
# Gizmos.
|
||||
class VIEW3D_GT_vr_camera_cone(Gizmo):
|
||||
bl_idname = "VIEW_3D_GT_vr_camera_cone"
|
||||
|
||||
aspect = 1.0, 1.0
|
||||
focal = 1.0
|
||||
|
||||
def draw(self, context):
|
||||
if not hasattr(self, "frame_shape"):
|
||||
aspect = self.aspect
|
||||
ui_scale = context.preferences.view.ui_scale
|
||||
aspect = tuple(a / ui_scale for a in self.aspect)
|
||||
focal = self.focal / ui_scale
|
||||
|
||||
frame_shape_verts = (
|
||||
(-aspect[0], -aspect[1], -1.0),
|
||||
(aspect[0], -aspect[1], -1.0),
|
||||
(aspect[0], aspect[1], -1.0),
|
||||
(-aspect[0], aspect[1], -1.0),
|
||||
(-aspect[0], -aspect[1], -1.0),
|
||||
(-aspect[0], -aspect[1], -focal),
|
||||
(aspect[0], -aspect[1], -focal),
|
||||
(aspect[0], aspect[1], -focal),
|
||||
(-aspect[0], aspect[1], -focal),
|
||||
(-aspect[0], -aspect[1], -focal),
|
||||
)
|
||||
lines_shape_verts = (
|
||||
(0.0, 0.0, 0.0),
|
||||
|
|
@ -308,10 +853,17 @@ class VIEW3D_GT_vr_camera_cone(Gizmo):
|
|||
self.lines_shape = self.new_custom_shape(
|
||||
'LINES', lines_shape_verts)
|
||||
|
||||
# Ensure correct GL state (otherwise other gizmos might mess that up)
|
||||
gpu.state.line_width_set(1.0)
|
||||
gpu.state.blend_set('ALPHA')
|
||||
line_width = 2
|
||||
|
||||
shader = gpu.shader.from_builtin('POLYLINE_UNIFORM_COLOR')
|
||||
shader.uniform_float("viewportSize", gpu.state.viewport_get()[2:])
|
||||
shader.uniform_float("lineWidth", line_width * gpu.state.line_width_get())
|
||||
|
||||
# Override default shader given by new_custom_shape()
|
||||
self.frame_shape = (self.frame_shape[0], shader)
|
||||
self.lines_shape = (self.lines_shape[0], shader)
|
||||
|
||||
gpu.state.blend_set('ALPHA')
|
||||
self.draw_custom_shape(self.frame_shape)
|
||||
self.draw_custom_shape(self.lines_shape)
|
||||
|
||||
|
|
@ -510,6 +1062,77 @@ class VIEW3D_GGT_vr_landmarks(GizmoGroup):
|
|||
self.gizmo.matrix_basis = lm_mat
|
||||
|
||||
|
||||
class VIEW3D_GGT_vr_captures(GizmoGroup):
|
||||
bl_idname = "VIEW3D_GGT_vr_captures"
|
||||
bl_label = "VR Location Scouting Captures Indicators"
|
||||
bl_space_type = 'VIEW_3D'
|
||||
bl_region_type = 'WINDOW'
|
||||
bl_options = {'3D', 'DEPTH_3D', 'PERSISTENT', 'SCALE'}
|
||||
|
||||
@staticmethod
|
||||
def compute_aspect(render_settings) -> tuple[float, float]:
|
||||
render_x = render_settings.resolution_x * render_settings.pixel_aspect_x
|
||||
render_y = render_settings.resolution_y * render_settings.pixel_aspect_y
|
||||
|
||||
aspect_x = render_x / render_y if render_x < render_y else 1
|
||||
aspect_y = render_y / render_x if render_x > render_y else 1
|
||||
|
||||
# Base aspect to match native Blender Camera Gizmo (using Auto Sensor Fit).
|
||||
base_aspect = 1 / 4
|
||||
return aspect_x * base_aspect, aspect_y * base_aspect
|
||||
|
||||
@staticmethod
|
||||
def get_selection_color(context, is_active_capture) -> tuple[float, float, float]:
|
||||
selection_color = Color((0.25, 0.81, 1.0))
|
||||
|
||||
# Shift the hue of the base theme selection color, decrease its saturation/value further for inactive captures.
|
||||
if not is_active_capture:
|
||||
selection_color.s += 0.2
|
||||
selection_color.v -= 0.5
|
||||
|
||||
return selection_color[:3]
|
||||
|
||||
@staticmethod
|
||||
def get_transform_matrix(capture):
|
||||
rot_mat = Matrix.Identity(3)
|
||||
rot_mat.rotate(capture.orientation)
|
||||
rot_mat.resize_4x4()
|
||||
loc_mat = Matrix.Translation(capture.location)
|
||||
|
||||
return loc_mat @ rot_mat
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
view3d = context.space_data
|
||||
return view3d.shading.vr_show_captures
|
||||
|
||||
def setup(self, context):
|
||||
pass
|
||||
|
||||
def draw_prepare(self, context):
|
||||
for g in self.gizmos:
|
||||
self.gizmos.remove(g)
|
||||
|
||||
scene = context.scene
|
||||
|
||||
for idx, capture in enumerate(scene.vr_captures):
|
||||
gizmo = self.gizmos.new(VIEW3D_GT_vr_camera_cone.bl_idname)
|
||||
gizmo.aspect = self.compute_aspect(scene.render)
|
||||
sensor_fit_fac = 36 * 2 # Twice the Blender default Camera sensor fit value (36mm).
|
||||
gizmo.focal = capture.lens_focal / sensor_fit_fac
|
||||
|
||||
is_active_capture = (idx == scene.vr_captures_selected)
|
||||
color = self.get_selection_color(context, is_active_capture)
|
||||
|
||||
gizmo.color = color
|
||||
gizmo.color_highlight = color
|
||||
gizmo.alpha = 1.0
|
||||
|
||||
gizmo.matrix_basis = self.get_transform_matrix(capture)
|
||||
|
||||
self.gizmo = gizmo
|
||||
|
||||
|
||||
classes = (
|
||||
VIEW3D_OT_vr_landmark_add,
|
||||
VIEW3D_OT_vr_landmark_remove,
|
||||
|
|
@ -522,12 +1145,24 @@ classes = (
|
|||
VIEW3D_OT_cursor_to_vr_landmark,
|
||||
VIEW3D_OT_update_vr_landmark,
|
||||
|
||||
VIEW3D_OT_vr_location_scouting_viewfinder_capture,
|
||||
VIEW3D_OT_vr_location_scouting_viewfinder_apply_action,
|
||||
VIEW3D_OT_vr_location_scouting_add_camera_from_capture,
|
||||
VIEW3D_OT_vr_location_scouting_add_marker_from_capture,
|
||||
VIEW3D_OT_vr_location_scouting_active_camera_to_capture,
|
||||
VIEW3D_OT_vr_location_scouting_remove_capture,
|
||||
VIEW3D_OT_vr_location_scouting_browse_captures,
|
||||
VIEW3D_OT_vr_location_scouting_viewfinder_cycle_mode,
|
||||
VIEW3D_OT_vr_location_scouting_viewfinder_cycle_action,
|
||||
VIEW3D_OT_vr_location_scouting_viewfinder_swap_hands,
|
||||
|
||||
VIEW3D_GT_vr_camera_cone,
|
||||
VIEW3D_GT_vr_controller_grip,
|
||||
VIEW3D_GT_vr_controller_aim,
|
||||
VIEW3D_GGT_vr_viewer_pose,
|
||||
VIEW3D_GGT_vr_controller_poses,
|
||||
VIEW3D_GGT_vr_landmarks,
|
||||
VIEW3D_GGT_vr_captures,
|
||||
)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -194,8 +194,49 @@ class VRLandmark(PropertyGroup):
|
|||
)
|
||||
|
||||
|
||||
class VRCapture(PropertyGroup):
|
||||
# Note: This PropertyGroup needs to be kept in sync with the internal XrLocationScoutingCapture struct
|
||||
# and get_active_location_scouting_capture() function.
|
||||
name: bpy.props.StringProperty(
|
||||
name="VR Capture",
|
||||
default="Capture"
|
||||
)
|
||||
location: bpy.props.FloatVectorProperty(
|
||||
name="Capture Location",
|
||||
subtype='TRANSLATION',
|
||||
)
|
||||
orientation: bpy.props.FloatVectorProperty(
|
||||
name="Capture Orientation",
|
||||
size=4,
|
||||
subtype='QUATERNION',
|
||||
)
|
||||
lens_focal: bpy.props.FloatProperty(
|
||||
name="Capture Focal Length",
|
||||
)
|
||||
dof_enabled: bpy.props.BoolProperty(
|
||||
name="Capture DoF Enabled",
|
||||
)
|
||||
dof_distance: bpy.props.FloatProperty(
|
||||
name="Capture DoF Focus Distance",
|
||||
)
|
||||
dof_fstop: bpy.props.FloatProperty(
|
||||
name="Capture DoF Aperture F-Stop",
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def get_selected_capture(context):
|
||||
scene = context.scene
|
||||
captures = scene.vr_captures
|
||||
|
||||
return (
|
||||
None if (len(captures) <
|
||||
1) else captures[scene.vr_captures_selected]
|
||||
)
|
||||
|
||||
|
||||
classes = (
|
||||
VRLandmark,
|
||||
VRCapture,
|
||||
)
|
||||
|
||||
|
||||
|
|
@ -214,6 +255,19 @@ def register():
|
|||
update=vr_landmark_active_update,
|
||||
)
|
||||
|
||||
bpy.types.Scene.vr_captures = bpy.props.CollectionProperty(
|
||||
name="Location Scouting Captures",
|
||||
type=VRCapture,
|
||||
)
|
||||
bpy.types.Scene.vr_captures_selected = bpy.props.IntProperty(
|
||||
name="Selected Capture"
|
||||
)
|
||||
|
||||
bpy.types.WindowManager.vr_capture_review_running = bpy.props.BoolProperty(
|
||||
name="Capture Review Modal Operator Running",
|
||||
default=False
|
||||
)
|
||||
|
||||
bpy.app.handlers.load_post.append(vr_ensure_default_landmark)
|
||||
|
||||
|
||||
|
|
@ -225,4 +279,9 @@ def unregister():
|
|||
del bpy.types.Scene.vr_landmarks_selected
|
||||
del bpy.types.Scene.vr_landmarks_active
|
||||
|
||||
del bpy.types.Scene.vr_captures
|
||||
del bpy.types.Scene.vr_captures_selected
|
||||
|
||||
del bpy.types.WindowManager.vr_capture_review_running
|
||||
|
||||
bpy.app.handlers.load_post.remove(vr_ensure_default_landmark)
|
||||
|
|
|
|||
|
|
@ -126,6 +126,7 @@ _km_hierarchy = [
|
|||
('View3D Move Modal', 'EMPTY', 'WINDOW', []),
|
||||
('View3D Zoom Modal', 'EMPTY', 'WINDOW', []),
|
||||
('View3D Dolly Modal', 'EMPTY', 'WINDOW', []),
|
||||
('View3D VR Location Scouting Capture Review Modal', 'EMPTY', 'WINDOW', []),
|
||||
|
||||
# toolbar and properties
|
||||
('3D View Generic', 'VIEW_3D', 'WINDOW', [
|
||||
|
|
|
|||
|
|
@ -6709,6 +6709,28 @@ def km_view3d_dolly_modal(_params):
|
|||
return keymap
|
||||
|
||||
|
||||
def km_view3d_location_scouting_capture_review_modal(_params):
|
||||
items = []
|
||||
keymap = (
|
||||
"View3D VR Location Scouting Capture Review Modal",
|
||||
{"space_type": 'EMPTY', "region_type": 'WINDOW', "modal": True},
|
||||
{"items": items},
|
||||
)
|
||||
|
||||
items.extend([
|
||||
("EXIT", {"type": 'ESC', "value": 'PRESS', "any": True}, None),
|
||||
("EXIT", {"type": 'RIGHTMOUSE', "value": 'PRESS', "any": True}, None),
|
||||
|
||||
("PREVIOUS", {"type": 'UP_ARROW', "value": 'PRESS'}, None),
|
||||
("NEXT", {"type": 'DOWN_ARROW', "value": 'PRESS'}, None),
|
||||
|
||||
("ADD_CAMERA", {"type": 'C', "value": 'PRESS'}, None),
|
||||
("ADD_MARKER", {"type": 'M', "value": 'PRESS'}, None),
|
||||
])
|
||||
|
||||
return keymap
|
||||
|
||||
|
||||
def km_paint_stroke_modal(_params):
|
||||
items = []
|
||||
keymap = (
|
||||
|
|
@ -9064,6 +9086,7 @@ def generate_keymaps(params=None):
|
|||
km_view3d_move_modal(params),
|
||||
km_view3d_zoom_modal(params),
|
||||
km_view3d_dolly_modal(params),
|
||||
km_view3d_location_scouting_capture_review_modal(params),
|
||||
km_paint_stroke_modal(params),
|
||||
km_sculpt_expand_modal(params),
|
||||
km_sculpt_mesh_filter_modal_map(params),
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ namespace blender {
|
|||
|
||||
/* Blender file format version. */
|
||||
#define BLENDER_FILE_VERSION BLENDER_VERSION
|
||||
#define BLENDER_FILE_SUBVERSION 39
|
||||
#define BLENDER_FILE_SUBVERSION 40
|
||||
|
||||
/* Minimum Blender version that supports reading file written with the current
|
||||
* version. Older Blender versions will test this and cancel loading the file, showing a warning to
|
||||
|
|
|
|||
|
|
@ -20,6 +20,8 @@
|
|||
#include "DNA_node_types.h"
|
||||
#include "DNA_scene_types.h"
|
||||
#include "DNA_screen_types.h"
|
||||
#include "DNA_windowmanager_types.h"
|
||||
#include "DNA_xr_types.h"
|
||||
|
||||
#include "BLI_listbase_iterator.hh"
|
||||
#include "BLI_string.h"
|
||||
|
|
@ -805,6 +807,19 @@ void blo_do_versions_520(FileData * /*fd*/, Library * /*lib*/, Main *bmain)
|
|||
}
|
||||
}
|
||||
|
||||
if (!MAIN_VERSION_FILE_ATLEAST(bmain, 502, 40)) {
|
||||
for (wmWindowManager &wm : bmain->wm) {
|
||||
wm.xr.session_settings.viewfinder_enabled = false;
|
||||
wm.xr.session_settings.viewfinder_crosshair_enabled = true;
|
||||
|
||||
wm.xr.session_settings.viewfinder_hand = XR_VIEWFINDER_HAND_RIGHT;
|
||||
wm.xr.session_settings.viewfinder_scale = 1.0f;
|
||||
|
||||
wm.xr.session_settings.viewfinder_passepartout_overscan = 0.5f;
|
||||
wm.xr.session_settings.viewfinder_passepartout_opacity = 0.5f;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Always bump subversion in BKE_blender_version.h when adding versioning
|
||||
* code here, and wrap it inside a MAIN_VERSION_FILE_ATLEAST check.
|
||||
|
|
|
|||
|
|
@ -66,6 +66,7 @@ void ED_view3d_draw_offscreen_simple(Depsgraph *depsgraph,
|
|||
bool draw_background,
|
||||
const char *viewname,
|
||||
bool do_color_management,
|
||||
Object *camera_override,
|
||||
GPUOffScreen *ofs,
|
||||
GPUViewport *viewport);
|
||||
|
||||
|
|
|
|||
|
|
@ -65,6 +65,7 @@ set(SRC
|
|||
view3d_snap.cc
|
||||
view3d_utils.cc
|
||||
view3d_view.cc
|
||||
view3d_vr_location_scouting.cc
|
||||
|
||||
view3d_intern.hh
|
||||
view3d_navigate.hh
|
||||
|
|
@ -105,6 +106,10 @@ endif()
|
|||
|
||||
if(WITH_XR_OPENXR)
|
||||
add_definitions(-DWITH_XR_OPENXR)
|
||||
|
||||
list(APPEND INC
|
||||
../../windowmanager/xr/
|
||||
)
|
||||
endif()
|
||||
|
||||
blender_add_lib(bf_editor_space_view3d "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
|
||||
|
|
|
|||
|
|
@ -1856,6 +1856,7 @@ void ED_view3d_draw_offscreen_simple(Depsgraph *depsgraph,
|
|||
bool draw_background,
|
||||
const char *viewname,
|
||||
const bool do_color_management,
|
||||
Object *camera_override,
|
||||
GPUOffScreen *ofs,
|
||||
GPUViewport *viewport)
|
||||
{
|
||||
|
|
@ -1927,7 +1928,14 @@ void ED_view3d_draw_offscreen_simple(Depsgraph *depsgraph,
|
|||
v3d.object_type_exclude_viewport = object_type_exclude_viewport_override;
|
||||
v3d.object_type_exclude_select = object_type_exclude_select_override;
|
||||
|
||||
rv3d.persp = RV3D_PERSP;
|
||||
if (camera_override != nullptr) {
|
||||
/* Override the active View3D camera and force camera perspective. */
|
||||
rv3d.persp = RV3D_CAMOB;
|
||||
v3d.camera = camera_override;
|
||||
}
|
||||
else {
|
||||
rv3d.persp = RV3D_PERSP;
|
||||
}
|
||||
v3d.clip_start = clip_start;
|
||||
v3d.clip_end = clip_end;
|
||||
/* Actually not used since we pass in the projection matrix. */
|
||||
|
|
|
|||
|
|
@ -194,6 +194,11 @@ void VIEW3D_OT_snap_cursor_to_active(wmOperatorType *ot);
|
|||
|
||||
void VIEW3D_OT_interactive_add(wmOperatorType *ot);
|
||||
|
||||
/* `view3d_location_scouting.cc` */
|
||||
|
||||
void vr_location_scouting_capture_review_modal_keymap(wmKeyConfig *keyconf);
|
||||
void VIEW3D_OT_vr_location_scouting_capture_review(wmOperatorType *ot);
|
||||
|
||||
/* space_view3d.cc */
|
||||
|
||||
extern "C" const char *view3d_context_dir[]; /* doc access */
|
||||
|
|
|
|||
|
|
@ -258,6 +258,10 @@ void view3d_operatortypes()
|
|||
WM_operatortype_append(VIEW3D_OT_ruler_add);
|
||||
WM_operatortype_append(VIEW3D_OT_ruler_remove);
|
||||
|
||||
#ifdef WITH_XR_OPENXR
|
||||
WM_operatortype_append(VIEW3D_OT_vr_location_scouting_capture_review);
|
||||
#endif
|
||||
|
||||
ed::transform::transform_operatortypes();
|
||||
}
|
||||
|
||||
|
|
@ -275,6 +279,7 @@ void view3d_keymap(wmKeyConfig *keyconf)
|
|||
viewzoom_modal_keymap(keyconf);
|
||||
viewdolly_modal_keymap(keyconf);
|
||||
viewplace_modal_keymap(keyconf);
|
||||
vr_location_scouting_capture_review_modal_keymap(keyconf);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
|
|
|||
|
|
@ -0,0 +1,376 @@
|
|||
/* SPDX-FileCopyrightText: 2026 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup spview3d
|
||||
*/
|
||||
|
||||
#include "BKE_context.hh"
|
||||
#include "BKE_lib_id.hh"
|
||||
#include "BKE_object.hh"
|
||||
#include "BKE_object_types.hh"
|
||||
|
||||
#include "BLI_math_rotation.h"
|
||||
#include "BLI_math_vector.h"
|
||||
|
||||
#include "BLT_translation.hh"
|
||||
|
||||
#include "DNA_camera_types.h"
|
||||
|
||||
#include "ED_screen.hh"
|
||||
#include "ED_view3d.hh"
|
||||
|
||||
#include "RNA_access.hh"
|
||||
|
||||
#include "UI_interface.hh"
|
||||
|
||||
#include "WM_api.hh"
|
||||
|
||||
#ifdef WITH_XR_OPENXR
|
||||
# include "wm_xr.hh"
|
||||
#endif
|
||||
|
||||
namespace blender {
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Location Scouting Capture Review Operator
|
||||
*
|
||||
* \note This operator relies on the WM XR submodule, and is thus conditionally compiled
|
||||
* if WITH_XR_OPENXR is defined. However, to ensure keymap files continuity, the
|
||||
* operator modal keymap is always defined, and is conditionally assigned to the
|
||||
* operator if WITH_XR_OPENXR is defined.
|
||||
*
|
||||
* \{ */
|
||||
|
||||
/* NOTE: these defines are saved in keymap files, do not change values but just add new ones */
|
||||
enum {
|
||||
CAPTURE_REVIEW_MODAL_EXIT = 1,
|
||||
|
||||
CAPTURE_REVIEW_MODAL_PREV,
|
||||
CAPTURE_REVIEW_MODAL_NEXT,
|
||||
|
||||
CAPTURE_REVIEW_MODAL_ADD_CAMERA,
|
||||
CAPTURE_REVIEW_MODAL_ADD_MARKER,
|
||||
};
|
||||
|
||||
void vr_location_scouting_capture_review_modal_keymap(wmKeyConfig *keyconf)
|
||||
{
|
||||
static const EnumPropertyItem modal_items[] = {
|
||||
{CAPTURE_REVIEW_MODAL_EXIT, "EXIT", 0, "Exit", ""},
|
||||
|
||||
{CAPTURE_REVIEW_MODAL_PREV, "PREVIOUS", 0, "Previous Capture", "Switch to previous capture"},
|
||||
{CAPTURE_REVIEW_MODAL_NEXT, "NEXT", 0, "Next Capture", "Switch to next capture"},
|
||||
|
||||
{CAPTURE_REVIEW_MODAL_ADD_CAMERA,
|
||||
"ADD_CAMERA",
|
||||
0,
|
||||
"Add Camera",
|
||||
"Add Camera from current capture"},
|
||||
{CAPTURE_REVIEW_MODAL_ADD_MARKER,
|
||||
"ADD_MARKER",
|
||||
0,
|
||||
"Add Marker",
|
||||
"Add Marker from current capture"},
|
||||
|
||||
{0, nullptr, 0, nullptr, nullptr},
|
||||
};
|
||||
|
||||
wmKeyMap *keymap = WM_modalkeymap_find(keyconf,
|
||||
"View3D VR Location Scouting Capture Review Modal");
|
||||
|
||||
/* This function is called for each space-type, only needs to add map once. */
|
||||
if (keymap && keymap->modal_items) {
|
||||
return;
|
||||
}
|
||||
|
||||
keymap = WM_modalkeymap_ensure(
|
||||
keyconf, "View3D VR Location Scouting Capture Review Modal", modal_items);
|
||||
|
||||
/* Assign map to operators. */
|
||||
#ifdef WITH_XR_OPENXR
|
||||
WM_modalkeymap_assign(keymap, "VIEW3D_OT_vr_location_scouting_capture_review");
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef WITH_XR_OPENXR
|
||||
|
||||
struct CaptureReviewData {
|
||||
/* Context. */
|
||||
ScrArea *area;
|
||||
RegionView3D *rv3d;
|
||||
View3D *v3d;
|
||||
|
||||
/* Previous camera to restore on exit. */
|
||||
Object *prev_view3d_cam_ob;
|
||||
eRegionView3D_Persp prev_view3d_persp;
|
||||
|
||||
/* Fake camera object to set the View3D. */
|
||||
Object *cam_ob;
|
||||
Camera *cam_data;
|
||||
};
|
||||
|
||||
static void location_scouting_review_draw_status(bContext *C, wmOperator *op)
|
||||
{
|
||||
WorkspaceStatus status(C);
|
||||
|
||||
status.opmodal(IFACE_("Exit"), op->type, CAPTURE_REVIEW_MODAL_EXIT);
|
||||
|
||||
status.opmodal("", op->type, CAPTURE_REVIEW_MODAL_PREV);
|
||||
status.item(IFACE_("Previous"), ICON_NONE);
|
||||
|
||||
status.opmodal("", op->type, CAPTURE_REVIEW_MODAL_NEXT);
|
||||
status.item(IFACE_("Next"), ICON_NONE);
|
||||
|
||||
status.opmodal("", op->type, CAPTURE_REVIEW_MODAL_ADD_CAMERA);
|
||||
status.item(IFACE_("Add Camera"), ICON_NONE);
|
||||
|
||||
status.opmodal("", op->type, CAPTURE_REVIEW_MODAL_ADD_MARKER);
|
||||
status.item(IFACE_("Add Marker"), ICON_NONE);
|
||||
}
|
||||
|
||||
bool vr_location_scouting_capture_review_poll(bContext *C)
|
||||
{
|
||||
return !wm_xr_location_scouting_is_captures_empty(CTX_data_scene(C)) &&
|
||||
ED_operator_region_view3d_active(C);
|
||||
}
|
||||
|
||||
/* The capture review property is stored on the WM, registered by the VR Python add-on. */
|
||||
static bool vr_location_scouting_capture_review_get_running_state(bContext *C)
|
||||
{
|
||||
PointerRNA wm_ptr = RNA_id_pointer_create(&CTX_wm_manager(C)->id);
|
||||
PropertyRNA *state_prop = RNA_struct_find_property(&wm_ptr, "vr_capture_review_running");
|
||||
|
||||
/* Property wasn't found, VR add-on is probably not loaded. Shouldn't be possible. */
|
||||
BLI_assert(state_prop != nullptr);
|
||||
|
||||
return RNA_property_boolean_get(&wm_ptr, state_prop);
|
||||
}
|
||||
|
||||
static void vr_location_scouting_capture_review_set_running_state(bContext *C, const bool state)
|
||||
{
|
||||
PointerRNA wm_ptr = RNA_id_pointer_create(&CTX_wm_manager(C)->id);
|
||||
PropertyRNA *state_prop = RNA_struct_find_property(&wm_ptr, "vr_capture_review_running");
|
||||
|
||||
/* Property wasn't found, VR add-on is probably not loaded. Shouldn't be possible. */
|
||||
BLI_assert(state_prop != nullptr);
|
||||
|
||||
RNA_property_boolean_set(&wm_ptr, state_prop, state);
|
||||
}
|
||||
|
||||
static wmOperatorStatus vr_location_scouting_capture_review_invoke(bContext *C,
|
||||
wmOperator *op,
|
||||
const wmEvent * /*event*/)
|
||||
{
|
||||
/* Operator invoked while already running, toggle off. */
|
||||
if (vr_location_scouting_capture_review_get_running_state(C)) {
|
||||
/* Set the running state (stored on the WM) to false, catched by the running operator modal. */
|
||||
vr_location_scouting_capture_review_set_running_state(C, false);
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
View3D *v3d;
|
||||
ARegion *region;
|
||||
ED_view3d_context_user_region(C, &v3d, ®ion);
|
||||
|
||||
RegionView3D *rv3d = static_cast<RegionView3D *>(region->regiondata);
|
||||
ScrArea *area = CTX_wm_area(C);
|
||||
|
||||
if (RV3D_LOCK_FLAGS(rv3d) & RV3D_LOCK_ANY_TRANSFORM) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
CaptureReviewData *op_data = MEM_new_zeroed<CaptureReviewData>("View3DReviewCaptureData");
|
||||
op_data->area = area;
|
||||
op_data->rv3d = rv3d;
|
||||
op_data->v3d = v3d;
|
||||
|
||||
op_data->prev_view3d_cam_ob = v3d->camera;
|
||||
ED_view3d_lastview_store(rv3d);
|
||||
/* Store previous persp separately from #ED_view3d_lastview_store as setting rv3d->lpersp to
|
||||
* CAMOB is unexpected by navigation logic. */
|
||||
op_data->prev_view3d_persp = rv3d->persp;
|
||||
|
||||
/* Build a fake Camera object to set on the View3D. */
|
||||
op_data->cam_ob = BKE_id_new_nomain<Object>("ReviewCaptureCamera");
|
||||
op_data->cam_ob->type = OB_CAMERA;
|
||||
|
||||
/* Lock rotation to prevent user from exiting the review camera view. Re-using quadview flags. */
|
||||
rv3d->viewlock |= RV3D_LOCK_ROTATION;
|
||||
|
||||
op_data->cam_data = BKE_id_new_nomain<Camera>("ReviewCaptureCameraData");
|
||||
op_data->cam_ob->data = id_cast<ID *>(op_data->cam_data);
|
||||
|
||||
op->customdata = op_data;
|
||||
|
||||
/* Set running state. */
|
||||
vr_location_scouting_capture_review_set_running_state(C, true);
|
||||
|
||||
WM_event_add_modal_handler(C, op);
|
||||
location_scouting_review_draw_status(C, op);
|
||||
|
||||
return OPERATOR_RUNNING_MODAL;
|
||||
}
|
||||
|
||||
static void vr_location_scouting_capture_review_exit(bContext *C, wmOperator *op)
|
||||
{
|
||||
CaptureReviewData *op_data = static_cast<CaptureReviewData *>(op->customdata);
|
||||
RegionView3D *rv3d = op_data->rv3d;
|
||||
|
||||
/* Restore viewport, last view stored by #ED_view3d_lastview_store */
|
||||
copy_qt_qt(rv3d->viewquat, rv3d->lviewquat);
|
||||
rv3d->view = rv3d->lview;
|
||||
rv3d->view_axis_roll = rv3d->lview_axis_roll;
|
||||
rv3d->persp = op_data->prev_view3d_persp;
|
||||
rv3d->viewlock &= ~RV3D_LOCK_ROTATION;
|
||||
|
||||
op_data->v3d->camera = op_data->prev_view3d_cam_ob;
|
||||
|
||||
vr_location_scouting_capture_review_set_running_state(C, false);
|
||||
|
||||
/* Redraw entire area (both the viewport and sidebar regions), clear status text. */
|
||||
ED_area_tag_redraw(CTX_wm_area(C));
|
||||
ED_workspace_status_text(C, nullptr);
|
||||
|
||||
/* Free data. */
|
||||
BKE_id_free(nullptr, id_cast<ID *>(op_data->cam_ob));
|
||||
BKE_id_free(nullptr, id_cast<ID *>(op_data->cam_data));
|
||||
|
||||
MEM_delete(op_data);
|
||||
}
|
||||
|
||||
static void vr_location_scouting_capture_review_cancel(bContext *C, wmOperator *op)
|
||||
{
|
||||
vr_location_scouting_capture_review_exit(C, op);
|
||||
}
|
||||
|
||||
static bool vr_location_scouting_capture_review_event(bContext *C, const wmEvent *event)
|
||||
{
|
||||
/* Return true if event is handled, false otherwise. */
|
||||
if (event->type != EVT_MODAL_MAP) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (event->val) {
|
||||
case CAPTURE_REVIEW_MODAL_EXIT:
|
||||
vr_location_scouting_capture_review_set_running_state(C, false);
|
||||
break;
|
||||
case CAPTURE_REVIEW_MODAL_PREV:
|
||||
case CAPTURE_REVIEW_MODAL_NEXT: {
|
||||
wmOperatorType *ot = WM_operatortype_find("VIEW3D_OT_vr_location_scouting_browse_captures",
|
||||
false);
|
||||
|
||||
PointerRNA props_ptr = WM_operator_properties_create_ptr(ot);
|
||||
RNA_boolean_set(&props_ptr, "backward", event->val == CAPTURE_REVIEW_MODAL_PREV);
|
||||
|
||||
WM_operator_name_call_ptr(C, ot, wm::OpCallContext::ExecDefault, &props_ptr, nullptr);
|
||||
WM_operator_properties_free(&props_ptr);
|
||||
|
||||
break;
|
||||
}
|
||||
case CAPTURE_REVIEW_MODAL_ADD_CAMERA:
|
||||
WM_operator_name_call(C,
|
||||
"VIEW3D_OT_vr_location_scouting_add_camera_from_capture",
|
||||
wm::OpCallContext::ExecDefault,
|
||||
nullptr,
|
||||
nullptr);
|
||||
break;
|
||||
case CAPTURE_REVIEW_MODAL_ADD_MARKER:
|
||||
WM_operator_name_call(C,
|
||||
"VIEW3D_OT_vr_location_scouting_add_marker_from_capture",
|
||||
wm::OpCallContext::ExecDefault,
|
||||
nullptr,
|
||||
nullptr);
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static wmOperatorStatus vr_location_scouting_capture_review_modal(bContext *C,
|
||||
wmOperator *op,
|
||||
const wmEvent *event)
|
||||
{
|
||||
CaptureReviewData *op_data = static_cast<CaptureReviewData *>(op->customdata);
|
||||
|
||||
/* Exit review if the mouse leaves the viewport area, or if the active area editor changes.
|
||||
* This prevents undefined behavior caused by the operator running without an active View3D
|
||||
* area while still allowing the operator to be non-blocking for interactive sidebar UI. */
|
||||
if ((ED_area_find_under_cursor(C, SPACE_TYPE_ANY, event->xy) != op_data->area) ||
|
||||
(op_data->area->spacetype != SPACE_VIEW3D))
|
||||
{
|
||||
vr_location_scouting_capture_review_exit(C, op);
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
/* Get the current capture. */
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
auto capture = wm_xr_location_scouting_get_active_capture(scene);
|
||||
|
||||
if (!capture.has_value()) {
|
||||
BKE_report(op->reports, RPT_INFO, "No VR captures to display, exiting capture review...");
|
||||
vr_location_scouting_capture_review_exit(C, op);
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
const bool event_handled = vr_location_scouting_capture_review_event(C, event);
|
||||
|
||||
/* Exit requested, state set by the operator invoke from UI, or event function from keymap. */
|
||||
if (!vr_location_scouting_capture_review_get_running_state(C)) {
|
||||
vr_location_scouting_capture_review_exit(C, op);
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
/* Force perspective to camera. */
|
||||
op_data->rv3d->persp = RV3D_CAMOB;
|
||||
|
||||
/* Set Camera data from capture. */
|
||||
op_data->cam_data->lens = capture->lens_focal;
|
||||
SET_FLAG_FROM_TEST(op_data->cam_data->dof.flag, capture->dof_enabled, CAM_DOF_ENABLED);
|
||||
op_data->cam_data->dof.aperture_fstop = capture->dof_fstop;
|
||||
op_data->cam_data->dof.focus_distance = capture->dof_distance;
|
||||
|
||||
/* Camera viewport display settings, set passepartout to emphasize that the modal is enabled. */
|
||||
op_data->cam_data->flag |= CAM_SHOWPASSEPARTOUT;
|
||||
op_data->cam_data->passepartalpha = 0.99f; /* *Almost* completely opaque. */
|
||||
|
||||
float capture_cam_mat[4][4];
|
||||
quat_to_mat4(capture_cam_mat, capture->orientation_quat);
|
||||
copy_v3_v3(capture_cam_mat[3], capture->position);
|
||||
|
||||
BKE_object_apply_mat4(op_data->cam_ob, capture_cam_mat, false, false);
|
||||
/* Minimum eval without going through the depsgraph. */
|
||||
BKE_object_to_mat4(op_data->cam_ob, op_data->cam_ob->runtime->object_to_world.ptr());
|
||||
|
||||
/* Set fake Camera object as the View3D camera. */
|
||||
op_data->v3d->camera = op_data->cam_ob;
|
||||
|
||||
ED_area_tag_redraw(CTX_wm_area(C));
|
||||
location_scouting_review_draw_status(C, op);
|
||||
|
||||
if (event_handled) {
|
||||
return OPERATOR_RUNNING_MODAL;
|
||||
}
|
||||
|
||||
return OPERATOR_PASS_THROUGH;
|
||||
}
|
||||
|
||||
void VIEW3D_OT_vr_location_scouting_capture_review(wmOperatorType *ot)
|
||||
{
|
||||
/* Identifiers. */
|
||||
ot->name = "Location Scouting Capture Review";
|
||||
ot->description = "Interactively review Location Scouting VR Captures";
|
||||
ot->idname = "VIEW3D_OT_vr_location_scouting_capture_review";
|
||||
|
||||
/* Callbacks. */
|
||||
ot->invoke = vr_location_scouting_capture_review_invoke;
|
||||
ot->cancel = vr_location_scouting_capture_review_cancel;
|
||||
ot->modal = vr_location_scouting_capture_review_modal;
|
||||
ot->poll = vr_location_scouting_capture_review_poll;
|
||||
}
|
||||
|
||||
#endif /* WITH_XR_OPENXR */
|
||||
|
||||
/** \} */
|
||||
|
||||
} // namespace blender
|
||||
|
|
@ -87,6 +87,33 @@ enum eXrPoseFlag : short {
|
|||
};
|
||||
ENUM_OPERATORS(eXrPoseFlag)
|
||||
|
||||
/* Location Scouting Viewfinder. */
|
||||
enum eXrViewfinderHand { XR_VIEWFINDER_HAND_LEFT = 0, XR_VIEWFINDER_HAND_RIGHT = 1 };
|
||||
|
||||
enum eXrViewfinderMode {
|
||||
XR_VIEWFINDER_MODE_LIVE = 0,
|
||||
XR_VIEWFINDER_MODE_PLAYBACK = 1,
|
||||
XR_VIEWFINDER_MODE_CONFIRM = 2
|
||||
};
|
||||
|
||||
enum eXrViewfinderLiveAction {
|
||||
XR_VIEWFINDER_ACTION_LIVE_LENS = 0,
|
||||
XR_VIEWFINDER_ACTION_LIVE_DOF = 1,
|
||||
XR_VIEWFINDER_ACTION_LIVE_FOCUS = 2,
|
||||
XR_VIEWFINDER_ACTION_LIVE_APERTURE = 3
|
||||
};
|
||||
|
||||
enum eXrViewfinderPlaybackAction {
|
||||
XR_VIEWFINDER_ACTION_PB_BROWSE = 0,
|
||||
XR_VIEWFINDER_ACTION_PB_PREVIEW = 1,
|
||||
XR_VIEWFINDER_ACTION_PB_DELETE = 2
|
||||
};
|
||||
|
||||
enum eXrViewfinderConfirmAction {
|
||||
XR_VIEWFINDER_ACTION_CF_CONFIRM = 0,
|
||||
XR_VIEWFINDER_ACTION_CF_CANCEL = 1
|
||||
};
|
||||
|
||||
/**
|
||||
* The following user and component path lengths are dependent on OpenXR's XR_MAX_PATH_LENGTH
|
||||
* (256). A user path will be combined with a component path to identify an action binding, and
|
||||
|
|
@ -115,7 +142,15 @@ struct XrSessionSettings {
|
|||
char draw_flags = 0;
|
||||
/** Draw style for controller visualization. */
|
||||
char controller_draw_style = 0;
|
||||
char _pad2[2] = {};
|
||||
|
||||
char viewfinder_enabled = 0;
|
||||
char viewfinder_crosshair_enabled = 0;
|
||||
char viewfinder_hand = 0; /* #eXrViewfinderHand */
|
||||
char _pad2[3];
|
||||
|
||||
float viewfinder_scale = 1.0f;
|
||||
float viewfinder_passepartout_overscan = 0.5f;
|
||||
float viewfinder_passepartout_opacity = 0.5f;
|
||||
|
||||
/** Clipping distance. */
|
||||
float clip_start = 0, clip_end = 0;
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ static wmXrData *rna_XrSession_wm_xr_data_get(PointerRNA *ptr)
|
|||
/* Callers could also get XrSessionState pointer through ptr->data, but prefer if we just
|
||||
* consistently pass wmXrData pointers to the WM_xr_xxx() API. */
|
||||
|
||||
BLI_assert(ELEM(ptr->type, RNA_XrSessionSettings, RNA_XrSessionState));
|
||||
BLI_assert(ELEM(ptr->type, RNA_XrSessionSettings, RNA_XrSessionState, RNA_XrViewfinderState));
|
||||
|
||||
wmWindowManager *wm = (wmWindowManager *)ptr->owner_id;
|
||||
BLI_assert(wm && (GS(wm->id.name) == ID_WM));
|
||||
|
|
@ -1027,6 +1027,291 @@ static void rna_XrSessionState_viewer_pose_rotation_get(PointerRNA *ptr, float *
|
|||
# endif
|
||||
}
|
||||
|
||||
static PointerRNA rna_XrSessionState_viewfinder_get(PointerRNA *ptr)
|
||||
{
|
||||
# ifdef WITH_XR_OPENXR
|
||||
const wmXrData *xr = rna_XrSession_wm_xr_data_get(ptr);
|
||||
wmXrViewfinderState *viewfinder = WM_xr_session_state_viewfinder_handle_get(xr);
|
||||
return RNA_pointer_create_discrete(ptr->owner_id, RNA_XrViewfinderState, viewfinder);
|
||||
# else
|
||||
UNUSED_VARS(ptr);
|
||||
return PointerRNA_NULL;
|
||||
# endif
|
||||
}
|
||||
|
||||
static void rna_XrSessionState_viewfinder_location_get(PointerRNA *ptr, float *r_values)
|
||||
{
|
||||
# ifdef WITH_XR_OPENXR
|
||||
const wmXrData *xr = rna_XrSession_wm_xr_data_get(ptr);
|
||||
WM_xr_session_state_viewfinder_location_get(xr, r_values);
|
||||
# else
|
||||
UNUSED_VARS(ptr);
|
||||
zero_v3(r_values);
|
||||
# endif
|
||||
}
|
||||
|
||||
static void rna_XrSessionState_viewfinder_orientation_get(PointerRNA *ptr, float *r_values)
|
||||
{
|
||||
# ifdef WITH_XR_OPENXR
|
||||
const wmXrData *xr = rna_XrSession_wm_xr_data_get(ptr);
|
||||
WM_xr_session_state_viewfinder_orientation_get(xr, r_values);
|
||||
# else
|
||||
UNUSED_VARS(ptr);
|
||||
unit_qt(r_values);
|
||||
# endif
|
||||
}
|
||||
|
||||
static void rna_XrSessionState_viewfinder_trigger_flash(PointerRNA ptr)
|
||||
{
|
||||
# ifdef WITH_XR_OPENXR
|
||||
wmXrData *xr = rna_XrSession_wm_xr_data_get(&ptr);
|
||||
WM_xr_session_state_viewfinder_trigger_flash(xr);
|
||||
# else
|
||||
UNUSED_VARS(ptr);
|
||||
# endif
|
||||
}
|
||||
|
||||
static void rna_XrSessionState_viewfinder_trigger_focus_indicator(PointerRNA ptr, bool hit_success)
|
||||
{
|
||||
# ifdef WITH_XR_OPENXR
|
||||
wmXrData *xr = rna_XrSession_wm_xr_data_get(&ptr);
|
||||
WM_xr_session_state_viewfinder_trigger_focus_indicator(xr, hit_success);
|
||||
# else
|
||||
UNUSED_VARS(ptr, hit_success);
|
||||
# endif
|
||||
}
|
||||
|
||||
static void rna_XrSessionState_viewfinder_reset_view_smoothing(PointerRNA ptr)
|
||||
{
|
||||
# ifdef WITH_XR_OPENXR
|
||||
wmXrData *xr = rna_XrSession_wm_xr_data_get(&ptr);
|
||||
WM_xr_session_state_viewfinder_reset_view_smoothing(xr);
|
||||
# else
|
||||
UNUSED_VARS(ptr);
|
||||
# endif
|
||||
}
|
||||
|
||||
static bool rna_XrSessionState_viewfinder_capture_dof_enabled_get(PointerRNA *ptr)
|
||||
{
|
||||
bool value;
|
||||
# ifdef WITH_XR_OPENXR
|
||||
const wmXrData *xr = rna_XrSession_wm_xr_data_get(ptr);
|
||||
WM_xr_session_state_viewfinder_capture_dof_enabled_get(xr, &value);
|
||||
# else
|
||||
UNUSED_VARS(ptr);
|
||||
value = 1.0f;
|
||||
# endif
|
||||
return value;
|
||||
}
|
||||
|
||||
static void rna_XrSessionState_viewfinder_capture_dof_enabled_set(PointerRNA *ptr, bool value)
|
||||
{
|
||||
# ifdef WITH_XR_OPENXR
|
||||
wmXrData *xr = rna_XrSession_wm_xr_data_get(ptr);
|
||||
WM_xr_session_state_viewfinder_capture_dof_enabled_set(xr, value);
|
||||
# else
|
||||
UNUSED_VARS(ptr, value);
|
||||
# endif
|
||||
}
|
||||
|
||||
static float rna_XrSessionState_viewfinder_capture_lens_focal_get(PointerRNA *ptr)
|
||||
{
|
||||
float value;
|
||||
# ifdef WITH_XR_OPENXR
|
||||
const wmXrData *xr = rna_XrSession_wm_xr_data_get(ptr);
|
||||
WM_xr_session_state_viewfinder_capture_lens_focal_get(xr, &value);
|
||||
# else
|
||||
UNUSED_VARS(ptr);
|
||||
value = 1.0f;
|
||||
# endif
|
||||
return value;
|
||||
}
|
||||
|
||||
static void rna_XrSessionState_viewfinder_capture_lens_focal_set(PointerRNA *ptr, float value)
|
||||
{
|
||||
# ifdef WITH_XR_OPENXR
|
||||
wmXrData *xr = rna_XrSession_wm_xr_data_get(ptr);
|
||||
WM_xr_session_state_viewfinder_capture_lens_focal_set(xr, value);
|
||||
# else
|
||||
UNUSED_VARS(ptr, value);
|
||||
# endif
|
||||
}
|
||||
|
||||
static float rna_XrSessionState_viewfinder_capture_dof_fstop_get(PointerRNA *ptr)
|
||||
{
|
||||
float value;
|
||||
# ifdef WITH_XR_OPENXR
|
||||
const wmXrData *xr = rna_XrSession_wm_xr_data_get(ptr);
|
||||
WM_xr_session_state_viewfinder_capture_dof_fstop_get(xr, &value);
|
||||
# else
|
||||
UNUSED_VARS(ptr);
|
||||
value = 1.0f;
|
||||
# endif
|
||||
return value;
|
||||
}
|
||||
|
||||
static void rna_XrSessionState_viewfinder_capture_dof_fstop_set(PointerRNA *ptr, float value)
|
||||
{
|
||||
# ifdef WITH_XR_OPENXR
|
||||
wmXrData *xr = rna_XrSession_wm_xr_data_get(ptr);
|
||||
WM_xr_session_state_viewfinder_capture_dof_fstop_set(xr, value);
|
||||
# else
|
||||
UNUSED_VARS(ptr, value);
|
||||
# endif
|
||||
}
|
||||
|
||||
static float rna_XrSessionState_viewfinder_capture_dof_distance_get(PointerRNA *ptr)
|
||||
{
|
||||
float value;
|
||||
# ifdef WITH_XR_OPENXR
|
||||
const wmXrData *xr = rna_XrSession_wm_xr_data_get(ptr);
|
||||
WM_xr_session_state_viewfinder_capture_dof_distance_get(xr, &value);
|
||||
# else
|
||||
UNUSED_VARS(ptr);
|
||||
value = 1.0f;
|
||||
# endif
|
||||
return value;
|
||||
}
|
||||
|
||||
static void rna_XrSessionState_viewfinder_capture_dof_distance_set(PointerRNA *ptr, float value)
|
||||
{
|
||||
# ifdef WITH_XR_OPENXR
|
||||
wmXrData *xr = rna_XrSession_wm_xr_data_get(ptr);
|
||||
WM_xr_session_state_viewfinder_capture_dof_distance_set(xr, value);
|
||||
# else
|
||||
UNUSED_VARS(ptr, value);
|
||||
# endif
|
||||
}
|
||||
|
||||
static bool rna_XrSessionState_viewfinder_playback_show_active_capture_in_space_enabled_get(
|
||||
PointerRNA *ptr)
|
||||
{
|
||||
bool value;
|
||||
# ifdef WITH_XR_OPENXR
|
||||
const wmXrData *xr = rna_XrSession_wm_xr_data_get(ptr);
|
||||
WM_xr_session_state_viewfinder_playback_show_active_capture_in_space_enabled_get(xr, &value);
|
||||
# else
|
||||
UNUSED_VARS(ptr);
|
||||
value = 1.0f;
|
||||
# endif
|
||||
return value;
|
||||
}
|
||||
|
||||
static void rna_XrSessionState_viewfinder_playback_show_active_capture_in_space_enabled_set(
|
||||
PointerRNA *ptr, bool value)
|
||||
{
|
||||
# ifdef WITH_XR_OPENXR
|
||||
wmXrData *xr = rna_XrSession_wm_xr_data_get(ptr);
|
||||
WM_xr_session_state_viewfinder_playback_show_active_capture_in_space_enabled_set(xr, value);
|
||||
# else
|
||||
UNUSED_VARS(ptr, value);
|
||||
# endif
|
||||
}
|
||||
|
||||
static int rna_XrSessionState_viewfinder_active_mode_get(PointerRNA *ptr)
|
||||
{
|
||||
int value;
|
||||
# ifdef WITH_XR_OPENXR
|
||||
const wmXrData *xr = rna_XrSession_wm_xr_data_get(ptr);
|
||||
eXrViewfinderMode enum_value;
|
||||
WM_xr_session_state_viewfinder_active_mode_get(xr, &enum_value);
|
||||
value = static_cast<int>(enum_value);
|
||||
# else
|
||||
UNUSED_VARS(ptr);
|
||||
value = 0;
|
||||
# endif
|
||||
return value;
|
||||
}
|
||||
|
||||
static void rna_XrSessionState_viewfinder_active_mode_set(PointerRNA *ptr, int value)
|
||||
{
|
||||
# ifdef WITH_XR_OPENXR
|
||||
wmXrData *xr = rna_XrSession_wm_xr_data_get(ptr);
|
||||
const eXrViewfinderMode enum_value = static_cast<eXrViewfinderMode>(value);
|
||||
WM_xr_session_state_viewfinder_active_mode_set(xr, enum_value);
|
||||
# else
|
||||
UNUSED_VARS(ptr, value);
|
||||
# endif
|
||||
}
|
||||
|
||||
static int rna_XrSessionState_viewfinder_active_action_live_get(PointerRNA *ptr)
|
||||
{
|
||||
int value;
|
||||
# ifdef WITH_XR_OPENXR
|
||||
const wmXrData *xr = rna_XrSession_wm_xr_data_get(ptr);
|
||||
eXrViewfinderLiveAction enum_value;
|
||||
WM_xr_session_state_viewfinder_active_action_live_get(xr, &enum_value);
|
||||
value = static_cast<int>(enum_value);
|
||||
# else
|
||||
UNUSED_VARS(ptr);
|
||||
value = 0;
|
||||
# endif
|
||||
return value;
|
||||
}
|
||||
|
||||
static void rna_XrSessionState_viewfinder_active_action_live_set(PointerRNA *ptr, int value)
|
||||
{
|
||||
# ifdef WITH_XR_OPENXR
|
||||
wmXrData *xr = rna_XrSession_wm_xr_data_get(ptr);
|
||||
const eXrViewfinderLiveAction enum_value = static_cast<eXrViewfinderLiveAction>(value);
|
||||
WM_xr_session_state_viewfinder_active_action_live_set(xr, enum_value);
|
||||
# else
|
||||
UNUSED_VARS(ptr, value);
|
||||
# endif
|
||||
}
|
||||
|
||||
static int rna_XrSessionState_viewfinder_active_action_playback_get(PointerRNA *ptr)
|
||||
{
|
||||
int value;
|
||||
# ifdef WITH_XR_OPENXR
|
||||
const wmXrData *xr = rna_XrSession_wm_xr_data_get(ptr);
|
||||
eXrViewfinderPlaybackAction enum_value;
|
||||
WM_xr_session_state_viewfinder_active_action_playback_get(xr, &enum_value);
|
||||
value = static_cast<int>(enum_value);
|
||||
# else
|
||||
UNUSED_VARS(ptr);
|
||||
value = 0;
|
||||
# endif
|
||||
return value;
|
||||
}
|
||||
|
||||
static void rna_XrSessionState_viewfinder_active_action_playback_set(PointerRNA *ptr, int value)
|
||||
{
|
||||
# ifdef WITH_XR_OPENXR
|
||||
wmXrData *xr = rna_XrSession_wm_xr_data_get(ptr);
|
||||
const eXrViewfinderPlaybackAction enum_value = static_cast<eXrViewfinderPlaybackAction>(value);
|
||||
WM_xr_session_state_viewfinder_active_action_playback_set(xr, enum_value);
|
||||
# else
|
||||
UNUSED_VARS(ptr, value);
|
||||
# endif
|
||||
}
|
||||
|
||||
static int rna_XrSessionState_viewfinder_active_action_confirm_get(PointerRNA *ptr)
|
||||
{
|
||||
int value;
|
||||
# ifdef WITH_XR_OPENXR
|
||||
const wmXrData *xr = rna_XrSession_wm_xr_data_get(ptr);
|
||||
eXrViewfinderConfirmAction enum_value;
|
||||
WM_xr_session_state_viewfinder_active_action_confirm_get(xr, &enum_value);
|
||||
value = static_cast<int>(enum_value);
|
||||
# else
|
||||
UNUSED_VARS(ptr);
|
||||
value = 0;
|
||||
# endif
|
||||
return value;
|
||||
}
|
||||
|
||||
static void rna_XrSessionState_viewfinder_active_action_confirm_set(PointerRNA *ptr, int value)
|
||||
{
|
||||
# ifdef WITH_XR_OPENXR
|
||||
wmXrData *xr = rna_XrSession_wm_xr_data_get(ptr);
|
||||
const eXrViewfinderConfirmAction enum_value = static_cast<eXrViewfinderConfirmAction>(value);
|
||||
WM_xr_session_state_viewfinder_active_action_confirm_set(xr, enum_value);
|
||||
# else
|
||||
UNUSED_VARS(ptr, value);
|
||||
# endif
|
||||
}
|
||||
|
||||
static void rna_XrSessionState_nav_location_get(PointerRNA *ptr, float *r_values)
|
||||
{
|
||||
# ifdef WITH_XR_OPENXR
|
||||
|
|
@ -1965,6 +2250,20 @@ static void rna_def_xr_session_settings(BlenderRNA *brna)
|
|||
{0, nullptr, 0, nullptr, nullptr},
|
||||
};
|
||||
|
||||
static const EnumPropertyItem viewfinder_hands[] = {
|
||||
{XR_VIEWFINDER_HAND_LEFT,
|
||||
"LEFT",
|
||||
0,
|
||||
"Left",
|
||||
"Place the viewfinder on the left hand controller"},
|
||||
{XR_VIEWFINDER_HAND_RIGHT,
|
||||
"RIGHT",
|
||||
0,
|
||||
"Right",
|
||||
"Place the viewfinder on the right hand controller"},
|
||||
{0, nullptr, 0, nullptr, nullptr},
|
||||
};
|
||||
|
||||
srna = RNA_def_struct(brna, "XrSessionSettings", nullptr);
|
||||
RNA_def_struct_ui_text(srna, "XR Session Settings", "");
|
||||
|
||||
|
|
@ -2057,6 +2356,48 @@ static void rna_def_xr_session_settings(BlenderRNA *brna)
|
|||
RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_COLOR);
|
||||
RNA_def_property_update(prop, NC_WM | ND_XR_DATA_CHANGED, nullptr);
|
||||
|
||||
prop = RNA_def_property(srna, "viewfinder_enabled", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
||||
RNA_def_property_boolean_default(prop, true);
|
||||
RNA_def_property_ui_text(prop, "Viewfinder Enabled", "Enable the Location Scouting Viewfinder");
|
||||
RNA_def_property_update(prop, NC_WM | ND_XR_DATA_CHANGED, nullptr);
|
||||
|
||||
prop = RNA_def_property(srna, "viewfinder_hand", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
||||
RNA_def_property_enum_default(prop, XR_VIEWFINDER_HAND_LEFT);
|
||||
RNA_def_property_enum_items(prop, viewfinder_hands);
|
||||
RNA_def_property_ui_text(
|
||||
prop, "Viewfinder Hand", "Hand on which to place the Location Scouting Viewfinder");
|
||||
RNA_def_property_update(prop, NC_WM | ND_XR_DATA_CHANGED, nullptr);
|
||||
|
||||
prop = RNA_def_property(srna, "viewfinder_scale", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
||||
RNA_def_property_range(prop, -3.0f, FLT_MAX);
|
||||
RNA_def_property_ui_range(prop, 0.001f, 3.0f, 0.01 * 100, 3);
|
||||
RNA_def_property_ui_text(prop, "Viewfinder Scale", "Location Scouting Viewfinder size scale");
|
||||
RNA_def_property_update(prop, NC_WM | ND_XR_DATA_CHANGED, nullptr);
|
||||
|
||||
prop = RNA_def_property(srna, "viewfinder_crosshair_enabled", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
||||
RNA_def_property_boolean_default(prop, true);
|
||||
RNA_def_property_ui_text(
|
||||
prop, "Viewfinder Crosshair Enabled", "Enable the Viewfinder Crosshair");
|
||||
RNA_def_property_update(prop, NC_WM | ND_XR_DATA_CHANGED, nullptr);
|
||||
|
||||
prop = RNA_def_property(srna, "viewfinder_passepartout_overscan", PROP_FLOAT, PROP_FACTOR);
|
||||
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
||||
RNA_def_property_ui_text(prop,
|
||||
"Viewfinder Passepartout Overscan",
|
||||
"Border size of the Viewfinder Passepartout overlay");
|
||||
RNA_def_property_update(prop, NC_WM | ND_XR_DATA_CHANGED, nullptr);
|
||||
|
||||
prop = RNA_def_property(srna, "viewfinder_passepartout_opacity", PROP_FLOAT, PROP_FACTOR);
|
||||
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
||||
RNA_def_property_ui_text(prop,
|
||||
"Viewfinder Passepartout Opacity",
|
||||
"Opacity of the darkened Viewfinder Passepartout overlay");
|
||||
RNA_def_property_update(prop, NC_WM | ND_XR_DATA_CHANGED, nullptr);
|
||||
|
||||
prop = RNA_def_property(srna, "clip_start", PROP_FLOAT, PROP_DISTANCE);
|
||||
RNA_def_property_range(prop, 1e-6f, FLT_MAX);
|
||||
RNA_def_property_ui_range(prop, 0.001f, FLT_MAX, 0.1 * 100, 3);
|
||||
|
|
@ -2130,6 +2471,12 @@ static void rna_def_xr_session_state(BlenderRNA *brna)
|
|||
srna = RNA_def_struct(brna, "XrSessionState", nullptr);
|
||||
RNA_def_struct_ui_text(srna, "Session State", "Runtime state information about the VR session");
|
||||
|
||||
/* XrViewfinderState */
|
||||
prop = RNA_def_pointer(
|
||||
srna, "viewfinder", "XrViewfinderState", "Viewfinder", "Viewfinder State");
|
||||
RNA_def_property_pointer_funcs(
|
||||
prop, "rna_XrSessionState_viewfinder_get", nullptr, nullptr, nullptr);
|
||||
|
||||
func = RNA_def_function(srna, "is_running", "rna_XrSessionState_is_running");
|
||||
RNA_def_function_ui_description(func, "Query if the VR session is currently running");
|
||||
RNA_def_function_flag(func, FUNC_NO_SELF);
|
||||
|
|
@ -2486,6 +2833,201 @@ static void rna_def_xr_session_state(BlenderRNA *brna)
|
|||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name XR Session State Viewfinder
|
||||
* \{ */
|
||||
|
||||
static void rna_def_xr_session_state_viewfinder(BlenderRNA *brna)
|
||||
{
|
||||
StructRNA *srna;
|
||||
FunctionRNA *func;
|
||||
PropertyRNA *parm, *prop;
|
||||
|
||||
static const EnumPropertyItem viewfinder_modes[] = {
|
||||
{XR_VIEWFINDER_MODE_LIVE,
|
||||
"LIVE",
|
||||
ICON_RESTRICT_RENDER_OFF,
|
||||
"Live Mode",
|
||||
"Capture a shot using the viewfinder"},
|
||||
{XR_VIEWFINDER_MODE_PLAYBACK,
|
||||
"PLAYBACK",
|
||||
ICON_IMAGE_DATA,
|
||||
"Playback Mode",
|
||||
"Preview and playback captured shots in the viewfinder"},
|
||||
{XR_VIEWFINDER_MODE_CONFIRM,
|
||||
"CONFIRM",
|
||||
ICON_CHECKMARK,
|
||||
"Confirmation Mode",
|
||||
"Confirm user action"},
|
||||
{0, nullptr, 0, nullptr, nullptr},
|
||||
};
|
||||
|
||||
static const EnumPropertyItem viewfinder_live_actions[] = {
|
||||
{XR_VIEWFINDER_ACTION_LIVE_LENS, "LENS", ICON_VIEW_ZOOM, "Focal Length Control", nullptr},
|
||||
{XR_VIEWFINDER_ACTION_LIVE_DOF, "DOF", ICON_COMMUNITY, "Toggle Depth of Field", nullptr},
|
||||
{XR_VIEWFINDER_ACTION_LIVE_FOCUS, "FOCUS", ICON_PIVOT_BOUNDBOX, "Set Focus Point", nullptr},
|
||||
{XR_VIEWFINDER_ACTION_LIVE_APERTURE, "APERTURE", ICON_PROP_CON, "Aperture Control", nullptr},
|
||||
{0, nullptr, 0, nullptr, nullptr},
|
||||
};
|
||||
|
||||
static const EnumPropertyItem viewfinder_playback_actions[] = {
|
||||
{XR_VIEWFINDER_ACTION_PB_BROWSE,
|
||||
"BROWSE",
|
||||
ICON_RENDERLAYERS,
|
||||
"Browse captured shots",
|
||||
nullptr},
|
||||
{XR_VIEWFINDER_ACTION_PB_PREVIEW,
|
||||
"PREVIEW",
|
||||
ICON_OUTLINER_OB_CAMERA,
|
||||
"Preview selected shot in space"},
|
||||
{XR_VIEWFINDER_ACTION_PB_DELETE, "DELETE", ICON_TRASH, "Delete selected shot"},
|
||||
{0, nullptr, 0, nullptr, nullptr}};
|
||||
|
||||
static const EnumPropertyItem viewfinder_confirm_actions[] = {
|
||||
{XR_VIEWFINDER_ACTION_CF_CANCEL, "CANCEL", ICON_X, "Cancel", nullptr},
|
||||
{XR_VIEWFINDER_ACTION_CF_CONFIRM, "CONFIRM", ICON_CHECKMARK, "Confirm", nullptr},
|
||||
{0, nullptr, 0, nullptr, nullptr}};
|
||||
|
||||
srna = RNA_def_struct(brna, "XrViewfinderState", nullptr);
|
||||
RNA_def_struct_ui_text(srna,
|
||||
"Viewfinder State",
|
||||
"Runtime state information about the VR Location Scouting Viewfinder");
|
||||
|
||||
prop = RNA_def_property(srna, "location", PROP_FLOAT, PROP_TRANSLATION);
|
||||
RNA_def_property_array(prop, 3);
|
||||
RNA_def_property_float_funcs(
|
||||
prop, "rna_XrSessionState_viewfinder_location_get", nullptr, nullptr);
|
||||
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
|
||||
RNA_def_property_ui_text(
|
||||
prop, "Viewfinder Location", "Last known location of the viewfinder in world space");
|
||||
|
||||
prop = RNA_def_property(srna, "orientation", PROP_FLOAT, PROP_QUATERNION);
|
||||
RNA_def_property_array(prop, 4);
|
||||
RNA_def_property_float_funcs(
|
||||
prop, "rna_XrSessionState_viewfinder_orientation_get", nullptr, nullptr);
|
||||
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
|
||||
RNA_def_property_ui_text(
|
||||
prop, "Viewfinder Rotation", "Last known orientation of the viewfinder in world space");
|
||||
|
||||
func = RNA_def_function(srna, "trigger_flash", "rna_XrSessionState_viewfinder_trigger_flash");
|
||||
RNA_def_function_ui_description(func,
|
||||
"Trigger the Viewfinder flash to indicate a shot was captured");
|
||||
RNA_def_function_flag(func, FUNC_SELF_AS_RNA);
|
||||
|
||||
func = RNA_def_function(
|
||||
srna, "trigger_focus_indicator", "rna_XrSessionState_viewfinder_trigger_focus_indicator");
|
||||
RNA_def_function_ui_description(
|
||||
func, "Blink the Viewfinder crosshair to indicate whether a focus action hit a target");
|
||||
RNA_def_function_flag(func, FUNC_SELF_AS_RNA);
|
||||
parm = RNA_def_boolean(func,
|
||||
"hit_success",
|
||||
false,
|
||||
"Hit success",
|
||||
"True to blink the success color, False to blink the miss color");
|
||||
RNA_def_parameter_flags(parm, PropertyFlag(0), PARM_REQUIRED);
|
||||
|
||||
func = RNA_def_function(
|
||||
srna, "reset_view_smoothing", "rna_XrSessionState_viewfinder_reset_view_smoothing");
|
||||
RNA_def_function_ui_description(func, "Reset the Viewfinder continuous view smoothing");
|
||||
RNA_def_function_flag(func, FUNC_SELF_AS_RNA);
|
||||
|
||||
prop = RNA_def_property(srna, "capture_dof_enabled", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
||||
RNA_def_property_boolean_funcs(prop,
|
||||
"rna_XrSessionState_viewfinder_capture_dof_enabled_get",
|
||||
"rna_XrSessionState_viewfinder_capture_dof_enabled_set");
|
||||
RNA_def_property_ui_text(prop,
|
||||
"Viewfinder Capture Depth of Field Enabled",
|
||||
"Enable viewfinder capture depth of field");
|
||||
RNA_def_property_update(prop, NC_WM | ND_XR_DATA_CHANGED, nullptr);
|
||||
|
||||
prop = RNA_def_property(srna, "capture_lens_focal", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
||||
RNA_def_property_float_funcs(prop,
|
||||
"rna_XrSessionState_viewfinder_capture_lens_focal_get",
|
||||
"rna_XrSessionState_viewfinder_capture_lens_focal_set",
|
||||
nullptr);
|
||||
RNA_def_property_ui_text(prop,
|
||||
"Viewfinder Capture Focal Length",
|
||||
"Viewfinder capture focal length value in millimeters");
|
||||
RNA_def_property_update(prop, NC_WM | ND_XR_DATA_CHANGED, nullptr);
|
||||
|
||||
prop = RNA_def_property(srna, "capture_dof_distance", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
||||
RNA_def_property_float_funcs(prop,
|
||||
"rna_XrSessionState_viewfinder_capture_dof_distance_get",
|
||||
"rna_XrSessionState_viewfinder_capture_dof_distance_set",
|
||||
nullptr);
|
||||
RNA_def_property_ui_text(prop,
|
||||
"Viewfinder Capture Focus Distance",
|
||||
"Viewfinder capture distance to the focus point for depth of field");
|
||||
RNA_def_property_update(prop, NC_WM | ND_XR_DATA_CHANGED, nullptr);
|
||||
|
||||
prop = RNA_def_property(srna, "capture_dof_fstop", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
||||
RNA_def_property_float_funcs(prop,
|
||||
"rna_XrSessionState_viewfinder_capture_dof_fstop_get",
|
||||
"rna_XrSessionState_viewfinder_capture_dof_fstop_set",
|
||||
nullptr);
|
||||
RNA_def_property_ui_text(prop, "Viewfinder Capture F-Stop", "Viewfinder capture f-stop ratio");
|
||||
RNA_def_property_update(prop, NC_WM | ND_XR_DATA_CHANGED, nullptr);
|
||||
|
||||
prop = RNA_def_property(
|
||||
srna, "playback_show_active_capture_in_space_enabled", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
||||
RNA_def_property_boolean_funcs(
|
||||
prop,
|
||||
"rna_XrSessionState_viewfinder_playback_show_active_capture_in_space_enabled_get",
|
||||
"rna_XrSessionState_viewfinder_playback_show_active_capture_in_space_enabled_set");
|
||||
RNA_def_property_ui_text(prop,
|
||||
"Viewfinder Playback Show active capture in space enabled",
|
||||
"Display active capture in space when in Viewfinder Playback mode");
|
||||
RNA_def_property_update(prop, NC_WM | ND_XR_DATA_CHANGED, nullptr);
|
||||
|
||||
prop = RNA_def_property(srna, "active_mode", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
||||
RNA_def_property_enum_funcs(prop,
|
||||
"rna_XrSessionState_viewfinder_active_mode_get",
|
||||
"rna_XrSessionState_viewfinder_active_mode_set",
|
||||
nullptr);
|
||||
RNA_def_property_enum_items(prop, viewfinder_modes);
|
||||
RNA_def_property_ui_text(prop, "Viewfinder Mode", "Active viewfinder mode, live or playback");
|
||||
RNA_def_property_update(prop, NC_WM | ND_XR_DATA_CHANGED, nullptr);
|
||||
|
||||
prop = RNA_def_property(srna, "active_action_live", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
||||
RNA_def_property_enum_funcs(prop,
|
||||
"rna_XrSessionState_viewfinder_active_action_live_get",
|
||||
"rna_XrSessionState_viewfinder_active_action_live_set",
|
||||
nullptr);
|
||||
RNA_def_property_enum_items(prop, viewfinder_live_actions);
|
||||
RNA_def_property_ui_text(prop, "Viewfinder Live Action", "Active viewfinder live action");
|
||||
RNA_def_property_update(prop, NC_WM | ND_XR_DATA_CHANGED, nullptr);
|
||||
|
||||
prop = RNA_def_property(srna, "active_action_playback", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
||||
RNA_def_property_enum_funcs(prop,
|
||||
"rna_XrSessionState_viewfinder_active_action_playback_get",
|
||||
"rna_XrSessionState_viewfinder_active_action_playback_set",
|
||||
nullptr);
|
||||
RNA_def_property_enum_items(prop, viewfinder_playback_actions);
|
||||
RNA_def_property_ui_text(
|
||||
prop, "Viewfinder Playback Action", "Active viewfinder playback action");
|
||||
RNA_def_property_update(prop, NC_WM | ND_XR_DATA_CHANGED, nullptr);
|
||||
|
||||
prop = RNA_def_property(srna, "active_action_confirm", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
||||
RNA_def_property_enum_funcs(prop,
|
||||
"rna_XrSessionState_viewfinder_active_action_confirm_get",
|
||||
"rna_XrSessionState_viewfinder_active_action_confirm_set",
|
||||
nullptr);
|
||||
RNA_def_property_enum_items(prop, viewfinder_confirm_actions);
|
||||
RNA_def_property_ui_text(prop, "Viewfinder Confirm Action", "Active viewfinder confirm action");
|
||||
RNA_def_property_update(prop, NC_WM | ND_XR_DATA_CHANGED, nullptr);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name XR Event Data
|
||||
* \{ */
|
||||
|
|
@ -2598,6 +3140,7 @@ void RNA_def_xr(BlenderRNA *brna)
|
|||
rna_def_xr_actionmap(brna);
|
||||
rna_def_xr_session_settings(brna);
|
||||
rna_def_xr_session_state(brna);
|
||||
rna_def_xr_session_state_viewfinder(brna);
|
||||
rna_def_xr_eventdata(brna);
|
||||
|
||||
RNA_define_animate_sdna(true);
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ set(INC
|
|||
gizmo/intern
|
||||
../compositor
|
||||
../editors/include
|
||||
../editors/interface
|
||||
../gpu
|
||||
../makesrna
|
||||
../../../intern/memutil
|
||||
|
|
@ -196,6 +197,7 @@ if(WITH_XR_OPENXR)
|
|||
xr/intern/wm_xr_action.cc
|
||||
xr/intern/wm_xr_actionmap.cc
|
||||
xr/intern/wm_xr_draw.cc
|
||||
xr/intern/wm_xr_location_scouting.cc
|
||||
xr/intern/wm_xr_operators.cc
|
||||
xr/intern/wm_xr_session.cc
|
||||
|
||||
|
|
|
|||
|
|
@ -78,6 +78,7 @@ struct wmNDOFMotionData;
|
|||
#ifdef WITH_XR_OPENXR
|
||||
struct wmXrRuntimeData;
|
||||
struct wmXrSessionState;
|
||||
struct wmXrViewfinderState;
|
||||
#endif
|
||||
|
||||
namespace bke::id {
|
||||
|
|
@ -2277,17 +2278,27 @@ bool WM_xr_session_exists(const wmXrData *xr);
|
|||
* Check if the session is running, according to the OpenXR definition.
|
||||
*/
|
||||
bool WM_xr_session_is_ready(const wmXrData *xr);
|
||||
|
||||
wmXrSessionState *WM_xr_session_state_handle_get(const wmXrData *xr);
|
||||
wmXrViewfinderState *WM_xr_session_state_viewfinder_handle_get(const wmXrData *xr);
|
||||
|
||||
bContext *WM_xr_session_context_get(const wmXrData *xr);
|
||||
bContext *WM_xr_session_context_ensure(wmXrData *xr, const wmWindowManager *wm);
|
||||
|
||||
void WM_xr_session_base_pose_reset(wmXrData *xr);
|
||||
void WM_xr_session_state_navigation_reset(wmXrSessionState *state);
|
||||
void WM_xr_session_state_viewfinder_reset(wmXrSessionState *state);
|
||||
|
||||
void WM_xr_session_state_vignette_activate(wmXrData *xr);
|
||||
void WM_xr_session_state_vignette_update(wmXrSessionState *state);
|
||||
|
||||
bool WM_xr_session_state_viewer_pose_location_get(const wmXrData *xr, float r_location[3]);
|
||||
bool WM_xr_session_state_viewer_pose_rotation_get(const wmXrData *xr, float r_rotation[4]);
|
||||
bool WM_xr_session_state_viewer_pose_matrix_info_get(const wmXrData *xr,
|
||||
float r_viewmat[4][4],
|
||||
float *r_focal_len);
|
||||
bool WM_xr_session_state_viewer_scale_get(const wmXrData *xr, float *r_scale);
|
||||
|
||||
bool WM_xr_session_state_controller_grip_location_get(const wmXrData *xr,
|
||||
unsigned int subaction_idx,
|
||||
float r_location[3]);
|
||||
|
|
@ -2300,16 +2311,52 @@ bool WM_xr_session_state_controller_aim_location_get(const wmXrData *xr,
|
|||
bool WM_xr_session_state_controller_aim_rotation_get(const wmXrData *xr,
|
||||
unsigned int subaction_idx,
|
||||
float r_rotation[4]);
|
||||
|
||||
bool WM_xr_session_state_nav_location_get(const wmXrData *xr, float r_location[3]);
|
||||
void WM_xr_session_state_nav_location_set(wmXrData *xr, const float location[3]);
|
||||
bool WM_xr_session_state_nav_rotation_get(const wmXrData *xr, float r_rotation[4]);
|
||||
void WM_xr_session_state_nav_rotation_set(wmXrData *xr, const float rotation[4]);
|
||||
bool WM_xr_session_state_nav_scale_get(const wmXrData *xr, float *r_scale);
|
||||
void WM_xr_session_state_nav_scale_set(wmXrData *xr, float scale);
|
||||
bool WM_xr_session_state_viewer_scale_get(const wmXrData *xr, float *r_scale);
|
||||
void WM_xr_session_state_navigation_reset(wmXrSessionState *state);
|
||||
void WM_xr_session_state_vignette_activate(wmXrData *xr);
|
||||
void WM_xr_session_state_vignette_update(wmXrSessionState *state);
|
||||
|
||||
bool WM_xr_session_state_viewfinder_location_get(const wmXrData *xr, float r_location[3]);
|
||||
bool WM_xr_session_state_viewfinder_orientation_get(const wmXrData *xr, float r_rotation[4]);
|
||||
|
||||
void WM_xr_session_state_viewfinder_trigger_flash(wmXrData *xr);
|
||||
void WM_xr_session_state_viewfinder_trigger_focus_indicator(wmXrData *xr, bool hit_success);
|
||||
void WM_xr_session_state_viewfinder_reset_view_smoothing(wmXrData *xr);
|
||||
|
||||
bool WM_xr_session_state_viewfinder_capture_dof_enabled_get(const wmXrData *xr,
|
||||
bool *r_dof_enabled);
|
||||
void WM_xr_session_state_viewfinder_capture_dof_enabled_set(wmXrData *xr, bool dof_enabled);
|
||||
bool WM_xr_session_state_viewfinder_capture_lens_focal_get(const wmXrData *xr,
|
||||
float *r_lens_focal);
|
||||
void WM_xr_session_state_viewfinder_capture_lens_focal_set(wmXrData *xr, float lens_focal);
|
||||
bool WM_xr_session_state_viewfinder_capture_dof_distance_get(const wmXrData *xr,
|
||||
float *r_dof_distance);
|
||||
void WM_xr_session_state_viewfinder_capture_dof_distance_set(wmXrData *xr, float dof_distance);
|
||||
bool WM_xr_session_state_viewfinder_capture_dof_fstop_get(const wmXrData *xr, float *r_dof_fstop);
|
||||
void WM_xr_session_state_viewfinder_capture_dof_fstop_set(wmXrData *xr, float dof_fstop);
|
||||
|
||||
bool WM_xr_session_state_viewfinder_playback_show_active_capture_in_space_enabled_get(
|
||||
const wmXrData *xr, bool *r_enabled);
|
||||
void WM_xr_session_state_viewfinder_playback_show_active_capture_in_space_enabled_set(
|
||||
wmXrData *xr, bool enabled);
|
||||
|
||||
bool WM_xr_session_state_viewfinder_active_mode_get(const wmXrData *xr, eXrViewfinderMode *r_mode);
|
||||
void WM_xr_session_state_viewfinder_active_mode_set(wmXrData *xr, eXrViewfinderMode mode);
|
||||
bool WM_xr_session_state_viewfinder_active_action_live_get(const wmXrData *xr,
|
||||
eXrViewfinderLiveAction *r_action);
|
||||
void WM_xr_session_state_viewfinder_active_action_live_set(wmXrData *xr,
|
||||
eXrViewfinderLiveAction action);
|
||||
bool WM_xr_session_state_viewfinder_active_action_playback_get(
|
||||
const wmXrData *xr, eXrViewfinderPlaybackAction *r_action);
|
||||
void WM_xr_session_state_viewfinder_active_action_playback_set(wmXrData *xr,
|
||||
eXrViewfinderPlaybackAction action);
|
||||
bool WM_xr_session_state_viewfinder_active_action_confirm_get(
|
||||
const wmXrData *xr, eXrViewfinderConfirmAction *r_action);
|
||||
void WM_xr_session_state_viewfinder_active_action_confirm_set(wmXrData *xr,
|
||||
eXrViewfinderConfirmAction action);
|
||||
|
||||
ARegionType *WM_xr_surface_controller_region_type_get();
|
||||
|
||||
|
|
|
|||
|
|
@ -103,7 +103,7 @@ static void wm_xr_draw_matrices_create(const wmXrDrawData *draw_data,
|
|||
wm_xr_pose_to_imat(&eye_pose, eye_inv);
|
||||
|
||||
/* Apply base pose and navigation. */
|
||||
wm_xr_pose_scale_to_imat(&draw_data->base_pose, draw_data->base_scale, base_inv);
|
||||
wm_xr_pose_scale_to_imat(&session_state->base_pose, session_state->base_scale, base_inv);
|
||||
wm_xr_pose_scale_to_imat(&session_state->nav_pose_last_actions_sync,
|
||||
session_state->viewer_scale_last_actions_sync,
|
||||
nav_inv);
|
||||
|
|
@ -183,6 +183,11 @@ void wm_xr_draw_view(const GHOST_XrDrawViewInfo *draw_view, void *customdata)
|
|||
* #do_depsgraph callback. Thus, obtain the depsgraph directly without evaluating it. */
|
||||
Depsgraph *depsgraph = CTX_data_depsgraph_pointer(xr_context);
|
||||
|
||||
if (draw_view->view_idx == 0) {
|
||||
/* Only render location scouting viewfinder on first eye draw. */
|
||||
wm_xr_viewfinder_render_view(xr_data);
|
||||
}
|
||||
|
||||
/* Draws the view into the surface_data->viewport's frame-buffers. */
|
||||
ED_view3d_draw_offscreen_simple(depsgraph,
|
||||
scene,
|
||||
|
|
@ -204,6 +209,7 @@ void wm_xr_draw_view(const GHOST_XrDrawViewInfo *draw_view, void *customdata)
|
|||
true,
|
||||
nullptr,
|
||||
false,
|
||||
nullptr,
|
||||
vp->offscreen,
|
||||
vp->viewport);
|
||||
|
||||
|
|
@ -432,7 +438,7 @@ static void wm_xr_controller_aim_draw(const XrSessionSettings *settings, wmXrSes
|
|||
immUnbindProgram();
|
||||
}
|
||||
|
||||
void wm_xr_draw_controllers(const bContext * /*C*/, ARegion * /*region*/, void *customdata)
|
||||
void wm_xr_draw_controllers(const bContext *C, ARegion * /*region*/, void *customdata)
|
||||
{
|
||||
wmXrData *xr = static_cast<wmXrData *>(customdata);
|
||||
const XrSessionSettings *settings = &xr->session_settings;
|
||||
|
|
@ -441,6 +447,7 @@ void wm_xr_draw_controllers(const bContext * /*C*/, ARegion * /*region*/, void *
|
|||
|
||||
wm_xr_controller_model_draw(settings, xr_context, state);
|
||||
wm_xr_controller_aim_draw(settings, state);
|
||||
wm_xr_viewfinder_draw(C, settings, state);
|
||||
}
|
||||
|
||||
} // namespace blender
|
||||
|
|
|
|||
|
|
@ -23,6 +23,8 @@ namespace blender {
|
|||
|
||||
struct bContext;
|
||||
struct ARegion;
|
||||
struct Camera;
|
||||
struct GPUOffScreen;
|
||||
struct Object;
|
||||
struct wmWindow;
|
||||
struct wmWindowManager;
|
||||
|
|
@ -30,6 +32,42 @@ struct wmXrActionSet;
|
|||
struct wmXrController;
|
||||
struct wmXrData;
|
||||
|
||||
namespace gpu {
|
||||
class Texture;
|
||||
}
|
||||
|
||||
struct wmXrViewfinderState {
|
||||
/* Internal Runtime values. */
|
||||
float capture_position[3];
|
||||
float capture_orientation_quat[4];
|
||||
|
||||
GPUOffScreen *framebuffer;
|
||||
gpu::Texture *backside_logo_texture;
|
||||
|
||||
Camera *render_cam_data_id;
|
||||
double smoothing_delta_t;
|
||||
|
||||
/* Runtime values set by RNA methods called from Python. */
|
||||
double last_flash_trigger_time;
|
||||
double last_focus_hit_time;
|
||||
bool last_focus_hit_success;
|
||||
|
||||
/* Capture settings. */
|
||||
bool capture_dof_enabled;
|
||||
float capture_lens_focal;
|
||||
float capture_dof_distance;
|
||||
float capture_dof_fstop;
|
||||
|
||||
/* Playback settings. */
|
||||
bool playback_show_active_capture_in_space_enabled;
|
||||
|
||||
/** Active modes, concept differs from the rest of the Blender UI. */
|
||||
eXrViewfinderMode active_mode;
|
||||
eXrViewfinderLiveAction active_action_live;
|
||||
eXrViewfinderPlaybackAction active_action_playback;
|
||||
eXrViewfinderConfirmAction active_action_confirm;
|
||||
};
|
||||
|
||||
struct wmXrSessionState {
|
||||
bool is_started;
|
||||
|
||||
|
|
@ -41,6 +79,15 @@ struct wmXrSessionState {
|
|||
float viewer_mat_base[4][4];
|
||||
float focal_len;
|
||||
|
||||
wmXrViewfinderState viewfinder;
|
||||
|
||||
/** The pose (location + rotation) to which eye deltas will be applied to when drawing (world
|
||||
* space). With positional tracking enabled, it should be the same as the base pose, when
|
||||
* disabled it also contains a location delta from the moment the option was toggled. */
|
||||
GHOST_XrPose base_pose;
|
||||
/** Base scale (uniform, world space). */
|
||||
float base_scale;
|
||||
|
||||
/** Copy of XrSessionSettings.base_pose_ data to detect changes that need
|
||||
* resetting to base pose. */
|
||||
char prev_base_pose_type; /* #eXRSessionBasePoseType. */
|
||||
|
|
@ -128,12 +175,6 @@ struct wmXrDrawData {
|
|||
wmXrData *xr_data;
|
||||
wmXrSurfaceData *surface_data;
|
||||
|
||||
/** The pose (location + rotation) to which eye deltas will be applied to when drawing (world
|
||||
* space). With positional tracking enabled, it should be the same as the base pose, when
|
||||
* disabled it also contains a location delta from the moment the option was toggled. */
|
||||
GHOST_XrPose base_pose;
|
||||
/** Base scale (uniform, world space). */
|
||||
float base_scale;
|
||||
/** Offset to _subtract_ from the OpenXR eye and viewer pose to get the wanted effective pose
|
||||
* (e.g. a pose exactly at the landmark position). */
|
||||
float eye_position_ofs[3]; /* Local/view space. */
|
||||
|
|
@ -277,4 +318,12 @@ bool wm_xr_passthrough_enabled(void *customdata);
|
|||
*/
|
||||
void wm_xr_disable_passthrough(void *customdata);
|
||||
|
||||
/* `wm_xr_location_scouting.cc` */
|
||||
|
||||
bool wm_xr_viewfinder_operator_event_match_hand(bContext *C, const wmEvent *event);
|
||||
void wm_xr_viewfinder_render_view(wmXrData *xr_data);
|
||||
void wm_xr_viewfinder_draw(const bContext *C,
|
||||
const XrSessionSettings *settings,
|
||||
wmXrSessionState *state);
|
||||
|
||||
} // namespace blender
|
||||
|
|
|
|||
1144
source/blender/windowmanager/xr/intern/wm_xr_location_scouting.cc
Normal file
1144
source/blender/windowmanager/xr/intern/wm_xr_location_scouting.cc
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -420,6 +420,10 @@ static wmOperatorStatus wm_xr_navigation_grab_invoke(bContext *C,
|
|||
return OPERATOR_PASS_THROUGH;
|
||||
}
|
||||
|
||||
if (wm_xr_viewfinder_operator_event_match_hand(C, event)) {
|
||||
return OPERATOR_PASS_THROUGH;
|
||||
}
|
||||
|
||||
const wmXrActionData *actiondata = static_cast<const wmXrActionData *>(event->customdata);
|
||||
|
||||
wm_xr_grab_init(op);
|
||||
|
|
@ -787,8 +791,25 @@ static wmOperatorStatus wm_xr_navigation_fly_invoke(bContext *C,
|
|||
}
|
||||
|
||||
wmWindowManager *wm = CTX_wm_manager(C);
|
||||
wmXrData *xr = &wm->xr;
|
||||
|
||||
wm_xr_fly_init(op, &wm->xr);
|
||||
if (wm_xr_viewfinder_operator_event_match_hand(C, event)) {
|
||||
const bool swap_hands = xr->runtime->session_state.swap_hands;
|
||||
const eXrFlyMode mode = eXrFlyMode(RNA_enum_get(op->ptr, swap_hands ? "alt_mode" : "mode"));
|
||||
const eXrViewfinderHand viewfinder_hand = eXrViewfinderHand(
|
||||
xr->session_settings.viewfinder_hand);
|
||||
|
||||
const bool clashes_with_viewfinder = (ELEM(mode, XR_FLY_VIEWER_LEFT, XR_FLY_VIEWER_RIGHT) &&
|
||||
viewfinder_hand == XR_VIEWFINDER_HAND_LEFT) ||
|
||||
(ELEM(mode, XR_FLY_TURNLEFT, XR_FLY_TURNRIGHT) &&
|
||||
viewfinder_hand == XR_VIEWFINDER_HAND_RIGHT);
|
||||
|
||||
if (clashes_with_viewfinder) {
|
||||
return OPERATOR_PASS_THROUGH;
|
||||
}
|
||||
}
|
||||
|
||||
wm_xr_fly_init(op, xr);
|
||||
|
||||
WM_event_add_modal_handler(C, op);
|
||||
|
||||
|
|
@ -1553,6 +1574,10 @@ static wmOperatorStatus wm_xr_navigation_teleport_invoke(bContext *C,
|
|||
return OPERATOR_PASS_THROUGH;
|
||||
}
|
||||
|
||||
if (wm_xr_viewfinder_operator_event_match_hand(C, event)) {
|
||||
return OPERATOR_PASS_THROUGH;
|
||||
}
|
||||
|
||||
wm_xr_navigation_teleport_init(op);
|
||||
|
||||
const wmOperatorStatus retval = op->type->modal(C, op, event);
|
||||
|
|
@ -1799,6 +1824,17 @@ static wmOperatorStatus wm_xr_navigation_reset_exec(bContext *C, wmOperator *op)
|
|||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
static wmOperatorStatus wm_xr_navigation_reset_invoke(bContext *C,
|
||||
wmOperator *op,
|
||||
const wmEvent *event)
|
||||
{
|
||||
if (wm_xr_viewfinder_operator_event_match_hand(C, event)) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
return wm_xr_navigation_reset_exec(C, op);
|
||||
}
|
||||
|
||||
static void WM_OT_xr_navigation_reset(wmOperatorType *ot)
|
||||
{
|
||||
/* Identifiers. */
|
||||
|
|
@ -1807,6 +1843,7 @@ static void WM_OT_xr_navigation_reset(wmOperatorType *ot)
|
|||
ot->description = "Reset VR navigation deltas relative to session base pose";
|
||||
|
||||
/* Callbacks. */
|
||||
ot->invoke = wm_xr_navigation_reset_invoke;
|
||||
ot->exec = wm_xr_navigation_reset_exec;
|
||||
ot->poll = wm_xr_operator_sessionactive;
|
||||
|
||||
|
|
|
|||
|
|
@ -10,7 +10,9 @@
|
|||
#include "BKE_context.hh"
|
||||
#include "BKE_global.hh"
|
||||
#include "BKE_idprop.hh"
|
||||
#include "BKE_lib_id.hh"
|
||||
#include "BKE_main.hh"
|
||||
#include "BKE_object.hh"
|
||||
#include "BKE_scene.hh"
|
||||
#include "BKE_screen.hh"
|
||||
|
||||
|
|
@ -37,6 +39,11 @@
|
|||
#include "GPU_batch.hh"
|
||||
#include "GPU_viewport.hh"
|
||||
|
||||
#include "IMB_imbuf.hh"
|
||||
|
||||
#include "UI_interface_icons.hh"
|
||||
#include "UI_resources.hh"
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "WM_api.hh"
|
||||
|
|
@ -54,6 +61,11 @@ static CLG_LogRef LOG = {"wm.xr"};
|
|||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
||||
static void wm_xr_session_base_pose_calc(const Scene *scene,
|
||||
const XrSessionSettings *settings,
|
||||
GHOST_XrPose *r_base_pose,
|
||||
float *r_base_scale);
|
||||
|
||||
static void wm_xr_session_create_cb()
|
||||
{
|
||||
Main *bmain = G_MAIN;
|
||||
|
|
@ -67,8 +79,13 @@ static void wm_xr_session_create_cb()
|
|||
|
||||
wm_xr_session_actions_init(xr_data);
|
||||
|
||||
const bContext *xr_context = WM_xr_session_context_ensure(xr_data, wm);
|
||||
const Scene *scene = CTX_data_scene(xr_context);
|
||||
wm_xr_session_base_pose_calc(scene, settings, &state->base_pose, &state->base_scale);
|
||||
|
||||
/* Initialize navigation. */
|
||||
WM_xr_session_state_navigation_reset(state);
|
||||
WM_xr_session_state_viewfinder_reset(state);
|
||||
if (settings->base_scale < FLT_EPSILON) {
|
||||
settings->base_scale = 1.0f;
|
||||
}
|
||||
|
|
@ -93,6 +110,8 @@ static void wm_xr_session_controller_data_free(wmXrSessionState *state)
|
|||
void wm_xr_session_data_free(wmXrSessionState *state)
|
||||
{
|
||||
wm_xr_session_controller_data_free(state);
|
||||
BKE_id_free(nullptr, id_cast<ID *>(state->viewfinder.render_cam_data_id));
|
||||
GPU_TEXTURE_FREE_SAFE(state->viewfinder.backside_logo_texture);
|
||||
}
|
||||
|
||||
static void wm_xr_session_exit_cb(void *customdata)
|
||||
|
|
@ -201,14 +220,9 @@ static void wm_xr_session_base_pose_calc(const Scene *scene,
|
|||
|
||||
static void wm_xr_session_draw_data_populate(wmXrData *xr_data, wmXrDrawData *r_draw_data)
|
||||
{
|
||||
const XrSessionSettings *settings = &xr_data->session_settings;
|
||||
|
||||
memset(r_draw_data, 0, sizeof(*r_draw_data));
|
||||
r_draw_data->xr_data = xr_data;
|
||||
r_draw_data->surface_data = static_cast<wmXrSurfaceData *>(g_xr_surface->customdata);
|
||||
|
||||
Scene *scene = CTX_data_scene(WM_xr_session_context_get(xr_data));
|
||||
wm_xr_session_base_pose_calc(scene, settings, &r_draw_data->base_pose, &r_draw_data->base_scale);
|
||||
}
|
||||
|
||||
wmWindow *wm_xr_session_root_window_or_fallback_get(const wmWindowManager *wm,
|
||||
|
|
@ -292,6 +306,7 @@ void wm_xr_session_draw_data_update(wmXrSessionState *state,
|
|||
}
|
||||
/* Reset navigation. */
|
||||
WM_xr_session_state_navigation_reset(state);
|
||||
WM_xr_session_state_viewfinder_reset(state);
|
||||
break;
|
||||
case SESSION_STATE_EVENT_POSITION_TRACKING_TOGGLE:
|
||||
if (use_position_tracking) {
|
||||
|
|
@ -384,7 +399,7 @@ void wm_xr_session_state_update(const XrSessionSettings *settings,
|
|||
wm_xr_pose_to_mat(&viewer_pose, viewer_mat);
|
||||
|
||||
/* Apply base pose and navigation. */
|
||||
wm_xr_pose_scale_to_mat(&draw_data->base_pose, draw_data->base_scale, base_mat);
|
||||
wm_xr_pose_scale_to_mat(&state->base_pose, state->base_scale, base_mat);
|
||||
wm_xr_pose_scale_to_mat(&state->nav_pose_last_actions_sync, state->viewer_scale, nav_mat);
|
||||
mul_m4_m4m4(state->viewer_mat_base, base_mat, viewer_mat);
|
||||
mul_m4_m4m4(viewer_mat, nav_mat, state->viewer_mat_base);
|
||||
|
|
@ -392,7 +407,7 @@ void wm_xr_session_state_update(const XrSessionSettings *settings,
|
|||
/* Save final viewer pose and viewmat. */
|
||||
mat4_to_loc_quat(state->viewer_pose.position, state->viewer_pose.orientation_quat, viewer_mat);
|
||||
wm_xr_pose_scale_to_imat(&state->viewer_pose,
|
||||
draw_data->base_scale * state->viewer_scale_last_actions_sync,
|
||||
state->base_scale * state->viewer_scale_last_actions_sync,
|
||||
state->viewer_viewmat);
|
||||
|
||||
/* No idea why, but multiplying by two seems to make it match the VR view more. */
|
||||
|
|
@ -401,8 +416,8 @@ void wm_xr_session_state_update(const XrSessionSettings *settings,
|
|||
DEFAULT_SENSOR_WIDTH);
|
||||
|
||||
copy_v3_v3(state->prev_eye_position_ofs, draw_data->eye_position_ofs);
|
||||
memcpy(&state->prev_base_pose, &draw_data->base_pose, sizeof(state->prev_base_pose));
|
||||
state->prev_base_scale = draw_data->base_scale;
|
||||
memcpy(&state->prev_base_pose, &state->base_pose, sizeof(state->prev_base_pose));
|
||||
state->prev_base_scale = state->base_scale;
|
||||
memcpy(&state->prev_local_pose, &draw_view->local_pose, sizeof(state->prev_local_pose));
|
||||
copy_v3_v3(state->prev_eye_position_ofs, draw_data->eye_position_ofs);
|
||||
|
||||
|
|
@ -424,6 +439,11 @@ wmXrSessionState *WM_xr_session_state_handle_get(const wmXrData *xr)
|
|||
return xr->runtime ? &xr->runtime->session_state : nullptr;
|
||||
}
|
||||
|
||||
wmXrViewfinderState *WM_xr_session_state_viewfinder_handle_get(const wmXrData *xr)
|
||||
{
|
||||
return xr->runtime ? &xr->runtime->session_state.viewfinder : nullptr;
|
||||
}
|
||||
|
||||
bContext *WM_xr_session_context_ensure(wmXrData *xr, const wmWindowManager *wm)
|
||||
{
|
||||
if (xr->runtime == nullptr) {
|
||||
|
|
@ -472,6 +492,220 @@ bool WM_xr_session_state_viewer_pose_rotation_get(const wmXrData *xr, float r_ro
|
|||
return true;
|
||||
}
|
||||
|
||||
bool WM_xr_session_state_viewfinder_location_get(const wmXrData *xr, float r_location[3])
|
||||
{
|
||||
if (!WM_xr_session_is_ready(xr) || !xr->runtime->session_state.is_view_data_set) {
|
||||
zero_v3(r_location);
|
||||
return false;
|
||||
}
|
||||
|
||||
copy_v3_v3(r_location, xr->runtime->session_state.viewfinder.capture_position);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WM_xr_session_state_viewfinder_orientation_get(const wmXrData *xr, float r_rotation[4])
|
||||
{
|
||||
if (!WM_xr_session_is_ready(xr) || !xr->runtime->session_state.is_view_data_set) {
|
||||
unit_qt(r_rotation);
|
||||
return false;
|
||||
}
|
||||
|
||||
copy_v4_v4(r_rotation, xr->runtime->session_state.viewfinder.capture_orientation_quat);
|
||||
return true;
|
||||
}
|
||||
|
||||
void WM_xr_session_state_viewfinder_trigger_flash(wmXrData *xr)
|
||||
{
|
||||
if (WM_xr_session_exists(xr)) {
|
||||
xr->runtime->session_state.viewfinder.last_flash_trigger_time = BLI_time_now_seconds();
|
||||
}
|
||||
}
|
||||
|
||||
void WM_xr_session_state_viewfinder_trigger_focus_indicator(wmXrData *xr, bool hit_success)
|
||||
{
|
||||
if (WM_xr_session_exists(xr)) {
|
||||
xr->runtime->session_state.viewfinder.last_focus_hit_time = BLI_time_now_seconds();
|
||||
xr->runtime->session_state.viewfinder.last_focus_hit_success = hit_success;
|
||||
}
|
||||
}
|
||||
|
||||
void WM_xr_session_state_viewfinder_reset_view_smoothing(wmXrData *xr)
|
||||
{
|
||||
if (WM_xr_session_exists(xr)) {
|
||||
xr->runtime->session_state.viewfinder.smoothing_delta_t = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
bool WM_xr_session_state_viewfinder_capture_dof_enabled_get(const wmXrData *xr,
|
||||
bool *r_dof_enabled)
|
||||
{
|
||||
if (!WM_xr_session_is_ready(xr) || !xr->runtime->session_state.is_view_data_set) {
|
||||
*r_dof_enabled = 0.0f;
|
||||
return false;
|
||||
}
|
||||
|
||||
*r_dof_enabled = xr->runtime->session_state.viewfinder.capture_dof_enabled;
|
||||
return true;
|
||||
}
|
||||
|
||||
void WM_xr_session_state_viewfinder_capture_dof_enabled_set(wmXrData *xr, bool dof_enabled)
|
||||
{
|
||||
if (WM_xr_session_exists(xr)) {
|
||||
xr->runtime->session_state.viewfinder.capture_dof_enabled = dof_enabled;
|
||||
}
|
||||
}
|
||||
|
||||
bool WM_xr_session_state_viewfinder_capture_lens_focal_get(const wmXrData *xr, float *r_lens_focal)
|
||||
{
|
||||
if (!WM_xr_session_is_ready(xr) || !xr->runtime->session_state.is_view_data_set) {
|
||||
*r_lens_focal = 1.0f;
|
||||
return false;
|
||||
}
|
||||
|
||||
*r_lens_focal = xr->runtime->session_state.viewfinder.capture_lens_focal;
|
||||
return true;
|
||||
}
|
||||
|
||||
void WM_xr_session_state_viewfinder_capture_lens_focal_set(wmXrData *xr, float lens_focal)
|
||||
{
|
||||
if (WM_xr_session_exists(xr)) {
|
||||
xr->runtime->session_state.viewfinder.capture_lens_focal = lens_focal;
|
||||
}
|
||||
}
|
||||
|
||||
bool WM_xr_session_state_viewfinder_capture_dof_distance_get(const wmXrData *xr,
|
||||
float *r_dof_distance)
|
||||
{
|
||||
if (!WM_xr_session_is_ready(xr) || !xr->runtime->session_state.is_view_data_set) {
|
||||
*r_dof_distance = 1.0f;
|
||||
return false;
|
||||
}
|
||||
|
||||
*r_dof_distance = xr->runtime->session_state.viewfinder.capture_dof_distance;
|
||||
return true;
|
||||
}
|
||||
|
||||
void WM_xr_session_state_viewfinder_capture_dof_distance_set(wmXrData *xr, float dof_distance)
|
||||
{
|
||||
if (WM_xr_session_exists(xr)) {
|
||||
xr->runtime->session_state.viewfinder.capture_dof_distance = dof_distance;
|
||||
}
|
||||
}
|
||||
|
||||
bool WM_xr_session_state_viewfinder_capture_dof_fstop_get(const wmXrData *xr, float *r_dof_fstop)
|
||||
{
|
||||
if (!WM_xr_session_is_ready(xr) || !xr->runtime->session_state.is_view_data_set) {
|
||||
*r_dof_fstop = 1.0f;
|
||||
return false;
|
||||
}
|
||||
|
||||
*r_dof_fstop = xr->runtime->session_state.viewfinder.capture_dof_fstop;
|
||||
return true;
|
||||
}
|
||||
|
||||
void WM_xr_session_state_viewfinder_capture_dof_fstop_set(wmXrData *xr, float dof_fstop)
|
||||
{
|
||||
if (WM_xr_session_exists(xr)) {
|
||||
xr->runtime->session_state.viewfinder.capture_dof_fstop = dof_fstop;
|
||||
}
|
||||
}
|
||||
|
||||
bool WM_xr_session_state_viewfinder_playback_show_active_capture_in_space_enabled_get(
|
||||
const wmXrData *xr, bool *r_enabled)
|
||||
{
|
||||
if (!WM_xr_session_is_ready(xr) || !xr->runtime->session_state.is_view_data_set) {
|
||||
*r_enabled = 0.0f;
|
||||
return false;
|
||||
}
|
||||
|
||||
*r_enabled = xr->runtime->session_state.viewfinder.playback_show_active_capture_in_space_enabled;
|
||||
return true;
|
||||
}
|
||||
|
||||
void WM_xr_session_state_viewfinder_playback_show_active_capture_in_space_enabled_set(wmXrData *xr,
|
||||
bool enabled)
|
||||
{
|
||||
if (WM_xr_session_exists(xr)) {
|
||||
xr->runtime->session_state.viewfinder.playback_show_active_capture_in_space_enabled = enabled;
|
||||
}
|
||||
}
|
||||
|
||||
bool WM_xr_session_state_viewfinder_active_mode_get(const wmXrData *xr, eXrViewfinderMode *r_mode)
|
||||
{
|
||||
if (!WM_xr_session_is_ready(xr) || !xr->runtime->session_state.is_view_data_set) {
|
||||
*r_mode = static_cast<eXrViewfinderMode>(0);
|
||||
return false;
|
||||
}
|
||||
|
||||
*r_mode = xr->runtime->session_state.viewfinder.active_mode;
|
||||
return true;
|
||||
}
|
||||
|
||||
void WM_xr_session_state_viewfinder_active_mode_set(wmXrData *xr, eXrViewfinderMode mode)
|
||||
{
|
||||
if (WM_xr_session_exists(xr)) {
|
||||
xr->runtime->session_state.viewfinder.active_mode = mode;
|
||||
}
|
||||
}
|
||||
|
||||
bool WM_xr_session_state_viewfinder_active_action_live_get(const wmXrData *xr,
|
||||
eXrViewfinderLiveAction *r_action)
|
||||
{
|
||||
if (!WM_xr_session_is_ready(xr) || !xr->runtime->session_state.is_view_data_set) {
|
||||
*r_action = static_cast<eXrViewfinderLiveAction>(0);
|
||||
return false;
|
||||
}
|
||||
|
||||
*r_action = xr->runtime->session_state.viewfinder.active_action_live;
|
||||
return true;
|
||||
}
|
||||
|
||||
void WM_xr_session_state_viewfinder_active_action_live_set(wmXrData *xr,
|
||||
eXrViewfinderLiveAction action)
|
||||
{
|
||||
if (WM_xr_session_exists(xr)) {
|
||||
xr->runtime->session_state.viewfinder.active_action_live = action;
|
||||
}
|
||||
}
|
||||
bool WM_xr_session_state_viewfinder_active_action_playback_get(
|
||||
const wmXrData *xr, eXrViewfinderPlaybackAction *r_action)
|
||||
{
|
||||
if (!WM_xr_session_is_ready(xr) || !xr->runtime->session_state.is_view_data_set) {
|
||||
*r_action = static_cast<eXrViewfinderPlaybackAction>(0);
|
||||
return false;
|
||||
}
|
||||
|
||||
*r_action = xr->runtime->session_state.viewfinder.active_action_playback;
|
||||
return true;
|
||||
}
|
||||
void WM_xr_session_state_viewfinder_active_action_playback_set(wmXrData *xr,
|
||||
eXrViewfinderPlaybackAction action)
|
||||
{
|
||||
if (WM_xr_session_exists(xr)) {
|
||||
xr->runtime->session_state.viewfinder.active_action_playback = action;
|
||||
}
|
||||
}
|
||||
|
||||
bool WM_xr_session_state_viewfinder_active_action_confirm_get(const wmXrData *xr,
|
||||
eXrViewfinderConfirmAction *r_action)
|
||||
{
|
||||
if (!WM_xr_session_is_ready(xr) || !xr->runtime->session_state.is_view_data_set) {
|
||||
*r_action = static_cast<eXrViewfinderConfirmAction>(0);
|
||||
return false;
|
||||
}
|
||||
|
||||
*r_action = xr->runtime->session_state.viewfinder.active_action_confirm;
|
||||
return true;
|
||||
}
|
||||
|
||||
void WM_xr_session_state_viewfinder_active_action_confirm_set(wmXrData *xr,
|
||||
eXrViewfinderConfirmAction action)
|
||||
{
|
||||
if (WM_xr_session_exists(xr)) {
|
||||
xr->runtime->session_state.viewfinder.active_action_confirm = action;
|
||||
}
|
||||
}
|
||||
|
||||
bool WM_xr_session_state_viewer_pose_matrix_info_get(const wmXrData *xr,
|
||||
float r_viewmat[4][4],
|
||||
float *r_focal_len)
|
||||
|
|
@ -641,6 +875,45 @@ void WM_xr_session_state_navigation_reset(wmXrSessionState *state)
|
|||
state->swap_hands = false;
|
||||
}
|
||||
|
||||
void WM_xr_session_state_viewfinder_reset(wmXrSessionState *state)
|
||||
{
|
||||
/* Runtime values. */
|
||||
state->viewfinder.smoothing_delta_t = 0.0;
|
||||
state->viewfinder.last_flash_trigger_time = 0.0;
|
||||
state->viewfinder.last_focus_hit_time = 0.0;
|
||||
state->viewfinder.last_focus_hit_success = false;
|
||||
|
||||
/* Create a Camera data ID to override the View3D camera (for setting parameters such as DoF).
|
||||
* This ID is freed in #wm_xr_session_data_free. */
|
||||
if (state->viewfinder.render_cam_data_id == nullptr) {
|
||||
state->viewfinder.render_cam_data_id = BKE_id_new_nomain<Camera>("ViewfinderCamera");
|
||||
}
|
||||
|
||||
/* Create a Camera logo texture to draw on the backside of the viewfinder. */
|
||||
if (state->viewfinder.backside_logo_texture == nullptr) {
|
||||
ImBuf *ibuf = ui::svg_icon_bitmap(ICON_RESTRICT_RENDER_OFF, 256.0f, false);
|
||||
if (ibuf) {
|
||||
state->viewfinder.backside_logo_texture = IMB_create_gpu_texture(
|
||||
"viewfinder_backside_logo", ibuf, false, true, true);
|
||||
IMB_freeImBuf(ibuf);
|
||||
}
|
||||
}
|
||||
|
||||
/* Capture settings. */
|
||||
state->viewfinder.capture_dof_enabled = false;
|
||||
state->viewfinder.capture_lens_focal = 50.0f;
|
||||
state->viewfinder.capture_dof_fstop = 2.8f;
|
||||
state->viewfinder.capture_dof_distance = 10.0f;
|
||||
|
||||
/* Playback settings. */
|
||||
state->viewfinder.playback_show_active_capture_in_space_enabled = true;
|
||||
|
||||
/* Active modes. */
|
||||
state->viewfinder.active_mode = XR_VIEWFINDER_MODE_LIVE;
|
||||
state->viewfinder.active_action_live = XR_VIEWFINDER_ACTION_LIVE_LENS;
|
||||
state->viewfinder.active_action_playback = XR_VIEWFINDER_ACTION_PB_BROWSE;
|
||||
}
|
||||
|
||||
void WM_xr_session_state_vignette_activate(wmXrData *xr)
|
||||
{
|
||||
if (WM_xr_session_exists(xr)) {
|
||||
|
|
|
|||
|
|
@ -27,4 +27,22 @@ bool wm_xr_events_handle(wmWindowManager *wm);
|
|||
|
||||
void wm_xr_operatortypes_register();
|
||||
|
||||
/* `wm_xr_location_scouting.cc` */
|
||||
|
||||
/* NOTE: Keep in sync with the Python VR Scene Inspection add-on VRCapture class.
|
||||
* See comment in #wm_xr_location_scouting_get_active_capture. */
|
||||
struct XrLocationScoutingCapture {
|
||||
float3 position;
|
||||
float4 orientation_quat;
|
||||
|
||||
float lens_focal;
|
||||
|
||||
bool dof_enabled;
|
||||
float dof_distance;
|
||||
float dof_fstop;
|
||||
};
|
||||
|
||||
bool wm_xr_location_scouting_is_captures_empty(Scene *scene);
|
||||
std::optional<XrLocationScoutingCapture> wm_xr_location_scouting_get_active_capture(Scene *scene);
|
||||
|
||||
} // namespace blender
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue