/// <summary> /// Generate the instances of instancer parts. /// </summary> internal void GeneratePartInstances(HEU_SessionBase session) { List <HEU_PartData> partsToDestroy = new List <HEU_PartData>(); int numParts = _parts.Count; for (int i = 0; i < numParts; ++i) { if (_parts[i].IsPartInstancer() && !_parts[i].HaveInstancesBeenGenerated()) { if (!_parts[i].GeneratePartInstances(session)) { partsToDestroy.Add(_parts[i]); } } } int numPartsToDestroy = partsToDestroy.Count; for (int i = 0; i < numPartsToDestroy; ++i) { HEU_GeoNode parentNode = partsToDestroy[i].ParentGeoNode; if (parentNode != null) { parentNode.RemoveAndDestroyPart(partsToDestroy[i]); } else { HEU_PartData.DestroyPart(partsToDestroy[i]); } } partsToDestroy.Clear(); }
/// <summary> /// Process the part at the given index, creating its data (geometry), /// and adding it to the list of parts. /// </summary> /// <param name="session"></param> /// <param name="partID"></param> /// <returns>A valid HEU_PartData if it has been successfully processed.</returns> private void ProcessPart(HEU_SessionBase session, int partID, ref HAPI_PartInfo partInfo, ref HEU_PartData partData) { HEU_HoudiniAsset parentAsset = ParentAsset; bool bResult = true; //Debug.LogFormat("Part: name={0}, id={1}, type={2}, instanced={3}, instance count={4}, instance part count={5}", HEU_SessionManager.GetString(partInfo.nameSH, session), partID, partInfo.type, partInfo.isInstanced, partInfo.instanceCount, partInfo.instancedPartCount); #if HEU_PROFILER_ON float processPartStartTime = Time.realtimeSinceStartup; #endif bool isPartEditable = IsIntermediateOrEditable(); bool isAttribInstancer = false; if (IsGeoInputType()) { // Setup for input node to accept inputs if (_inputNode == null) { string partName = HEU_SessionManager.GetString(partInfo.nameSH, session); _inputNode = HEU_InputNode.CreateSetupInput(GeoID, 0, partName, HEU_InputNode.InputNodeType.NODE, ParentAsset); if (_inputNode != null) { ParentAsset.AddInputNode(_inputNode); } } if (HEU_HAPIUtility.IsSupportedPolygonType(partInfo.type) && partInfo.vertexCount == 0) { // No geometry for input asset if (partData != null) { // Clean up existing part HEU_PartData.DestroyPart(partData); partData = null; } // No need to process further since we don't have geometry return; } } else { // Preliminary check for attribute instancing (mesh type with no verts but has points with instances) if (HEU_HAPIUtility.IsSupportedPolygonType(partInfo.type) && partInfo.vertexCount == 0 && partInfo.pointCount > 0) { HAPI_AttributeInfo instanceAttrInfo = new HAPI_AttributeInfo(); HEU_GeneralUtility.GetAttributeInfo(session, GeoID, partID, HEU_PluginSettings.UnityInstanceAttr, ref instanceAttrInfo); if (instanceAttrInfo.exists && instanceAttrInfo.count > 0) { isAttribInstancer = true; } } } if (partInfo.type == HAPI_PartType.HAPI_PARTTYPE_INVALID) { // Clean up invalid parts if (partData != null) { HEU_PartData.DestroyPart(partData); partData = null; } } else if (partInfo.type < HAPI_PartType.HAPI_PARTTYPE_MAX) { // Process the part based on type. Keep or ignore. // We treat parts of type curve as curves, along with geo nodes that are editable and type curves if (partInfo.type == HAPI_PartType.HAPI_PARTTYPE_CURVE) { if (partData == null) { partData = ScriptableObject.CreateInstance <HEU_PartData>(); } partData.Initialize(session, partID, GeoID, _containerObjectNode.ObjectID, this, ref partInfo, HEU_PartData.PartOutputType.CURVE, isPartEditable, _containerObjectNode.IsInstancer(), false); SetupGameObjectAndTransform(partData, parentAsset); partData.ProcessCurvePart(session); } else if (partInfo.type == HAPI_PartType.HAPI_PARTTYPE_VOLUME) { // We only process "height" volume parts. Other volume parts are ignored for now. #if TERRAIN_SUPPORTED HAPI_VolumeInfo volumeInfo = new HAPI_VolumeInfo(); bResult = session.GetVolumeInfo(GeoID, partID, ref volumeInfo); if (!bResult) { Debug.LogErrorFormat("Unable to get volume info for geo node {0} and part {1} ", GeoID, partID); } else { if (Displayable && !IsIntermediateOrEditable()) { if (partData == null) { partData = ScriptableObject.CreateInstance <HEU_PartData>(); } else { // Clear volume data (case where switching from polygonal mesh to volume output) partData.ClearGeneratedMeshOutput(); } partData.Initialize(session, partID, GeoID, _containerObjectNode.ObjectID, this, ref partInfo, HEU_PartData.PartOutputType.VOLUME, isPartEditable, _containerObjectNode.IsInstancer(), false); SetupGameObjectAndTransform(partData, ParentAsset); } } #else Debug.LogWarningFormat("Terrain (heightfield volume) is not yet supported."); #endif } else if (partInfo.type == HAPI_PartType.HAPI_PARTTYPE_INSTANCER || isAttribInstancer) { if (partData == null) { partData = ScriptableObject.CreateInstance <HEU_PartData>(); } else { partData.ClearGeneratedMeshOutput(); partData.ClearGeneratedVolumeOutput(); } partData.Initialize(session, partID, GeoID, _containerObjectNode.ObjectID, this, ref partInfo, HEU_PartData.PartOutputType.INSTANCER, isPartEditable, _containerObjectNode.IsInstancer(), isAttribInstancer); SetupGameObjectAndTransform(partData, parentAsset); } else if (HEU_HAPIUtility.IsSupportedPolygonType(partInfo.type)) { if (partData == null) { partData = ScriptableObject.CreateInstance <HEU_PartData>(); } else { // Clear volume data (case where switching from something other output to mesh) partData.ClearGeneratedVolumeOutput(); } partData.Initialize(session, partID, GeoID, _containerObjectNode.ObjectID, this, ref partInfo, HEU_PartData.PartOutputType.MESH, isPartEditable, _containerObjectNode.IsInstancer(), false); // This check allows to ignore editable non-display nodes by default, but commented out to allow // them for now. Users can also ignore them by turning on IgnoreNonDisplayNodes //if (Displayable || (Editable && ParentAsset.EditableNodesToolsEnabled)) { SetupGameObjectAndTransform(partData, parentAsset); } } else { Debug.LogWarningFormat("Unsupported part type {0}", partInfo.type); } if (partData != null) { // Success! _parts.Add(partData); // Set unique name for the part string partName = HEU_PluginSettings.UseFullPathNamesForOutput ? GeneratePartFullName(partData.PartName) : partData.PartName; partData.SetGameObjectName(partName); // For intermediate or default-type editable nodes, setup the HEU_AttributeStore if (isPartEditable) { partData.SyncAttributesStore(session, _geoInfo.nodeId, ref partInfo); } else { // Remove attributes store if it has it partData.DestroyAttributesStore(); } } } #if HEU_PROFILER_ON Debug.LogFormat("PART PROCESS TIME:: NAME={0}, TIME={1}", HEU_SessionManager.GetString(partInfo.nameSH, session), (Time.realtimeSinceStartup - processPartStartTime)); #endif }
public void RemoveAndDestroyPart(HEU_PartData part) { _parts.Remove(part); HEU_PartData.DestroyPart(part); }
public void GenerateGeometry(HEU_SessionBase session, bool bRebuild) { // Volumes could come in as a geonode + part for each heightfield layer. // Otherwise the other geo types can be done individually. bool bResult = false; List<HEU_PartData> meshParts = new List<HEU_PartData>(); List<HEU_PartData> volumeParts = new List<HEU_PartData>(); List<HEU_PartData> partsToDestroy = new List<HEU_PartData>(); HEU_HoudiniAsset parentAsset = ParentAsset; foreach (HEU_GeoNode geoNode in _geoNodes) { geoNode.GetPartsByOutputType(meshParts, volumeParts); if (volumeParts.Count > 0) { // Volumes // Each layer in the volume is retrieved as a volume part, in the display geo node. // But we need to handle all layers as 1 terrain output in Unity, with 1 height layer and // other layers as alphamaps. geoNode.ProcessVolumeParts(session, volumeParts, bRebuild); // Clear the volume parts after processing since we are done with this set volumeParts.Clear(); } } // Meshes foreach (HEU_PartData part in meshParts) { // This returns false when there is no valid geometry or is not instancing. Should remove it as otherwise // stale data sticks around on recook bResult = part.GenerateMesh(session, parentAsset.GenerateUVs, parentAsset.GenerateTangents, parentAsset.GenerateNormals, parentAsset.UseLODGroups); if (!bResult) { partsToDestroy.Add(part); } } int numPartsToDestroy = partsToDestroy.Count; for (int i = 0; i < numPartsToDestroy; ++i) { HEU_GeoNode parentNode = partsToDestroy[i].ParentGeoNode; if (parentNode != null) { parentNode.RemoveAndDestroyPart(partsToDestroy[i]); } else { HEU_PartData.DestroyPart(partsToDestroy[i]); } } partsToDestroy.Clear(); ApplyObjectTransformToGeoNodes(); // Set visibility and attribute-based tag, layer, and scripts bool bIsVisible = IsVisible(); foreach (HEU_GeoNode geoNode in _geoNodes) { geoNode.CalculateVisiblity(bIsVisible); geoNode.CalculateColliderState(); geoNode.SetAttributeModifiersOnPartOutputs(session); } // Create editable attributes. // This should happen after visibility has been calculated above // since we need to show/hide the intermediate geometry during painting. foreach (HEU_PartData part in meshParts) { if (part.ParentGeoNode.IsIntermediateOrEditable()) { part.SetupAttributeGeometry(session); } } }
public void GenerateGeometry(HEU_SessionBase session) { // Volumes could come in as a geonode + part for each heightfield layer. // Otherwise the other geo types can be done individually. bool bResult = false; List<HEU_PartData> meshParts = new List<HEU_PartData>(); List<HEU_PartData> volumeParts = new List<HEU_PartData>(); List<HEU_PartData> partsToDestroy = new List<HEU_PartData>(); HEU_HoudiniAsset parentAsset = ParentAsset; foreach (HEU_GeoNode geoNode in _geoNodes) { geoNode.GetPartsByOutputType(meshParts, volumeParts); } // Meshes foreach (HEU_PartData part in meshParts) { bResult = part.GenerateMesh(session, parentAsset.GenerateUVs, parentAsset.GenerateTangents, parentAsset.GenerateNormals, parentAsset.UseLODGroups); if (!bResult) { partsToDestroy.Add(part); } } #if TERRAIN_SUPPORTED // Volumes // Each layer in the volume is retrieved as a volume part, in the display geo node. // But we need to handle all layers as 1 terrain output in Unity, with 1 height layer and // other layers as alphamaps. if (volumeParts.Count > 0) { HEU_PartData heightLayerPart = null; HEU_VolumeCache volumeCache = new HEU_VolumeCache(); volumeCache.GenerateTerrainFromParts(session, volumeParts, ParentAsset, out heightLayerPart); // Remove volume parts that are not the height layer (even if heightLayerPart is null) foreach (HEU_PartData part in volumeParts) { if (part != heightLayerPart) { partsToDestroy.Add(part); } } } #endif int numPartsToDestroy = partsToDestroy.Count; for(int i = 0; i < numPartsToDestroy; ++i) { HEU_GeoNode parentNode = partsToDestroy[i].ParentGeoNode; if (parentNode != null) { parentNode.RemoveAndDestroyPart(partsToDestroy[i]); } else { HEU_PartData.DestroyPart(partsToDestroy[i]); } } partsToDestroy.Clear(); ApplyObjectTransformToGeoNodes(); // Set visibility bool bIsVisible = IsVisible(); foreach (HEU_GeoNode geoNode in _geoNodes) { geoNode.CalculateVisiblity(bIsVisible); } // Create editable attributes. // This should happen after visibility has been calculated above // since we need to show/hide the intermediate geometry during painting. foreach (HEU_PartData part in meshParts) { if (part.ParentGeoNode.IsIntermediateOrEditable()) { part.SetupAttributeGeometry(session); } } }
/// <summary> /// Process the part at the given index, creating its data (geometry), /// and adding it to the list of parts. /// </summary> /// <param name="session"></param> /// <param name="partID"></param> /// <returns>A valid HEU_PartData if it has been successfully processed.</returns> private void ProcessPart(HEU_SessionBase session, int partID, ref HAPI_PartInfo partInfo, ref HEU_PartData partData) { HEU_HoudiniAsset parentAsset = ParentAsset; bool bResult = true; //Debug.LogFormat("Part: name={0}, id={1}, type={2}, instanced={3}, instance count={4}, instance part count={5}", HEU_SessionManager.GetString(partInfo.nameSH, session), partID, partInfo.type, partInfo.isInstanced, partInfo.instanceCount, partInfo.instancedPartCount); #if HEU_PROFILER_ON float processPartStartTime = Time.realtimeSinceStartup; #endif bool isPartEditable = IsIntermediateOrEditable(); if (IsGeoInputType()) { // Setup for input node to accept inputs if (_inputNode == null) { string partName = HEU_SessionManager.GetString(partInfo.nameSH, session); _inputNode = HEU_InputNode.CreateSetupInput(GeoID, 0, partName, HEU_InputNode.InputNodeType.NODE, ParentAsset); if (_inputNode != null) { ParentAsset.AddInputNode(_inputNode); } } if (partInfo.type == HAPI_PartType.HAPI_PARTTYPE_MESH && partInfo.vertexCount == 0) { // No geometry for input asset if (partData != null) { // Clean up existing part HEU_PartData.DestroyPart(partData); partData = null; } // No need to process further since we don't have geometry return; } } if (partInfo.type == HAPI_PartType.HAPI_PARTTYPE_INVALID) { // Clean up invalid parts if (partData != null) { HEU_PartData.DestroyPart(partData); partData = null; } } else if (partInfo.type < HAPI_PartType.HAPI_PARTTYPE_MAX) { // Process the part based on type. Keep or ignore. // We treat parts of type curve as curves, along with geo nodes that are editable and type curves if (partInfo.type == HAPI_PartType.HAPI_PARTTYPE_CURVE) { if (partData == null) { partData = ScriptableObject.CreateInstance <HEU_PartData>(); } partData.Initialize(session, partID, GeoID, _containerObjectNode.ObjectID, this, ref partInfo, HEU_PartData.PartOutputType.CURVE, isPartEditable); SetupGameObjectAndTransform(partData, parentAsset); partData.ProcessCurvePart(session); } else if (partInfo.type == HAPI_PartType.HAPI_PARTTYPE_VOLUME) { // We only process "height" volume parts. Other volume parts are ignored for now. #if TERRAIN_SUPPORTED HAPI_VolumeInfo volumeInfo = new HAPI_VolumeInfo(); bResult = session.GetVolumeInfo(GeoID, partID, ref volumeInfo); if (!bResult) { Debug.LogErrorFormat("Unable to get volume info for geo node {0} and part {1} ", GeoID, partID); } else { if (Displayable && !IsIntermediateOrEditable()) { if (partData == null) { partData = ScriptableObject.CreateInstance <HEU_PartData>(); } partData.Initialize(session, partID, GeoID, _containerObjectNode.ObjectID, this, ref partInfo, HEU_PartData.PartOutputType.VOLUME, isPartEditable); SetupGameObjectAndTransform(partData, ParentAsset); } } #else Debug.LogWarningFormat("Terrain (heightfield volume) is not yet supported."); #endif } else if (partInfo.type == HAPI_PartType.HAPI_PARTTYPE_MESH) { if (partData == null) { partData = ScriptableObject.CreateInstance <HEU_PartData>(); } partData.Initialize(session, partID, GeoID, _containerObjectNode.ObjectID, this, ref partInfo, HEU_PartData.PartOutputType.MESH, isPartEditable); SetupGameObjectAndTransform(partData, parentAsset); } else if (partInfo.type == HAPI_PartType.HAPI_PARTTYPE_INSTANCER) { if (partData == null) { partData = ScriptableObject.CreateInstance <HEU_PartData>(); } partData.Initialize(session, partID, GeoID, _containerObjectNode.ObjectID, this, ref partInfo, HEU_PartData.PartOutputType.INSTANCER, isPartEditable); SetupGameObjectAndTransform(partData, parentAsset); } else { Debug.LogWarningFormat("Unsupported part type {0}", partInfo.type); } if (partData != null) { // Success! _parts.Add(partData); // Set unique name for the part string partFullName = GeneratePartFullName(partData.PartName); partFullName = HEU_EditorUtility.GetUniqueNameForSibling(ParentAsset.RootGameObject.transform, partFullName); partData.SetGameObjectName(partFullName); // For intermediate or default-type editable nodes, setup the HEU_AttributeStore if (isPartEditable) { partData.SyncAttributesStore(session, _geoInfo.nodeId, ref partInfo); } else { // Remove attributes store if it has it partData.DestroyAttributesStore(); } HEU_GeneralUtility.AssignUnityTag(session, GeoID, partData.PartID, partData._gameObject); HEU_GeneralUtility.MakeStaticIfHasAttribute(session, GeoID, partData.PartID, partData._gameObject); } } #if HEU_PROFILER_ON Debug.LogFormat("PART PROCESS TIME:: NAME={0}, TIME={1}", HEU_SessionManager.GetString(partInfo.nameSH, session), (Time.realtimeSinceStartup - processPartStartTime)); #endif }