/// <summary> /// Retrieves object info from Houdini session and updates internal state. /// New geo nodes are created, unused geo nodes are destroyed. /// Geo nodes are then refreshed to be in sync with Houdini session. /// </summary> /// <returns>True if internal state has changed (including geometry).</returns> internal void UpdateObject(HEU_SessionBase session, bool bForceUpdate) { if (ParentAsset == null) { return; } // Update the geo info if (!session.GetObjectInfo(ObjectID, ref _objectInfo)) { return; } SyncWithObjectInfo(session); // Update the object transform _objectTransform = ParentAsset.GetObjectTransform(session, ObjectID); // Container for existing geo nodes that are still in use List<HEU_GeoNode> geoNodesToKeep = new List<HEU_GeoNode>(); // Container for new geo infos that need to be created List<HAPI_GeoInfo> newGeoInfosToCreate = new List<HAPI_GeoInfo>(); if (_objectInfo.haveGeosChanged || bForceUpdate) { // Indicates that the geometry nodes have changed //HEU_Logger.Log("Geos have changed!"); // Form a list of geo infos that are now present after cooking List<HAPI_GeoInfo> postCookGeoInfos = new List<HAPI_GeoInfo>(); bool useOutputNodes = true; if (ParentAsset) useOutputNodes = ParentAsset.UseOutputNodes; HEU_HAPIUtility.GatherAllAssetGeoInfos(session, ParentAsset.AssetInfo, _objectInfo, useOutputNodes, ref postCookGeoInfos); // Now for each geo node that are present after cooking, we check if its // new or whether we already have it prior to cooking. int numPostCookGeoInfos = postCookGeoInfos.Count; for (int i = 0; i < numPostCookGeoInfos; i++) { bool bFound = false; for (int j = 0; j < _geoNodes.Count; j++) { string geoName = HEU_SessionManager.GetString(postCookGeoInfos[i].nameSH, session); if (geoName.Equals(_geoNodes[j].GeoName)) { _geoNodes[j].SetGeoInfo(postCookGeoInfos[i]); geoNodesToKeep.Add(_geoNodes[j]); _geoNodes.RemoveAt(j); bFound = true; break; } } if (!bFound) { newGeoInfosToCreate.Add(postCookGeoInfos[i]); } } // Whatever is left in _geoNodes is no longer needed so clean up int numCurrentGeos = _geoNodes.Count; for (int i = 0; i < numCurrentGeos; ++i) { _geoNodes[i].DestroyAllData(); } } else { Debug.Assert(_objectInfo.geoCount == _geoNodes.Count, "Expected same number of geometry nodes."); } // Go through the old geo nodes that are still in use and update if necessary. foreach (HEU_GeoNode geoNode in geoNodesToKeep) { // Get geo info and check if geo changed bool bGeoChanged = bForceUpdate || geoNode.HasGeoNodeChanged(session); if (bGeoChanged) { geoNode.UpdateGeo(session); } else { if (_objectInfo.haveGeosChanged) { // Clear object instances since the object info has changed. // Without this, the object instances were never getting updated // if only the inputs changed but not outputs (of instancers). geoNode.ClearObjectInstances(); } // Visiblity might have changed, so update that geoNode.CalculateVisiblity(IsVisible()); geoNode.CalculateColliderState(); } } // Create the new geo infos and add to our keep list foreach (HAPI_GeoInfo newGeoInfo in newGeoInfosToCreate) { geoNodesToKeep.Add(CreateGeoNode(session, newGeoInfo)); } // Overwrite the old list with new _geoNodes = geoNodesToKeep; // Updating the trasform is done in GenerateGeometry }
/// <summary> /// Retrieves object info from Houdini session and updates internal state. /// New geo nodes are created, unused geo nodes are destroyed. /// Geo nodes are then refreshed to be in sync with Houdini session. /// </summary> /// <returns>True if internal state has changed (including geometry).</returns> public void UpdateObject(HEU_SessionBase session, bool bForceUpdate) { // Update the geo info if (!session.GetObjectInfo(ObjectID, ref _objectInfo)) { return; } SyncWithObjectInfo(session); // Update the object transform _objectTransform = ParentAsset.GetObjectTransform(session, ObjectID); // Container for existing geo nodes that are still in use List<HEU_GeoNode> geoNodesToKeep = new List<HEU_GeoNode>(); // Container for new geo infos that need to be created List<HAPI_GeoInfo> newGeoInfosToCreate = new List<HAPI_GeoInfo>(); if (_objectInfo.haveGeosChanged || bForceUpdate) { // Indicates that the geometry nodes have changed //Debug.Log("Geos have changed!"); // Form a list of geo infos that are now present after cooking List<HAPI_GeoInfo> postCookGeoInfos = new List<HAPI_GeoInfo>(); // Get the display geo info HAPI_GeoInfo displayGeoInfo = new HAPI_GeoInfo(); if (session.GetDisplayGeoInfo(_objectInfo.nodeId, ref displayGeoInfo, false)) { postCookGeoInfos.Add(displayGeoInfo); } else { displayGeoInfo.nodeId = HEU_Defines.HEU_INVALID_NODE_ID; } // Get editable nodes, cook em, then create geo nodes for them HAPI_NodeId[] editableNodes = null; HEU_SessionManager.GetComposedChildNodeList(session, _objectInfo.nodeId, (int)HAPI_NodeType.HAPI_NODETYPE_SOP, (int)HAPI_NodeFlags.HAPI_NODEFLAGS_EDITABLE, true, out editableNodes); if (editableNodes != null) { foreach (HAPI_NodeId editNodeID in editableNodes) { if (editNodeID != displayGeoInfo.nodeId) { session.CookNode(editNodeID, HEU_PluginSettings.CookTemplatedGeos); HAPI_GeoInfo editGeoInfo = new HAPI_GeoInfo(); if (session.GetGeoInfo(editNodeID, ref editGeoInfo)) { postCookGeoInfos.Add(editGeoInfo); } } } } // Now for each geo node that are present after cooking, we check if its // new or whether we already have it prior to cooking. int numPostCookGeoInfos = postCookGeoInfos.Count; for (int i = 0; i < numPostCookGeoInfos; i++) { bool bFound = false; for (int j = 0; j < _geoNodes.Count; j++) { string geoName = HEU_SessionManager.GetString(postCookGeoInfos[i].nameSH, session); if (geoName.Equals(_geoNodes[j].GeoName)) { _geoNodes[j].SetGeoInfo(postCookGeoInfos[i]); geoNodesToKeep.Add(_geoNodes[j]); _geoNodes.RemoveAt(j); bFound = true; break; } } if (!bFound) { newGeoInfosToCreate.Add(postCookGeoInfos[i]); } } // Whatever is left in _geoNodes is no longer needed so clean up int numCurrentGeos = _geoNodes.Count; for (int i = 0; i < numCurrentGeos; ++i) { _geoNodes[i].DestroyAllData(); } } else { Debug.Assert(_objectInfo.geoCount == _geoNodes.Count, "Expected same number of geometry nodes."); } // Go through the old geo nodes that are still in use and update if necessary. foreach (HEU_GeoNode geoNode in geoNodesToKeep) { // Get geo info and check if geo changed bool bGeoChanged = bForceUpdate || geoNode.HasGeoNodeChanged(session); if (bGeoChanged) { geoNode.UpdateGeo(session); } else { if (_objectInfo.haveGeosChanged) { // Clear object instances since the object info has changed. // Without this, the object instances were never getting updated // if only the inputs changed but not outputs (of instancers). geoNode.ClearObjectInstances(); } // Visiblity might have changed, so update that geoNode.CalculateVisiblity(IsVisible()); geoNode.CalculateColliderState(); } } // Create the new geo infos and add to our keep list foreach (HAPI_GeoInfo newGeoInfo in newGeoInfosToCreate) { geoNodesToKeep.Add(CreateGeoNode(session, newGeoInfo)); } // Overwrite the old list with new _geoNodes = geoNodesToKeep; // Updating the trasform is done in GenerateGeometry }
/// <summary> /// Gets the object infos and transforms for given asset. /// </summary> /// <param name="assetID">ID of the asset</param> /// <param name="nodeInfo">HAPI_NodeInfo of the asset</param> /// <param name="objectInfos">Array of retrieved object infos</param> /// <param name="objectTransforms">Array of retrieved object transforms</param> /// <returns>True if succesfully retrieved object infos and transforms</returns> public static bool GetObjectInfos(HEU_SessionBase session, HAPI_NodeId assetID, ref HAPI_NodeInfo nodeInfo, out HAPI_ObjectInfo[] objectInfos, out HAPI_Transform[] objectTransforms) { objectInfos = new HAPI_ObjectInfo[0]; objectTransforms = new HAPI_Transform[0]; if (nodeInfo.type == HAPI_NodeType.HAPI_NODETYPE_SOP) { // For SOP assets, we use the parent IDs to get the object info and geo info objectInfos = new HAPI_ObjectInfo[1]; if (!session.GetObjectInfo(nodeInfo.parentId, ref objectInfos[0])) { return(false); } // Identity transform will be used for SOP assets, so not querying transform objectTransforms = new HAPI_Transform[1]; objectTransforms[0] = new HAPI_Transform(true); } else if (nodeInfo.type == HAPI_NodeType.HAPI_NODETYPE_OBJ) { int objectCount = 0; if (!session.ComposeObjectList(assetID, out objectCount)) { return(false); } if (objectCount <= 0) { // Since this asset is an object type and has 0 object as children, we use the object itself objectInfos = new HAPI_ObjectInfo[1]; if (!session.GetObjectInfo(nodeInfo.id, ref objectInfos[0])) { return(false); } // Identity transform will be used for single object assets, so not querying transform objectTransforms = new HAPI_Transform[1]; objectTransforms[0] = new HAPI_Transform(true); } else { // This object has children, so use GetComposedObjectList to get list of HAPI_ObjectInfos objectInfos = new HAPI_ObjectInfo[objectCount]; if (!session.GetComposedObjectList(nodeInfo.parentId, objectInfos, 0, objectCount)) { return(false); } // Now get the object transforms objectTransforms = new HAPI_Transform[objectCount]; if (!HEU_SessionManager.GetComposedObjectTransformsMemorySafe(session, nodeInfo.parentId, HAPI_RSTOrder.HAPI_SRT, objectTransforms, 0, objectCount)) { return(false); } } } else { Debug.LogWarningFormat(HEU_Defines.HEU_NAME + ": Unsupported node type {0}", nodeInfo.type); return(false); } return(true); }