diff --git a/addons/io_hubs_addon/debugger.py b/addons/io_hubs_addon/debugger.py index 956aab60..9a362905 100644 --- a/addons/io_hubs_addon/debugger.py +++ b/addons/io_hubs_addon/debugger.py @@ -1,8 +1,9 @@ from bpy.app.handlers import persistent import bpy from bpy.types import Context + from .preferences import EXPORT_TMP_FILE_NAME, EXPORT_TMP_SCREENSHOT_FILE_NAME -from .utils import isModuleAvailable, save_prefs, image_type_to_file_ext +from .utils import isModuleAvailable, save_prefs, find_area, image_type_to_file_ext from .icons import get_hubs_icons from .hubs_session import HubsSession, PARAMS_TO_STRING from . import api @@ -61,15 +62,61 @@ def poll(cls, context: Context): def execute(self, context): try: + selected_obs = bpy.context.selected_objects + active_ob = bpy.context.active_object + + viewpoint = None + if context.scene.hubs_scene_debugger_room_export_prefs.avatar_to_viewport: + area = find_area("VIEW_3D") + if area is not None: + r3d = area.spaces[0].region_3d + view_mat = r3d.view_matrix.inverted() + loc, rot, _ = view_mat.decompose() + from mathutils import Matrix, Vector, Euler + from math import radians + final_loc = loc + Vector((0, 0, -1.6)) + rot_offset = Matrix.Rotation(radians(180), 4, 'Z').to_4x4() + final_rot = rot.to_matrix().to_4x4() @ rot_offset + euler = final_rot.to_euler() + euler.x = 0 + euler.y = 0 + + bpy.ops.object.empty_add(location=final_loc, rotation=(euler.x, euler.y, euler.z), type="ARROWS") + viewpoint = bpy.context.object + viewpoint.name = "__scene_debugger_viewpoint" + from .components.utils import add_component + add_component(viewpoint, "waypoint") + + for ob in selected_obs: + ob.select_set(True) + context.view_layer.objects.active = active_ob + export_scene(context) + hubs_session.update() hubs_session.bring_to_front(context) + if viewpoint: + hubs_session.move_to_waypoint("__scene_debugger_viewpoint") + ob = bpy.context.scene.objects["__scene_debugger_viewpoint"] + if ob: + bpy.data.objects.remove(ob, do_unlink=True) + + for ob in selected_obs: + ob.select_set(True) + context.view_layer.objects.active = active_ob + return {'FINISHED'} except Exception as err: print(err) bpy.ops.wm.hubs_report_viewer('INVOKE_DEFAULT', title="Hubs scene debugger report", report_string='\n\n'.join( ["The scene export has failed", "Check the export logs or quit the browser instance and try again", f'{err}'])) + + if viewpoint: + ob = bpy.context.scene.objects["__scene_debugger_viewpoint"] + if ob: + bpy.data.objects.remove(ob, do_unlink=True) + return {'CANCELLED'} @@ -315,6 +362,11 @@ def draw(self, context: Context): row.operator(HubsUpdateRoomOperator.bl_idname, text=f'{update_mode}') + row = box.row() + row.prop(context.scene.hubs_scene_debugger_room_export_prefs, "avatar_to_viewport") + if "debugLocalScene" not in hubs_session.room_params: + row.enabled = False + class HUBS_PT_ToolsSceneSessionPanel(bpy.types.Panel): bl_idname = "HUBS_PT_ToolsSceneSessionPanel" @@ -921,6 +973,10 @@ class HubsSceneDebuggerRoomExportPrefs(bpy.types.PropertyGroup): name='Sampling Animations', description='Apply sampling to all animations. This has been forced OFF because it can break animations in Hubs', default=False, options=set()) + avatar_to_viewport: bpy.props.BoolProperty( + name='Spawn using viewport transform', + description='Spawn the avatar in the current viewport camera position/rotation', + default=True, options=set()) class HubsSceneProject(bpy.types.PropertyGroup): diff --git a/addons/io_hubs_addon/hubs_session.py b/addons/io_hubs_addon/hubs_session.py index 13678170..46b2f028 100644 --- a/addons/io_hubs_addon/hubs_session.py +++ b/addons/io_hubs_addon/hubs_session.py @@ -59,6 +59,22 @@ try { params["reticulumUrl"] = window.$P.getReticulumFetchUrl(""); } catch (e) {}; return params; """ +JS_WAYPOINT_UPDATE = """ + window.__scene_debugger_scene_update_listener = () => { + try { + setTimeout(() => { + window.location = `${window.location.href}#${arguments[0]}`; + const mat = APP.world.scene.getObjectByName(`${arguments[0]}`).matrixWorld; + APP.scene.systems["hubs-systems"].characterController.travelByWaypoint(mat, false, false); + }, 0); + } catch(e) { + console.warn(e); + }; + APP.scene.removeEventListener("environment-scene-loaded", window.__scene_debugger_scene_update_listener); + delete window.__scene_debugger_scene_update_listener; + }; + APP.scene.addEventListener("environment-scene-loaded", window.__scene_debugger_scene_update_listener); +""" class HubsSession: @@ -296,6 +312,9 @@ def load(self, url): def is_local_instance(self): return "hub_id" in self._web_driver.current_url + def move_to_waypoint(self, name): + self._web_driver.execute_script(JS_WAYPOINT_UPDATE, name) + @property def user_logged_in(self): return self._user_logged_in diff --git a/addons/io_hubs_addon/utils.py b/addons/io_hubs_addon/utils.py index 0f4aa2f0..aadbd964 100644 --- a/addons/io_hubs_addon/utils.py +++ b/addons/io_hubs_addon/utils.py @@ -209,6 +209,25 @@ def load_prefs(context): new_scene["url"] = scene["url"] new_scene["screenshot_url"] = scene["screenshot_url"] + prefs["hubs_room_idx"] = scene_debugger["hubs_room_idx"] + prefs.hubs_rooms.clear() + rooms = scene_debugger["hubs_rooms"] + for room in rooms: + new_room = prefs.hubs_rooms.add() + new_room.name = room["name"] + new_room.url = room["url"] + + +def find_area(area_type): + try: + import bpy + for a in bpy.data.window_managers[0].windows[0].screen.areas: + if a.type == area_type: + return a + return None + except Exception as err: + return None + def image_type_to_file_ext(image_type): file_extension = None