public HEU_SessionSyncData GetOrCreateSessionSync() { if (_sessionSync == null) { _sessionSync = new HEU_SessionSyncData(); } return(_sessionSync); }
/// <summary> /// Attempts to connect to running instance of Houdini with SessionSync enabled, /// with CONNECTION_ATTEMPT_RATE delay between attempts. Presuming that Houdini was just, /// launched this might take a few tries. Times out if unsuccessful after CONNECTION_TIME_OUT /// time. /// </summary> void UpdateConnecting(HEU_SessionSyncData syncData) { if (syncData == null || syncData.SyncStatus != HEU_SessionSyncData.Status.Connecting) { return; } // Attempt connection after waiting for a bit. if (Time.realtimeSinceStartup - syncData._timeLastUpdate >= CONNECTION_ATTEMPT_RATE) { if (InternalConnect(_sessionMode, _pipeName, HEU_PluginSettings.Session_Localhost, _port, HEU_PluginSettings.Session_AutoClose, HEU_PluginSettings.Session_Timeout, false)) { Log("Initializing..."); syncData.SyncStatus = HEU_SessionSyncData.Status.Initializing; try { HEU_SessionManager.InitializeDefaultSession(); HEU_SessionManager.GetDefaultSession().GetSessionData().SetSessionSync(syncData); syncData.SyncStatus = HEU_SessionSyncData.Status.Connected; Log("Connected!"); } catch (System.Exception ex) { syncData.SyncStatus = HEU_SessionSyncData.Status.Stopped; Log("Connection errored!"); Log(ex.ToString()); Debug.Log(ex.ToString()); } finally { // Clear this to get out of the connection state _connectionSyncData = null; } } else if (Time.realtimeSinceStartup - syncData._timeStartConnection >= CONNECTION_TIME_OUT) { syncData.SyncStatus = HEU_SessionSyncData.Status.Stopped; Log("Timed out trying to connect to Houdini." + "\nCheck if Houdini is running and SessionSync is enabled." + "\nCheck port or pipe name are correct by comparing with Houdini SessionSync panel."); } else { // Try again in a bit syncData._timeLastUpdate = Time.realtimeSinceStartup; } } }
/// <summary> /// Connect to a running instance of Houdini with SessionSync enabled. /// </summary> void ConnectSessionSync(HEU_SessionSyncData syncData) { if (syncData != null && syncData.SyncStatus != HEU_SessionSyncData.Status.Stopped) { return; } Log("Connecting To Houdini..."); HEU_SessionManager.RecreateDefaultSessionData(); if (syncData == null) { HEU_SessionData sessionData = HEU_SessionManager.GetSessionData(); if (sessionData != null) { syncData = sessionData.GetOrCreateSessionSync(); } else { syncData = new HEU_SessionSyncData(); } } bool result = InternalConnect(_sessionMode, _pipeName, HEU_PluginSettings.Session_Localhost, _port, HEU_PluginSettings.Session_AutoClose, HEU_PluginSettings.Session_Timeout, true); if (result) { try { HEU_SessionManager.InitializeDefaultSession(); HEU_SessionManager.GetDefaultSession().GetSessionData().SetSessionSync(syncData); syncData.SyncStatus = HEU_SessionSyncData.Status.Connected; Log("Connected!"); } catch (HEU_HoudiniEngineError ex) { syncData.SyncStatus = HEU_SessionSyncData.Status.Stopped; Log("Connection errored!"); Log(ex.ToString()); } } else { Log("Connection failed!"); } }
/// <summary> /// Upload the local HAPI_SessionSyncInfo to Houdini Engine. /// </summary> void UploadSessionSyncInfo(HEU_SessionBase session, HEU_SessionSyncData syncData) { if (session == null) { session = HEU_SessionManager.GetDefaultSession(); if (session == null || !session.IsSessionValid()) { return; } } session.SetSessionSyncInfo(ref syncData._syncInfo); }
/// <summary> /// Returns the local HEU_SessionSyncData state. /// </summary> HEU_SessionSyncData GetSessionSyncData() { HEU_SessionSyncData syncData = _connectionSyncData; if (syncData == null) { HEU_SessionData sessionData = HEU_SessionManager.GetSessionData(); if (sessionData != null) { // On domain reload, re-acquire serialized SessionSync // if session exists syncData = sessionData.GetOrCreateSessionSync(); } } return(syncData); }
/// <summary> /// Callback to update the local SessionSync state. /// </summary> void UpdateSync() { HEU_SessionSyncData syncData = GetSessionSyncData(); if (syncData != null) { if (syncData.SyncStatus == HEU_SessionSyncData.Status.Connecting) { UpdateConnecting(syncData); } else if (syncData.SyncStatus == HEU_SessionSyncData.Status.Connected) { UpdateConnected(syncData); } } }
/// <summary> /// Update the local SessionSync state while connected to Houdini. /// Synchronizes viewport if enabled. /// Disconnects if Houdini Engine session is not valid. /// </summary> void UpdateConnected(HEU_SessionSyncData syncData) { if (!HEU_PluginSettings.SessionSyncAutoCook) { return; } HEU_SessionBase session = HEU_SessionManager.GetDefaultSession(); if (session == null || !session.IsSessionValid() || !session.IsSessionSync()) { return; } if (session.ConnectionState == SessionConnectionState.CONNECTED) { // Get latest SessionSync info from Houdini Engine to synchronize // local state. DownloadSessionSyncInfo(null, syncData); // Use the above call to check validity of the session. // Note that once HAPI_IsSessionValid is improved, we might just use that. if (session.LastCallResultCode == HAPI_Result.HAPI_RESULT_INVALID_SESSION) { // Bad session Log("Session is invalid. Disconnecting."); Disconnect(syncData); return; } if (syncData._syncInfo.syncViewport) { UpdateViewport(session, syncData); } } else { if (syncData.SyncStatus == HEU_SessionSyncData.Status.Connected) { // Bad session Log("Session is invalid. Disconnecting."); Disconnect(syncData); } } }
/// <summary> /// Disconnect from SessionSync and close session. /// </summary> void Disconnect(HEU_SessionSyncData syncData) { if (syncData != null) { syncData.SyncStatus = HEU_SessionSyncData.Status.Stopped; // Store the sync info as it gets cleared in the session below _connectionSyncData = syncData; } if (HEU_SessionManager.CloseDefaultSession()) { Log("Connection closed!"); } else { Log("Failed to close session! "); } }
/// <summary> /// Download the latest HAPI_SessionSyncInfo from Houdini Engine /// to update the local state. /// </summary> void DownloadSessionSyncInfo(HEU_SessionBase session, HEU_SessionSyncData syncData) { if (session == null) { session = HEU_SessionManager.GetDefaultSession(); if (session == null || !session.IsSessionValid()) { return; } } HAPI_SessionSyncInfo syncInfo = new HAPI_SessionSyncInfo(); if (session.GetSessionSyncInfo(ref syncInfo)) { if (HEU_HAPIUtility.IsSessionSyncEqual(ref syncInfo, ref syncData._syncInfo)) { Repaint(); } syncData._syncInfo = syncInfo; } }
/// <summary> /// Launch Houdini with SessionSync enabled and automatically connect to it. /// </summary> void StartAndConnectToHoudini(HEU_SessionSyncData syncData) { if (syncData != null && syncData.SyncStatus != HEU_SessionSyncData.Status.Stopped) { return; } if (!OpenHoudini()) { return; } // Now attempt to connect to it by moving into Connecting state HEU_SessionManager.RecreateDefaultSessionData(); if (syncData == null) { HEU_SessionData sessionData = HEU_SessionManager.GetSessionData(); if (sessionData != null) { syncData = sessionData.GetOrCreateSessionSync(); } else { syncData = new HEU_SessionSyncData(); } syncData._validForConnection = true; } syncData.SyncStatus = HEU_SessionSyncData.Status.Connecting; _connectionSyncData = syncData; Log("Connecting..."); syncData._timeStartConnection = Time.realtimeSinceStartup; syncData._timeLastUpdate = Time.realtimeSinceStartup; }
/// <summary> /// Unity callback to draw this UI. /// </summary> void OnGUI() { SetupUI(); HEU_SessionSyncData syncData = GetSessionSyncData(); EditorGUI.BeginChangeCheck(); bool bSessionStarted = (syncData != null && syncData.SyncStatus != HEU_SessionSyncData.Status.Stopped); bool bSessionCanStart = !bSessionStarted; if (bSessionCanStart) { // Only able to start a session if no session exists. HEU_SessionBase session = HEU_SessionManager.GetDefaultSession(); if (session != null && session.IsSessionValid()) { bSessionCanStart = false; } } HEU_HoudiniAssetUI.DrawHeaderSection(); // Draw SessionSync status. if (syncData != null) { if (syncData.SyncStatus == HEU_SessionSyncData.Status.Stopped) { if (!bSessionCanStart) { EditorGUILayout.LabelField("Another session already running. Disconnect it to start SessionSync."); } else { EditorGUILayout.LabelField("Status: " + syncData.SyncStatus); } } else { EditorGUILayout.LabelField("Status: " + syncData.SyncStatus); } } else { if (!bSessionCanStart) { EditorGUILayout.LabelField("Another session already running. Disconnect it to start SessionSync."); } else { EditorGUILayout.LabelField("No active session."); } } EditorGUILayout.Separator(); EditorGUI.indentLevel++; // Draw initial connection buttons (Start, Connect) using (new EditorGUILayout.HorizontalScope()) { using (new EditorGUI.DisabledScope(bSessionStarted || !bSessionCanStart)) { if (GUILayout.Button("Start Houdini")) { StartAndConnectToHoudini(syncData); } else if (GUILayout.Button("Connect to Houdini")) { ConnectSessionSync(syncData); } } } using (new EditorGUI.DisabledScope((syncData == null || !bSessionStarted) && bSessionCanStart)) { if (GUILayout.Button("Disconnect")) { Disconnect(syncData); } } EditorGUILayout.Separator(); // Draw Connection Settings EditorGUILayout.LabelField("Connection Settings"); using (new EditorGUI.DisabledScope(bSessionStarted)) { SessionMode newSessionMode = (SessionMode)EditorGUILayout.EnumPopup("Type", _sessionMode); if (_sessionMode != newSessionMode) { _sessionMode = newSessionMode; HEU_PluginSettings.Session_Mode = newSessionMode; } EditorGUI.indentLevel++; if (_sessionMode == SessionMode.Pipe) { string newPipeName = EditorGUILayout.DelayedTextField("Pipe Name", _pipeName); if (_pipeName != newPipeName) { HEU_PluginSettings.Session_PipeName = newPipeName; _pipeName = newPipeName; } } else if (_sessionMode == SessionMode.Socket) { int newPort = EditorGUILayout.DelayedIntField("Port", _port); HEU_PluginSettings.Session_Port = newPort; if (_port != newPort) { HEU_PluginSettings.Session_Port = newPort; _port = newPort; } } EditorGUI.indentLevel--; } EditorGUILayout.Separator(); // The rest requires syncData // Synchronization settings, and new nodes if (syncData != null) { using (new EditorGUI.DisabledScope(syncData.SyncStatus != HEU_SessionSyncData.Status.Connected)) { EditorGUILayout.LabelField("Synchronization Settings"); EditorGUI.indentLevel++; HEU_PluginSettings.SessionSyncAutoCook = HEU_EditorUI.DrawToggleLeft(HEU_PluginSettings.SessionSyncAutoCook, "Sync With Houdini Cook"); bool enableHoudiniTime = HEU_EditorUI.DrawToggleLeft(syncData._syncInfo.cookUsingHoudiniTime, "Cook Using Houdini Time"); if (syncData._syncInfo.cookUsingHoudiniTime != enableHoudiniTime) { syncData._syncInfo.cookUsingHoudiniTime = enableHoudiniTime; UploadSessionSyncInfo(null, syncData); } bool enableSyncViewport = HEU_EditorUI.DrawToggleLeft(syncData._syncInfo.syncViewport, "Sync Viewport"); if (syncData._syncInfo.syncViewport != enableSyncViewport) { syncData._syncInfo.syncViewport = enableSyncViewport; UploadSessionSyncInfo(null, syncData); } EditorGUI.indentLevel--; } EditorGUILayout.Separator(); EditorGUILayout.LabelField("New Node"); using (new EditorGUI.DisabledScope(syncData.SyncStatus != HEU_SessionSyncData.Status.Connected)) { EditorGUI.indentLevel++; syncData._newNodeName = EditorGUILayout.TextField("Name", syncData._newNodeName); syncData._nodeTypeIndex = EditorGUILayout.Popup("Type", syncData._nodeTypeIndex, _nodeTypesLabels); using (new EditorGUI.DisabledGroupScope(string.IsNullOrEmpty(syncData._newNodeName))) { using (new EditorGUILayout.VerticalScope()) { if (GUILayout.Button("Create")) { if (syncData._nodeTypeIndex >= 0 && syncData._nodeTypeIndex < 3) { HEU_NodeSync.CreateNodeSync(null, _nodeTypes[syncData._nodeTypeIndex], syncData._newNodeName); } else if (syncData._nodeTypeIndex == 3) { CreateCurve(syncData._newNodeName); } else if (syncData._nodeTypeIndex == 4) { CreateInput(syncData._newNodeName); } } if (GUILayout.Button("Load NodeSync")) { LoadNodeSyncDialog(syncData._newNodeName); } } } EditorGUI.indentLevel--; } EditorGUILayout.Separator(); // Log using (new EditorGUILayout.VerticalScope(_backgroundStyle)) { using (new EditorGUILayout.HorizontalScope()) { EditorGUILayout.PrefixLabel(_eventMessageContent); if (GUILayout.Button("Clear")) { ClearLog(); } } string logMsg = GetLog(); using (var scrollViewScope = new EditorGUILayout.ScrollViewScope(_eventMessageScrollPos, GUILayout.Height(120))) { _eventMessageScrollPos = scrollViewScope.scrollPosition; GUILayout.Label(logMsg, _eventMessageStyle); } } } EditorGUI.indentLevel--; if (EditorGUI.EndChangeCheck() && syncData != null) { HEU_SessionBase sessionBase = HEU_SessionManager.GetDefaultSession(); if (sessionBase != null) { HEU_SessionManager.SaveAllSessionData(); } } }
/// <summary> /// Synchronize the viewport between HAPI and Unity. /// </summary> void UpdateViewport(HEU_SessionBase session, HEU_SessionSyncData syncData) { SceneView sceneView = SceneView.lastActiveSceneView; if (sceneView == null) { return; } // Get the latest viewport from HAPI, and check it agianst last update. HAPI_Viewport viewHAPI = new HAPI_Viewport(true); session.GetViewport(ref viewHAPI); if (!HEU_HAPIUtility.IsViewportEqual(ref viewHAPI, ref syncData._viewportHAPI)) { // HAPI has changed. Update local viewport. Transform target = sceneView.camera.transform; // Account for left-handed coordinate system Vector3 pivot = new Vector3(-viewHAPI.position[0], viewHAPI.position[1], viewHAPI.position[2]); Quaternion rotation = new Quaternion(viewHAPI.rotationQuaternion[0], viewHAPI.rotationQuaternion[1], viewHAPI.rotationQuaternion[2], viewHAPI.rotationQuaternion[3]); Vector3 euler = rotation.eulerAngles; euler.y = -euler.y; euler.z = -euler.z; // Flip the camera direction for Unity camera rotation = Quaternion.Euler(euler) * Quaternion.Euler(0, 180f, 0); // TODO: use viewHAPI.offset to set camera distance // Unfortuantely no direct API to set the camera distance in Unity sceneView.LookAtDirect(pivot, rotation); sceneView.Repaint(); // Store HAPI viewport for comparison on next update syncData._viewportHAPI = viewHAPI; syncData._viewportLocal = viewHAPI; syncData._viewportJustUpdated = true; } else { // HAPI hasn't changed, so let's see if local viewport has Vector3 pivot = sceneView.pivot; Quaternion rotation = sceneView.rotation; float localDistance = sceneView.cameraDistance; // Generate the local HAPI_Viewport HAPI_Viewport viewLocal = new HAPI_Viewport(true); // Account for left-handed coordinate system viewLocal.position[0] = -pivot.x; viewLocal.position[1] = pivot.y; viewLocal.position[2] = pivot.z; // Flip the camera direction for Unity camera rotation = rotation * Quaternion.Euler(0, 180f, 0); Vector3 euler = rotation.eulerAngles; euler.y = -euler.y; euler.z = -euler.z; rotation = Quaternion.Euler(euler); viewLocal.rotationQuaternion[0] = rotation.x; viewLocal.rotationQuaternion[1] = rotation.y; viewLocal.rotationQuaternion[2] = rotation.z; viewLocal.rotationQuaternion[3] = rotation.w; viewLocal.offset = syncData._viewportHAPI.offset; if (!HEU_HAPIUtility.IsViewportEqual(ref viewLocal, ref syncData._viewportLocal)) { // Always store local viewport for comparison on next update syncData._viewportLocal = viewLocal; if (syncData._viewportJustUpdated) { // Unity's SceneView internally updates the // viewport after setting it, so this makes sure // to update and store the latest change locally, // and skip sending it to HAPI syncData._viewportJustUpdated = false; } else { session.SetViewport(ref viewLocal); // Store HAPI viewport for comparison on next update syncData._viewportHAPI = viewLocal; } //Debug.Log("Setting HAPI (from local)"); //Debug.LogFormat("Pos: {0}, {1}, {2}", viewLocal.position[0], viewLocal.position[1], viewLocal.position[2]); //Debug.LogFormat("Rot: {0}, {1}, {2}, {3}", viewLocal.rotationQuaternion[0], //viewLocal.rotationQuaternion[1], viewLocal.rotationQuaternion[2], viewLocal.rotationQuaternion[3]); //Debug.LogFormat("Dis: {0}, sceneView.camDist: {1}", viewLocal.offset, sceneView.cameraDistance); } } }
public void SetSessionSync(HEU_SessionSyncData syncData) { _sessionSync = syncData; }