Compare commits
2 Commits
master
...
251-vr-col
Author | SHA1 | Date | |
---|---|---|---|
|
630e1c7494 | ||
|
1b614f4fb6 |
@ -23,6 +23,7 @@ from replication import porcelain
|
|||||||
from replication.constants import RP_COMMON, STATE_ACTIVE, STATE_SYNCING, UP
|
from replication.constants import RP_COMMON, STATE_ACTIVE, STATE_SYNCING, UP
|
||||||
from replication.exception import ContextError, NonAuthorizedOperationError
|
from replication.exception import ContextError, NonAuthorizedOperationError
|
||||||
from replication.interface import session
|
from replication.interface import session
|
||||||
|
from .timers import XrUserUpdate
|
||||||
|
|
||||||
from . import shared_data, utils
|
from . import shared_data, utils
|
||||||
|
|
||||||
@ -46,14 +47,16 @@ def sanitize_deps_graph(remove_nodes: bool = False):
|
|||||||
rm_cpt += 1
|
rm_cpt += 1
|
||||||
except NonAuthorizedOperationError:
|
except NonAuthorizedOperationError:
|
||||||
continue
|
continue
|
||||||
logging.info(f"Sanitize took { utils.current_milli_time()-start} ms, removed {rm_cpt} nodes")
|
logging.info(
|
||||||
|
f"Sanitize took { utils.current_milli_time()-start} ms, removed {rm_cpt} nodes")
|
||||||
|
|
||||||
|
|
||||||
def update_external_dependencies():
|
def update_external_dependencies():
|
||||||
"""Force external dependencies(files such as images) evaluation
|
"""Force external dependencies(files such as images) evaluation
|
||||||
"""
|
"""
|
||||||
external_types = ['WindowsPath', 'PosixPath', 'Image']
|
external_types = ['WindowsPath', 'PosixPath', 'Image']
|
||||||
nodes_ids = [n.uuid for n in session.repository.graph.values() if n.data['type_id'] in external_types]
|
nodes_ids = [n.uuid for n in session.repository.graph.values()
|
||||||
|
if n.data['type_id'] in external_types]
|
||||||
for node_id in nodes_ids:
|
for node_id in nodes_ids:
|
||||||
node = session.repository.graph.get(node_id)
|
node = session.repository.graph.get(node_id)
|
||||||
if node and node.owner in [session.repository.username, RP_COMMON]:
|
if node and node.owner in [session.repository.username, RP_COMMON]:
|
||||||
@ -72,11 +75,13 @@ def on_scene_update(scene):
|
|||||||
settings = utils.get_preferences()
|
settings = utils.get_preferences()
|
||||||
incoming_updates = shared_data.session.applied_updates
|
incoming_updates = shared_data.session.applied_updates
|
||||||
|
|
||||||
distant_update = [getattr(u.id, 'uuid', None) for u in dependency_updates if getattr(u.id, 'uuid', None) in incoming_updates]
|
distant_update = [getattr(u.id, 'uuid', None) for u in dependency_updates if getattr(
|
||||||
|
u.id, 'uuid', None) in incoming_updates]
|
||||||
if distant_update:
|
if distant_update:
|
||||||
for u in distant_update:
|
for u in distant_update:
|
||||||
shared_data.session.applied_updates.remove(u)
|
shared_data.session.applied_updates.remove(u)
|
||||||
logging.debug(f"Ignoring distant update of {dependency_updates[0].id.name}")
|
logging.debug(
|
||||||
|
f"Ignoring distant update of {dependency_updates[0].id.name}")
|
||||||
return
|
return
|
||||||
|
|
||||||
# NOTE: maybe we don't need to check each update but only the first
|
# NOTE: maybe we don't need to check each update but only the first
|
||||||
@ -84,7 +89,8 @@ def on_scene_update(scene):
|
|||||||
update_uuid = getattr(update.id, 'uuid', None)
|
update_uuid = getattr(update.id, 'uuid', None)
|
||||||
if update_uuid:
|
if update_uuid:
|
||||||
node = session.repository.graph.get(update.id.uuid)
|
node = session.repository.graph.get(update.id.uuid)
|
||||||
check_common = session.repository.rdp.get_implementation(update.id).bl_check_common
|
check_common = session.repository.rdp.get_implementation(
|
||||||
|
update.id).bl_check_common
|
||||||
|
|
||||||
if node and (node.owner == session.repository.username or check_common):
|
if node and (node.owner == session.repository.username or check_common):
|
||||||
logging.debug(f"Evaluate {update.id.name}")
|
logging.debug(f"Evaluate {update.id.name}")
|
||||||
@ -107,12 +113,14 @@ def on_scene_update(scene):
|
|||||||
porcelain.commit(session.repository, scn_uuid)
|
porcelain.commit(session.repository, scn_uuid)
|
||||||
porcelain.push(session.repository, 'origin', scn_uuid)
|
porcelain.push(session.repository, 'origin', scn_uuid)
|
||||||
|
|
||||||
scene_graph_changed = [u for u in reversed(dependency_updates) if getattr(u.id, 'uuid', None) and isinstance(u.id,(bpy.types.Scene,bpy.types.Collection))]
|
scene_graph_changed = [u for u in reversed(dependency_updates) if getattr(
|
||||||
|
u.id, 'uuid', None) and isinstance(u.id, (bpy.types.Scene, bpy.types.Collection))]
|
||||||
if scene_graph_changed:
|
if scene_graph_changed:
|
||||||
porcelain.purge_orphan_nodes(session.repository)
|
porcelain.purge_orphan_nodes(session.repository)
|
||||||
|
|
||||||
update_external_dependencies()
|
update_external_dependencies()
|
||||||
|
|
||||||
|
|
||||||
@persistent
|
@persistent
|
||||||
def resolve_deps_graph(dummy):
|
def resolve_deps_graph(dummy):
|
||||||
"""Resolve deps graph
|
"""Resolve deps graph
|
||||||
@ -138,6 +146,13 @@ def update_client_frame(scene):
|
|||||||
'frame_current': scene.frame_current
|
'frame_current': scene.frame_current
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@persistent
|
||||||
|
def xr_user_update(scene):
|
||||||
|
if session and session.state == STATE_ACTIVE:
|
||||||
|
xr_timer = XrUserUpdate()
|
||||||
|
xr_timer.register()
|
||||||
|
logging.info("XR Session timer started")
|
||||||
|
|
||||||
|
|
||||||
def register():
|
def register():
|
||||||
bpy.app.handlers.undo_post.append(resolve_deps_graph)
|
bpy.app.handlers.undo_post.append(resolve_deps_graph)
|
||||||
@ -146,6 +161,8 @@ def register():
|
|||||||
bpy.app.handlers.load_pre.append(load_pre_handler)
|
bpy.app.handlers.load_pre.append(load_pre_handler)
|
||||||
bpy.app.handlers.frame_change_pre.append(update_client_frame)
|
bpy.app.handlers.frame_change_pre.append(update_client_frame)
|
||||||
|
|
||||||
|
bpy.app.handlers.xr_session_start_pre.append(xr_user_update)
|
||||||
|
|
||||||
|
|
||||||
def unregister():
|
def unregister():
|
||||||
bpy.app.handlers.undo_post.remove(resolve_deps_graph)
|
bpy.app.handlers.undo_post.remove(resolve_deps_graph)
|
||||||
@ -153,3 +170,5 @@ def unregister():
|
|||||||
|
|
||||||
bpy.app.handlers.load_pre.remove(load_pre_handler)
|
bpy.app.handlers.load_pre.remove(load_pre_handler)
|
||||||
bpy.app.handlers.frame_change_pre.remove(update_client_frame)
|
bpy.app.handlers.frame_change_pre.remove(update_client_frame)
|
||||||
|
|
||||||
|
bpy.app.handlers.xr_session_start_pre.remove(xr_user_update)
|
||||||
|
@ -68,6 +68,7 @@ stop_modal_executor = False
|
|||||||
|
|
||||||
|
|
||||||
def draw_user(username, metadata, radius=0.01, intensity=10.0):
|
def draw_user(username, metadata, radius=0.01, intensity=10.0):
|
||||||
|
# TODO: Draw camera model from viewmatrix
|
||||||
view_corners = metadata.get('view_corners')
|
view_corners = metadata.get('view_corners')
|
||||||
color = metadata.get('color', (1,1,1,0))
|
color = metadata.get('color', (1,1,1,0))
|
||||||
objects = metadata.get('selected_objects', None)
|
objects = metadata.get('selected_objects', None)
|
||||||
|
@ -26,7 +26,7 @@ import bgl
|
|||||||
import blf
|
import blf
|
||||||
import bpy
|
import bpy
|
||||||
import gpu
|
import gpu
|
||||||
import mathutils
|
from mathutils import Vector, Matrix, Quaternion
|
||||||
from bpy_extras import view3d_utils
|
from bpy_extras import view3d_utils
|
||||||
from gpu_extras.batch import batch_for_shader
|
from gpu_extras.batch import batch_for_shader
|
||||||
from replication.constants import (STATE_ACTIVE, STATE_AUTH, STATE_CONFIG,
|
from replication.constants import (STATE_ACTIVE, STATE_AUTH, STATE_CONFIG,
|
||||||
@ -136,7 +136,7 @@ def bbox_from_obj(obj: bpy.types.Object, index: int = 1) -> list:
|
|||||||
(-radius, +radius, +radius), (+radius, +radius, +radius)]
|
(-radius, +radius, +radius), (+radius, +radius, +radius)]
|
||||||
|
|
||||||
base = obj.matrix_world
|
base = obj.matrix_world
|
||||||
bbox_corners = [base @ mathutils.Vector(corner) for corner in coords]
|
bbox_corners = [base @ Vector(corner) for corner in coords]
|
||||||
|
|
||||||
vertex_pos = [(point.x, point.y, point.z) for point in bbox_corners]
|
vertex_pos = [(point.x, point.y, point.z) for point in bbox_corners]
|
||||||
|
|
||||||
@ -159,39 +159,12 @@ def bbox_from_instance_collection(ic: bpy.types.Object, index: int = 0) -> list:
|
|||||||
vertex_pos += vertex_pos_temp
|
vertex_pos += vertex_pos_temp
|
||||||
vertex_indices += vertex_indices_temp
|
vertex_indices += vertex_indices_temp
|
||||||
|
|
||||||
bbox_corners = [ic.matrix_world @ mathutils.Vector(vertex) for vertex in vertex_pos]
|
bbox_corners = [ic.matrix_world @ Vector(vertex) for vertex in vertex_pos]
|
||||||
|
|
||||||
vertex_pos = [(point.x, point.y, point.z) for point in bbox_corners]
|
vertex_pos = [(point.x, point.y, point.z) for point in bbox_corners]
|
||||||
|
|
||||||
return vertex_pos, vertex_indices
|
return vertex_pos, vertex_indices
|
||||||
|
|
||||||
def generate_user_camera() -> list:
|
|
||||||
""" Generate a basic camera represention of the user point of view
|
|
||||||
|
|
||||||
:return: list of 7 points
|
|
||||||
"""
|
|
||||||
area, region, rv3d = view3d_find()
|
|
||||||
|
|
||||||
v1 = v2 = v3 = v4 = v5 = v6 = v7 = [0, 0, 0]
|
|
||||||
|
|
||||||
if area and region and rv3d:
|
|
||||||
width = region.width
|
|
||||||
height = region.height
|
|
||||||
|
|
||||||
v1 = project_to_viewport(region, rv3d, (0, 0))
|
|
||||||
v3 = project_to_viewport(region, rv3d, (0, height))
|
|
||||||
v2 = project_to_viewport(region, rv3d, (width, height))
|
|
||||||
v4 = project_to_viewport(region, rv3d, (width, 0))
|
|
||||||
|
|
||||||
v5 = project_to_viewport(region, rv3d, (width/2, height/2))
|
|
||||||
v6 = list(rv3d.view_location)
|
|
||||||
v7 = project_to_viewport(
|
|
||||||
region, rv3d, (width/2, height/2), distance=-.8)
|
|
||||||
|
|
||||||
coords = [v1, v2, v3, v4, v5, v6, v7]
|
|
||||||
|
|
||||||
return coords
|
|
||||||
|
|
||||||
|
|
||||||
def project_to_screen(coords: list) -> list:
|
def project_to_screen(coords: list) -> list:
|
||||||
""" Project 3D coordinate to 2D screen coordinates
|
""" Project 3D coordinate to 2D screen coordinates
|
||||||
@ -219,10 +192,10 @@ def get_bb_coords_from_obj(object: bpy.types.Object, instance: bpy.types.Object
|
|||||||
base = object.matrix_world
|
base = object.matrix_world
|
||||||
|
|
||||||
if instance:
|
if instance:
|
||||||
scale = mathutils.Matrix.Diagonal(object.matrix_world.to_scale())
|
scale = Matrix.Diagonal(object.matrix_world.to_scale())
|
||||||
base = instance.matrix_world @ scale.to_4x4()
|
base = instance.matrix_world @ scale.to_4x4()
|
||||||
|
|
||||||
bbox_corners = [base @ mathutils.Vector(
|
bbox_corners = [base @ Vector(
|
||||||
corner) for corner in object.bound_box]
|
corner) for corner in object.bound_box]
|
||||||
|
|
||||||
|
|
||||||
@ -267,9 +240,14 @@ class Widget(object):
|
|||||||
|
|
||||||
class UserFrustumWidget(Widget):
|
class UserFrustumWidget(Widget):
|
||||||
# Camera widget indices
|
# Camera widget indices
|
||||||
indices = ((1, 3), (2, 1), (3, 0),
|
camera_vertex = ((0, 0, 1),
|
||||||
(2, 0), (4, 5), (1, 6),
|
(-1, -0.5, -1), (1, -0.5, -1), (1, 0.5, -1), (-1, 0.5, -1),
|
||||||
(2, 6), (3, 6), (0, 6))
|
(0, 1, -1),
|
||||||
|
(-0.5, 0.6, -1), (0.5, 0.6, -1))
|
||||||
|
|
||||||
|
camera_indices = ((0, 1), (0, 2), (0, 3), (0, 4),
|
||||||
|
(1, 2), (2, 3), (3, 4), (4, 1),
|
||||||
|
(5, 6), (6, 7), (7, 5))
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
@ -290,27 +268,33 @@ class UserFrustumWidget(Widget):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
scene_current = self.data.get('scene_current')
|
scene_current = self.data.get('scene_current')
|
||||||
view_corners = self.data.get('view_corners')
|
view_matrix = self.data.get('view_matrix')
|
||||||
|
|
||||||
return (scene_current == bpy.context.scene.name or
|
return (scene_current == bpy.context.scene.name or
|
||||||
self.settings.presence_show_far_user) and \
|
self.settings.presence_show_far_user) and \
|
||||||
view_corners and \
|
view_matrix and \
|
||||||
self.settings.presence_show_user and \
|
self.settings.presence_show_user and \
|
||||||
self.settings.enable_presence
|
self.settings.enable_presence
|
||||||
|
|
||||||
def draw(self):
|
def draw(self):
|
||||||
location = self.data.get('view_corners')
|
|
||||||
shader = gpu.shader.from_builtin('3D_UNIFORM_COLOR')
|
shader = gpu.shader.from_builtin('3D_UNIFORM_COLOR')
|
||||||
positions = [tuple(coord) for coord in location]
|
xr_state = self.data.get('xr')
|
||||||
|
transformation = Matrix()
|
||||||
|
if xr_state:
|
||||||
|
loc = Vector(xr_state.get('viewer_pose_location'))
|
||||||
|
rot = Quaternion(xr_state.get('viewer_pose_rotation'))
|
||||||
|
scale = Vector((1,1,1))
|
||||||
|
transformation = Matrix.LocRotScale(loc, rot, scale)
|
||||||
|
else:
|
||||||
|
transformation = Matrix(self.data.get('view_matrix')).inverted()
|
||||||
|
|
||||||
if len(positions) != 7:
|
coords = [transformation @ Vector(vertex) for vertex in self.camera_vertex]
|
||||||
return
|
|
||||||
|
|
||||||
batch = batch_for_shader(
|
batch = batch_for_shader(
|
||||||
shader,
|
shader,
|
||||||
'LINES',
|
'LINES',
|
||||||
{"pos": positions},
|
{"pos": coords},
|
||||||
indices=self.indices)
|
indices=self.camera_indices)
|
||||||
|
|
||||||
shader.bind()
|
shader.bind()
|
||||||
shader.uniform_float("color", self.data.get('color'))
|
shader.uniform_float("color", self.data.get('color'))
|
||||||
@ -405,19 +389,24 @@ class UserNameWidget(Widget):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
scene_current = self.data.get('scene_current')
|
scene_current = self.data.get('scene_current')
|
||||||
view_corners = self.data.get('view_corners')
|
view_matrix = self.data.get('view_matrix')
|
||||||
|
|
||||||
return (scene_current == bpy.context.scene.name or
|
return (scene_current == bpy.context.scene.name or
|
||||||
self.settings.presence_show_far_user) and \
|
self.settings.presence_show_far_user) and \
|
||||||
view_corners and \
|
view_matrix and \
|
||||||
self.settings.presence_show_user and \
|
self.settings.presence_show_user and \
|
||||||
self.settings.enable_presence
|
self.settings.enable_presence
|
||||||
|
|
||||||
def draw(self):
|
def draw(self):
|
||||||
view_corners = self.data.get('view_corners')
|
xr_state = self.data.get('xr')
|
||||||
|
|
||||||
|
if xr_state:
|
||||||
|
position = xr_state.get('viewer_pose_location', [0,0,0])
|
||||||
|
else:
|
||||||
|
position = Matrix(self.data.get('view_matrix')).inverted().to_translation()
|
||||||
|
|
||||||
color = self.data.get('color')
|
color = self.data.get('color')
|
||||||
position = [tuple(coord) for coord in view_corners]
|
coords = project_to_screen(position)
|
||||||
coords = project_to_screen(position[1])
|
|
||||||
|
|
||||||
if coords:
|
if coords:
|
||||||
blf.position(0, coords[0], coords[1]+10, 0)
|
blf.position(0, coords[0], coords[1]+10, 0)
|
||||||
|
@ -28,8 +28,7 @@ from replication import porcelain
|
|||||||
|
|
||||||
from . import operators, utils
|
from . import operators, utils
|
||||||
from .presence import (UserFrustumWidget, UserNameWidget, UserModeWidget, UserSelectionWidget,
|
from .presence import (UserFrustumWidget, UserNameWidget, UserModeWidget, UserSelectionWidget,
|
||||||
generate_user_camera, get_view_matrix, refresh_3d_view,
|
get_view_matrix, refresh_3d_view, refresh_sidebar_view, renderer)
|
||||||
refresh_sidebar_view, renderer)
|
|
||||||
|
|
||||||
from . import shared_data
|
from . import shared_data
|
||||||
|
|
||||||
@ -276,21 +275,24 @@ class ClientUpdate(Timer):
|
|||||||
|
|
||||||
if session and renderer:
|
if session and renderer:
|
||||||
if session.state in [STATE_ACTIVE, STATE_LOBBY]:
|
if session.state in [STATE_ACTIVE, STATE_LOBBY]:
|
||||||
local_user = session.online_users.get(
|
local_user = session.online_users.get(settings.username)
|
||||||
settings.username)
|
xr_session_state = bpy.context.window_manager.xr_session_state
|
||||||
|
|
||||||
if not local_user:
|
if not local_user:
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
for username, user_data in session.online_users.items():
|
for username, user_data in session.online_users.items():
|
||||||
if username != settings.username:
|
if username != settings.username:
|
||||||
cached_user_data = self.users_metadata.get(
|
cached_user_data = self.users_metadata.get(username)
|
||||||
username)
|
|
||||||
new_user_data = session.online_users[username]['metadata']
|
new_user_data = session.online_users[username]['metadata']
|
||||||
|
|
||||||
if cached_user_data is None:
|
if cached_user_data is None:
|
||||||
self.users_metadata[username] = user_data['metadata']
|
self.users_metadata[username] = user_data['metadata']
|
||||||
elif 'view_matrix' in cached_user_data and 'view_matrix' in new_user_data and cached_user_data['view_matrix'] != new_user_data['view_matrix']:
|
elif 'view_matrix' in cached_user_data and \
|
||||||
|
'view_matrix' in new_user_data and \
|
||||||
|
cached_user_data['view_matrix'] != new_user_data['view_matrix'] or \
|
||||||
|
'xr' in cached_user_data and \
|
||||||
|
'xr' in new_user_data and \
|
||||||
|
cached_user_data['xr']['viewer_pose_location'] != new_user_data['xr']['viewer_pose_location']:
|
||||||
refresh_3d_view()
|
refresh_3d_view()
|
||||||
self.users_metadata[username] = user_data['metadata']
|
self.users_metadata[username] = user_data['metadata']
|
||||||
break
|
break
|
||||||
@ -300,13 +302,12 @@ class ClientUpdate(Timer):
|
|||||||
local_user_metadata = local_user.get('metadata')
|
local_user_metadata = local_user.get('metadata')
|
||||||
scene_current = bpy.context.scene.name
|
scene_current = bpy.context.scene.name
|
||||||
local_user = session.online_users.get(settings.username)
|
local_user = session.online_users.get(settings.username)
|
||||||
current_view_corners = generate_user_camera()
|
current_view_matrix = get_view_matrix()
|
||||||
|
|
||||||
# Init client metadata
|
# Init client metadata
|
||||||
if not local_user_metadata or 'color' not in local_user_metadata.keys():
|
if not local_user_metadata or 'color' not in local_user_metadata.keys():
|
||||||
metadata = {
|
metadata = {
|
||||||
'view_corners': get_view_matrix(),
|
'view_matrix': current_view_matrix,
|
||||||
'view_matrix': get_view_matrix(),
|
|
||||||
'color': (settings.client_color.r,
|
'color': (settings.client_color.r,
|
||||||
settings.client_color.g,
|
settings.client_color.g,
|
||||||
settings.client_color.b,
|
settings.client_color.b,
|
||||||
@ -322,10 +323,8 @@ class ClientUpdate(Timer):
|
|||||||
elif scene_current != local_user_metadata['scene_current']:
|
elif scene_current != local_user_metadata['scene_current']:
|
||||||
local_user_metadata['scene_current'] = scene_current
|
local_user_metadata['scene_current'] = scene_current
|
||||||
porcelain.update_user_metadata(session.repository, local_user_metadata)
|
porcelain.update_user_metadata(session.repository, local_user_metadata)
|
||||||
elif 'view_corners' in local_user_metadata and current_view_corners != local_user_metadata['view_corners']:
|
elif 'view_matrix' in local_user_metadata and current_view_matrix != local_user_metadata['view_matrix']:
|
||||||
local_user_metadata['view_corners'] = current_view_corners
|
local_user_metadata['view_matrix'] = current_view_matrix
|
||||||
local_user_metadata['view_matrix'] = get_view_matrix(
|
|
||||||
)
|
|
||||||
porcelain.update_user_metadata(session.repository, local_user_metadata)
|
porcelain.update_user_metadata(session.repository, local_user_metadata)
|
||||||
elif bpy.context.mode != local_user_metadata['mode_current']:
|
elif bpy.context.mode != local_user_metadata['mode_current']:
|
||||||
local_user_metadata['mode_current'] = bpy.context.mode
|
local_user_metadata['mode_current'] = bpy.context.mode
|
||||||
@ -387,3 +386,28 @@ class MainThreadExecutor(Timer):
|
|||||||
function, kwargs = self.execution_queue.get()
|
function, kwargs = self.execution_queue.get()
|
||||||
logging.debug(f"Executing {function.__name__}")
|
logging.debug(f"Executing {function.__name__}")
|
||||||
function(**kwargs)
|
function(**kwargs)
|
||||||
|
|
||||||
|
class XrUserUpdate(Timer):
|
||||||
|
def __init__(self, timeout=.01):
|
||||||
|
# TODO: Add user refresh rate settings
|
||||||
|
super().__init__(timeout)
|
||||||
|
|
||||||
|
def execute(self):
|
||||||
|
xr_session_state = bpy.context.window_manager.xr_session_state
|
||||||
|
|
||||||
|
if xr_session_state and xr_session_state.is_running:
|
||||||
|
# Update user state
|
||||||
|
|
||||||
|
porcelain.update_user_metadata(
|
||||||
|
session.repository,
|
||||||
|
{'xr': {
|
||||||
|
'viewer_pose_location': list(xr_session_state.viewer_pose_location),
|
||||||
|
'viewer_pose_rotation': list(xr_session_state.viewer_pose_rotation),
|
||||||
|
'controller_0_location': list(xr_session_state.controller_grip_location_get(bpy.context, 0)),
|
||||||
|
'controller_0_rotation': list(xr_session_state.controller_grip_rotation_get(bpy.context, 0)),
|
||||||
|
'controller_1_location': list(xr_session_state.controller_grip_location_get(bpy.context, 1)),
|
||||||
|
'controller_1_rotation': list(xr_session_state.controller_grip_rotation_get(bpy.context, 1))}
|
||||||
|
})
|
||||||
|
else:
|
||||||
|
logging.info("XR Session ended, stopping user update")
|
||||||
|
self.unregister()
|
Loading…
Reference in New Issue
Block a user