public static Material LoadSubstanceMaterialWithName(string materialPath, string substanceName)
	{
	    Material material = LoadUnityMaterial(materialPath);
#if UNITY_2017_4_OR_NEWER || UNITY_2018_1_OR_NEWER
	    HEU_Logger.LogErrorFormat("Houdini Engine for Unity does not support the new Substance plugin as of yet!");
#elif UNITY_EDITOR
			if (material != null)
			{
				string assetPath = HEU_AssetDatabase.GetAssetPath(material);
				
				SubstanceImporter substanceImporter = AssetImporter.GetAtPath(assetPath) as SubstanceImporter;

				ProceduralMaterial[] proceduralMaterials = substanceImporter.GetMaterials();
				for(int i = 0; i < proceduralMaterials.Length; ++i)
				{
					if(proceduralMaterials[i].name.Equals(substanceName))
					{
						material = proceduralMaterials[i];
						break;
					}
				}
			}
#endif

	    if (material != null)
	    {
		HEU_Logger.LogFormat("Loaded Substance material with name {0} from path {1}.", substanceName, materialPath);
	    }
	    else
	    {
		HEU_Logger.LogWarningFormat("Failed to load Substance material with name {0} from path {1}.", substanceName, materialPath);
	    }

	    return material;
	}
	public static Material LoadSubstanceMaterialWithIndex(string materialPath, int substanceMaterialIndex)
	{
	    Material material = LoadUnityMaterial(materialPath);
#if UNITY_2017_4_OR_NEWER || UNITY_2018_1_OR_NEWER
	    HEU_Logger.LogErrorFormat("Houdini Engine for Unity does not support the new Substance plugin as of yet!");
#elif UNITY_EDITOR
			if (material != null)
			{
				string assetPath = HEU_AssetDatabase.GetAssetPath(material);
				SubstanceImporter substanceImporter = AssetImporter.GetAtPath(assetPath) as SubstanceImporter;

				if(substanceMaterialIndex >= 0 && substanceMaterialIndex < substanceImporter.GetMaterialCount())
				{
					material = substanceImporter.GetMaterials()[substanceMaterialIndex];
				}
			}
#endif
	    if (material != null)
	    {
		HEU_Logger.LogFormat("Loaded Substance material with index {0} from path {1}.", substanceMaterialIndex, materialPath);
	    }
	    else
	    {
		HEU_Logger.LogWarningFormat("Failed to load Substance material with index {0} from path {1}.", substanceMaterialIndex, materialPath);
	    }

	    return material;
	}
	public static Material GetNewMaterialWithShader(string assetCacheFolderPath, string shaderName, string materialName = "", bool bWriteToFile = true)
	{
	    Material material = null;
	    Shader shader = FindShader(shaderName);
	    if (shader != null)
	    {
		material = new Material(shader);
		if (materialName == null || materialName.Length == 0)
		{
		    material.name = shaderName;
		}
		else
		{
		    material.name = materialName;
		}

		if (bWriteToFile && !string.IsNullOrEmpty(assetCacheFolderPath))
		{
		    string materialFileName = materialName + HEU_Defines.HEU_EXT_MAT;
		    HEU_AssetDatabase.CreateObjectInAssetCacheFolder(material, assetCacheFolderPath, HEU_Defines.HEU_FOLDER_MATERIALS, materialFileName, typeof(Material), bOverwriteExisting: true);
		}
	    }
	    else
	    {
		HEU_Logger.LogWarningFormat("Shader with name {0} not found!", shaderName);
	    }
	    return material;
	}
示例#4
0
 /// <summary>
 /// Add the given attribute to the internal map by name.
 /// </summary>
 /// <param name="attribute">Attribute data to store</param>
 public void SetAttribute(HEU_OutputAttribute attribute)
 {
     if (string.IsNullOrEmpty(attribute._name))
     {
         HEU_Logger.LogWarningFormat("Unable to store attribute with empty name!", attribute._name);
         return;
     }
     _attributes.Add(attribute._name, attribute);
 }
	public static HEU_MaterialData CreateUnitySubstanceMaterialData(int materialKey, string materialPath, string substanceName, int substanceIndex, List<HEU_MaterialData> materialCache,
		string assetCacheFolderPath)
	{
	    // Let's make sure we can find the Unity or Substance material first
	    Material material = null;

	    HEU_MaterialData.Source sourceType = HEU_MaterialData.Source.UNITY;
	    if (!string.IsNullOrEmpty(substanceName))
	    {
		sourceType = HEU_MaterialData.Source.SUBSTANCE;
		material = HEU_MaterialFactory.LoadSubstanceMaterialWithName(materialPath, substanceName);
	    }
	    else if (substanceIndex >= 0)
	    {
		sourceType = HEU_MaterialData.Source.SUBSTANCE;
		material = HEU_MaterialFactory.LoadSubstanceMaterialWithIndex(materialPath, substanceIndex);
	    }
	    else if (!string.IsNullOrEmpty(materialPath))
	    {
		material = HEU_MaterialFactory.LoadUnityMaterial(materialPath);
	    }

	    if (material != null)
	    {
		HEU_MaterialData materialData = ScriptableObject.CreateInstance<HEU_MaterialData>();
		materialData._materialSource = sourceType;
		materialData._materialKey = materialKey;
		materialData._material = material;

		materialCache.Add(materialData);
		return materialData;
	    }
	    else
	    {
		// We can't find the material in Unity, so notify user and use a default one which allows to at least get the geometry in.
		if (string.IsNullOrEmpty(materialPath))
		{
		    HEU_Logger.LogWarningFormat("Empty material name found. Using default material.");
		}
		else if (materialPath.Contains("Resources/unity_builtin_extra"))
		{
		    // Built in material. Don't display error.
		}
		else
		{
		    HEU_Logger.LogErrorFormat("Unable to find {0} material {1}. Using a default material instead. Please check material exists in project and reload asset!", sourceType, materialPath);
		}

		// The materialKey helps uniquely identify this material for further look ups. But we also need to get a valid file name
		// to create the default material, so strip out just the file name.
		string strippedFileName = HEU_Platform.GetFileName(materialPath);
		return CreateMaterialInCache(materialKey, strippedFileName, HEU_MaterialData.Source.UNITY, false, materialCache, assetCacheFolderPath);
	    }
	}
	public static void ExecuteToolNoInput(string toolName, string toolPath)
	{
	    GameObject go = HEU_HAPIUtility.InstantiateHDA(toolPath, Vector3.zero, HEU_SessionManager.GetOrCreateDefaultSession(), false);
	    if (go == null)
	    {
		HEU_Logger.LogWarningFormat("Failed to instantiate tool: {0}", toolName);
	    }
	    else
	    {
		HEU_EditorUtility.SelectObject(go);
	    }
	}
	public static void ExecuteToolGenerator(string toolName, string toolPath, Vector3 targetPosition, Quaternion targetRotation, Vector3 targetScale)
	{
	    GameObject go = HEU_HAPIUtility.InstantiateHDA(toolPath, targetPosition, HEU_SessionManager.GetOrCreateDefaultSession(), true);
	    if (go != null)
	    {
		go.transform.rotation = targetRotation;
		go.transform.localScale = targetScale;

		HEU_EditorUtility.SelectObject(go);
	    }
	    else
	    {
		HEU_Logger.LogWarningFormat("Failed to instantiate tool: {0}", toolName);
	    }
	}
示例#8
0
	/// <summary>
	/// Create a unique asset cache folder for the given asset path.
	/// The given asset path should be the HDA's path in the project.
	/// </summary>
	/// <param name="suggestedAssetPath">A suggested path to try. Will use default if empty or null./param>
	/// <returns>Unique asset cache folder for given asset path</returns>
	public static string CreateAssetCacheFolder(string suggestedAssetPath, int hash = 0)
	{
#if UNITY_EDITOR
	    // We create a unique folder inside our plugin's asset database cache folder.

	    string assetDBPath = GetAssetCachePath();
	    string assetWorkingPath = HEU_Platform.BuildPath(assetDBPath, HEU_Defines.HEU_WORKING_PATH);
	    if (!AssetDatabase.IsValidFolder(assetWorkingPath))
	    {
		AssetDatabase.CreateFolder(assetDBPath, HEU_Defines.HEU_WORKING_PATH);
	    }

	    string fileName = HEU_Platform.GetFileNameWithoutExtension(suggestedAssetPath);
	    if (string.IsNullOrEmpty(fileName))
	    {
		fileName = "AssetCache";
		HEU_Logger.LogWarningFormat("Unable to get file name from {0}. Using default value: {1}.", suggestedAssetPath, fileName);
	    }

	    if (HEU_PluginSettings.ShortenFolderPaths && fileName.Length >= 3 && hash != 0)
	    {
		fileName = fileName.Substring(0, 3) + hash;
	    }

	    string fullPath = HEU_Platform.BuildPath(assetWorkingPath, fileName);

	    // Gives us the unique folder path, which we then separate out to create this folder
	    fullPath = AssetDatabase.GenerateUniqueAssetPath(fullPath);

	    CreatePathWithFolders(fullPath);
	    if (!AssetDatabase.IsValidFolder(fullPath))
	    {
		HEU_Logger.LogErrorFormat("Unable to create a valid asset cache folder: {0}! Check directory permission or that enough space is available!", fullPath);
		fullPath = null;
	    }

	    return fullPath;
#else
			// TODO RUNTIME: AssetDatabase is not supported at runtime. Do we need to support this for runtime?
			HEU_Logger.LogWarning(HEU_Defines.HEU_USERMSG_NONEDITOR_NOT_SUPPORTED);
			return null;
#endif
	}
	public static Dictionary<int, HEU_MaterialData> GetMaterialDataMapFromCache(List<HEU_MaterialData> materialCache)
	{
	    Dictionary<int, HEU_MaterialData> materialMap = new Dictionary<int, HEU_MaterialData>();
	    if (materialCache != null)
	    {
		foreach (HEU_MaterialData materialData in materialCache)
		{
		    if (materialData._materialKey == HEU_Defines.HEU_INVALID_MATERIAL)
		    {
			HEU_Logger.LogWarningFormat("Invalid material key found! Recommend to reload HDA!");
		    }
		    else
		    {
			materialMap.Add(materialData._materialKey, materialData);
		    }
		}
	    }
	    return materialMap;
	}
示例#10
0
	/// <summary>
	/// Import the asset at the given path.
	/// </summary>
	/// <param name="assetPath"></param>
	/// <param name="options"></param>
	public static void ImportAsset(string assetPath, HEU_ImportAssetOptions heuOptions)
	{
#if UNITY_EDITOR
	    ImportAssetOptions unityOptions = ImportAssetOptions.Default;
	    switch (heuOptions)
	    {
		case HEU_ImportAssetOptions.Default: unityOptions = ImportAssetOptions.Default; break;
		case HEU_ImportAssetOptions.ForceUpdate: unityOptions = ImportAssetOptions.ForceUpdate; break;
		case HEU_ImportAssetOptions.ForceSynchronousImport: unityOptions = ImportAssetOptions.ForceSynchronousImport; break;
		case HEU_ImportAssetOptions.ImportRecursive: unityOptions = ImportAssetOptions.ImportRecursive; break;
		case HEU_ImportAssetOptions.DontDownloadFromCacheServer: unityOptions = ImportAssetOptions.DontDownloadFromCacheServer; break;
		case HEU_ImportAssetOptions.ForceUncompressedImport: unityOptions = ImportAssetOptions.ForceUncompressedImport; break;
		default: HEU_Logger.LogWarningFormat("Unsupported import options: {0}", heuOptions); break;
	    }

	    AssetDatabase.ImportAsset(assetPath, unityOptions);
#else
			HEU_Logger.LogWarning(HEU_Defines.HEU_USERMSG_NONEDITOR_NOT_SUPPORTED);
#endif
	}
	/// <summary>
	/// Load stored session data and recreate the session objects.
	/// </summary>
	public static void LoadAllSessionData()
	{
	    // Clear existing sessions, and load session data from storage.
	    // Then create session for each session data.
	    _sessionMap.Clear();

	    List<HEU_SessionData> sessionDatas = HEU_PluginStorage.LoadAllSessionData();
	    foreach (HEU_SessionData sessionData in sessionDatas)
	    {
		if (sessionData != null)
		{
		    try
		    {
			// Create session based on type
			HEU_SessionBase sessionBase = CreateSessionFromType(sessionData.SessionClassType);
			if (sessionBase != null)
			{
			    sessionBase.SetSessionData(sessionData);
			    _sessionMap.Add(sessionData.SessionID, sessionBase);

			    if (sessionData.IsDefaultSession)
			    {
				_defaultSession = sessionBase;
			    }

			    // Find assets in scene with session ID. Check if valid and reset those that aren't.
			}
		    }
		    catch (System.Exception ex)
		    {
			HEU_Logger.LogWarningFormat("Loading session with ID {0} failed with {1}. Ignoring the session.", sessionData.SessionID, ex.ToString());
		    }
		}
	    }

	    InternalValidateSceneAssets();
	}
	/// <summary>
	/// Load the saved plugin settings from disk.
	/// </summary>
	/// <returns>True if successfully loaded.</returns>
	public bool LoadPluginData()
	{
	    // First check if settings pref file exists
	    string settingsFilePath = SettingsFilePath();
	    if (!HEU_Platform.DoesFileExist(settingsFilePath))
	    {
		// Try reading from EditorPrefs to see if this is still using the old method
		return ReadFromEditorPrefs();
	    }

	    // Open file and read each line to create the settings entry
	    using (StreamReader reader = new StreamReader(settingsFilePath))
	    {
		// Must match first line
		string line = reader.ReadLine();
		if (string.IsNullOrEmpty(line) || !line.Equals(PluginSettingsLine1))
		{
		    HEU_Logger.LogWarningFormat("Unable to load Plugin settings file. {0} should have line 1: {1}", settingsFilePath, PluginSettingsLine1);
		    return false;
		}

		// Must match 2nd line
		line = reader.ReadLine();
		if (string.IsNullOrEmpty(line) || !line.StartsWith(PluginSettingsLine2))
		{
		    HEU_Logger.LogWarningFormat("Unable to load Plugin settings file. {0} should start line 2 with: {1}", settingsFilePath, PluginSettingsLine2);
		    return false;
		}

		Dictionary<string, StoreData> storeMap = new Dictionary<string, StoreData>();
		string keyStr;
		string typeStr;
		string valueStr;
		DataType dataType;
		// "key(type)=value"
		System.Text.RegularExpressions.Regex regex = new System.Text.RegularExpressions.Regex(@"^(\w+)\((\w+)\)=(.*)");
		while ((line = reader.ReadLine()) != null)
		{
		    System.Text.RegularExpressions.Match match = regex.Match(line);
		    if (match.Success && match.Groups.Count >= 4)
		    {
			keyStr = match.Groups[1].Value;
			typeStr = match.Groups[2].Value;
			valueStr = match.Groups[3].Value;

			if (!string.IsNullOrEmpty(keyStr) && !string.IsNullOrEmpty(typeStr)
				&& !string.IsNullOrEmpty(valueStr))
			{
			    try
			    {
				dataType = (DataType)System.Enum.Parse(typeof(DataType), typeStr);

				StoreData store = new StoreData();
				store._type = dataType;
				store._valueStr = valueStr;
				storeMap.Add(keyStr, store);
			    }
			    catch (System.Exception ex)
			    {
				HEU_Logger.LogErrorFormat("Invalid data type found in settings: {0}. Exception: {1}", typeStr, ex.ToString());
			    }
			}
		    }
		}

		_dataMap = storeMap;
	    }

	    return true;
	}
        /// <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;

            if (parentAsset == null)
            {
                return;
            }

            bool bResult = true;

            //HEU_Logger.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, 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)
                {
                    if (HEU_GeneralUtility.HasValidInstanceAttribute(session, GeoID, partID, HEU_PluginSettings.UnityInstanceAttr))
                    {
                        isAttribInstancer = true;
                    }
                    else if (HEU_GeneralUtility.HasValidInstanceAttribute(session, GeoID, partID, HEU_Defines.HEIGHTFIELD_TREEINSTANCE_PROTOTYPEINDEX))
                    {
                        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, partID);
                }
                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)
                    {
                        HEU_Logger.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 mesh data to handle 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
                    HEU_Logger.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
                {
                    HEU_Logger.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
            HEU_Logger.LogFormat("PART PROCESS TIME:: NAME={0}, TIME={1}", HEU_SessionManager.GetString(partInfo.nameSH, session), (Time.realtimeSinceStartup - processPartStartTime));
#endif
        }
	public static void ExecuteToolOperatorMultiple(string toolName, string toolPath, GameObject[] inputObjects)
	{
	    GameObject outputObjectToSelect = null;

	    GameObject go = HEU_HAPIUtility.InstantiateHDA(toolPath, Vector3.zero, HEU_SessionManager.GetOrCreateDefaultSession(), false);
	    if (go == null)
	    {
		HEU_Logger.LogWarningFormat("Failed to instantiate tool: {0}", toolName);
		return;
	    }

	    HEU_HoudiniAssetRoot assetRoot = go.GetComponent<HEU_HoudiniAssetRoot>();
	    if (assetRoot != null)
	    {
		HEU_HoudiniAsset asset = assetRoot._houdiniAsset;
		HEU_SessionBase session = asset.GetAssetSession(true);

		int numInputs = inputObjects.Length;

		List<HEU_InputNode> inputNodes = asset.GetInputNodes();
		if (inputNodes == null || inputNodes.Count == 0)
		{
		    HEU_Logger.LogErrorFormat("Unable to assign input geometry due to no asset inputs on selected tool.");
		}
		else
		{
		    // User could have selected any number of inputs objects, and asset could have any number of inputs.
		    // So use minimum of either to set input object into asset input.
		    int minInputCount = Mathf.Min(inputNodes.Count, numInputs);
		    for (int i = 0; i < minInputCount; ++i)
		    {
			bool bShouldUseHDA = IsValidInputHDA(inputObjects[i]);

			if (!bShouldUseHDA &&!IsValidInputMesh(inputObjects[i]))
			{
			    continue;
			}
			else if (bShouldUseHDA && !IsValidInputHDA(inputObjects[i]))
			{
			    continue;
			}
			
			GameObject inputObject = inputObjects[i];

			HEU_InputNode inputNode = inputNodes[i];
			inputNode.ResetInputNode(session);


			if (!bShouldUseHDA)
			{
			    inputNode.ChangeInputType(session, HEU_InputNode.InputObjectType.UNITY_MESH);
    
			    HEU_InputObjectInfo inputInfo = inputNode.AddInputEntryAtEndMesh(inputObject);
			    if (inputInfo != null)
			    {
			        inputInfo._useTransformOffset = false;
			        inputNode.KeepWorldTransform = true;
			        inputNode.PackGeometryBeforeMerging = false;
    
			        inputNode.RequiresUpload = true;
			    }
			    else
			    {
			        HEU_Logger.LogErrorFormat("Invalid input format: {0}", inputObject.gameObject.name);
			    }
			}
			else
			{
			    inputNode.ChangeInputType(session, HEU_InputNode.InputObjectType.HDA);

			    HEU_InputHDAInfo inputHDAInfo = inputNode.AddInputEntryAtEndHDA(inputObject);
			    if (inputHDAInfo != null)
			    {
			        inputNode.KeepWorldTransform = true;
			        inputNode.PackGeometryBeforeMerging = false;
    
			        inputNode.RequiresUpload = true;
			    }
			    else
			    {
			        HEU_Logger.LogErrorFormat("Invalid input format: {0}", inputObject.gameObject.name);
			    }
			}
		    }

		    asset.RequestCook(true, true, true, true);

		    outputObjectToSelect = assetRoot.gameObject;
		}
	    }

	    if (outputObjectToSelect != null)
	    {
		HEU_EditorUtility.SelectObject(outputObjectToSelect);
	    }
	}
	public static void ExecuteToolOperatorSingle(string toolName, string toolPath, GameObject[] inputObjects)
	{
	    // Single operator means single asset input. If multiple inputs are provided, create tool for each input.

	    bool bShouldUseHDA = ShouldUseHDA(inputObjects);

	    List<GameObject> outputObjectsToSelect = new List<GameObject>();

	    int numInputs = inputObjects.Length;
	    for (int i = 0; i < numInputs; ++i)
	    {
		if (inputObjects[i] == null)
		{
		    continue;
		}

		if (!bShouldUseHDA && !IsValidInputMesh(inputObjects[i]))
		{
		    HEU_Logger.LogWarningFormat("Specified object {0} does not contain a valid mesh!", inputObjects[i].name);
		    continue;
		}

		if (bShouldUseHDA && !IsValidInputHDA(inputObjects[i]))
		{
		    HEU_Logger.LogWarningFormat("Specified object {0} does not contain a valid HDA input!", inputObjects[i].name);
		    continue;
		}

		GameObject inputObject = inputObjects[i];

		GameObject go = HEU_HAPIUtility.InstantiateHDA(toolPath, Vector3.zero, HEU_SessionManager.GetOrCreateDefaultSession(), false);
		if (go != null)
		{
		    HEU_HoudiniAssetRoot assetRoot = go.GetComponent<HEU_HoudiniAssetRoot>();
		    if (assetRoot != null)
		    {
			HEU_HoudiniAsset asset = assetRoot._houdiniAsset;
			HEU_SessionBase session = asset.GetAssetSession(true);

			List<HEU_InputNode> inputNodes = asset.GetInputNodes();
			if (inputNodes == null || inputNodes.Count == 0)
			{
			    HEU_Logger.LogErrorFormat("Unable to assign input geometry due to no asset inputs on selected tool.");
			}
			else
			{
			    HEU_InputNode inputNode = inputNodes[0];

			    inputNode.ResetInputNode(session);

			    if (!bShouldUseHDA)
			    {
				inputNode.ChangeInputType(session, HEU_InputNode.InputObjectType.UNITY_MESH);

				HEU_InputObjectInfo inputInfo = inputNode.AddInputEntryAtEndMesh(inputObject);
				if (inputInfo != null)
				{
				    inputInfo._useTransformOffset = false;
				    inputNode.KeepWorldTransform = true;
				    inputNode.PackGeometryBeforeMerging = false;

				    inputNode.RequiresUpload = true;

				    asset.RequestCook(true, true, true, true);

				    outputObjectsToSelect.Add(assetRoot.gameObject);
				}
				else
				{
				    HEU_Logger.LogErrorFormat("Invalid input format: {0}", inputObject.gameObject.name);
				}
			    }
			    else
			    {
				inputNode.ChangeInputType(session, HEU_InputNode.InputObjectType.HDA);

				HEU_InputHDAInfo inputHDAInfo = inputNode.AddInputEntryAtEndHDA(inputObject);
				if (inputHDAInfo != null)
				{
				    inputNode.KeepWorldTransform = true;
				    inputNode.PackGeometryBeforeMerging = false;

				    inputNode.RequiresUpload = true;
				    asset.RequestCook(true, true, true, true);
				    outputObjectsToSelect.Add(assetRoot.gameObject);
				}
				else
				{
				    HEU_Logger.LogErrorFormat("Invalid input format: {0}", inputObject.gameObject.name);
				}
			    }
			}
		    }
		}
		else
		{
		    HEU_Logger.LogWarningFormat("Failed to instantiate tool: {0}", toolName);
		}
	    }

	    if (outputObjectsToSelect.Count > 0)
	    {
		HEU_EditorUtility.SelectObjects(outputObjectsToSelect.ToArray());
	    }
	}
示例#16
0
	private bool DrawDetailsGeometry()
	{
	    bool bChanged = false;

	    EditorGUIUtility.labelWidth = 250;

	    {
		bool oldValue = HEU_PluginSettings.Curves_ShowInSceneView;
		bool newValue = HEU_EditorUI.DrawToggleLeft(oldValue, "Show Curves in Scene View");
		if (newValue != oldValue)
		{
		    HEU_PluginSettings.Curves_ShowInSceneView = newValue;
		    HEU_HoudiniAsset.SetCurvesVisibilityInScene(newValue);
		    bChanged = true;
		}
	    }
	    HEU_EditorUI.DrawSeparator();
	    {
		int oldValue = HEU_PluginSettings.MaxVerticesPerPrimitive;
		int newValue = EditorGUILayout.DelayedIntField("Max Vertices Per Primitive", oldValue);
		if (newValue != oldValue)
		{
		    if (newValue == 3 || newValue == 4)
		    {
			HEU_PluginSettings.MaxVerticesPerPrimitive = newValue;
			bChanged = true;
		    }
		    else
		    {
			HEU_Logger.LogWarningFormat("Plugin only supports 3 (triangles) or 4 (quads) max vertices values.");
		    }
		}
	    }
	    HEU_EditorUI.DrawSeparator();
	    {
		float oldValue = HEU_PluginSettings.NormalGenerationThresholdAngle;
		float newValue = EditorGUILayout.DelayedFloatField("Normal Generation Threshold Angle", oldValue);
		if (newValue != oldValue)
		{
		    HEU_PluginSettings.NormalGenerationThresholdAngle = newValue;
		    bChanged = true;
		}
	    }
	    HEU_EditorUI.DrawSeparator();
	    {
		string oldValue = HEU_PluginSettings.DefaultTerrainMaterial;
		if (_terrainMaterial == null && !string.IsNullOrEmpty(oldValue))
		{
		    //HEU_Logger.Log("Loading terrain material at: " + oldValue);
		    _terrainMaterial = HEU_MaterialFactory.LoadUnityMaterial(oldValue);
		}

		Material newMaterial = EditorGUILayout.ObjectField("Default Terrain Material", _terrainMaterial, typeof(Material), false) as Material;
		if (newMaterial != _terrainMaterial)
		{
		    string materialPath = "";
		    if (newMaterial != null)
		    {
			materialPath = HEU_AssetDatabase.GetAssetPathWithSubAssetSupport(newMaterial);
			if (!string.IsNullOrEmpty(materialPath) && (materialPath.StartsWith(HEU_Defines.DEFAULT_UNITY_BUILTIN_RESOURCES)))
			{
			    // Default materials need to be specially handled
			    materialPath = HEU_AssetDatabase.GetUniqueAssetPathForUnityAsset(newMaterial);
			    newMaterial = HEU_AssetDatabase.LoadUnityAssetFromUniqueAssetPath<Material>(materialPath);
			}
		    }

		    HEU_PluginSettings.DefaultTerrainMaterial = materialPath;
		    _terrainMaterial = newMaterial;
		    bChanged = true;
		}
	    }
	    HEU_EditorUI.DrawSeparator();
	    {
		string oldValue = HEU_PluginSettings.TerrainSplatTextureDefault;
		string newValue = EditorGUILayout.DelayedTextField("Default Terrain Splat Texture", oldValue);
		if (!newValue.Equals(oldValue))
		{
		    HEU_PluginSettings.TerrainSplatTextureDefault = newValue;
		    bChanged = true;
		}
	    }
	    HEU_EditorUI.DrawSeparator();
	    {
		string oldValue = HEU_PluginSettings.DefaultStandardShader;
		string newValue = EditorGUILayout.DelayedTextField("Default Standard Shader", oldValue);
		if (!newValue.Equals(oldValue))
		{
		    HEU_PluginSettings.DefaultStandardShader = newValue;
		    bChanged = true;
		}
	    }
	    HEU_EditorUI.DrawSeparator();
	    {
		string oldValue = HEU_PluginSettings.DefaultTransparentShader;
		string newValue = EditorGUILayout.DelayedTextField("Default Transparent Shader", oldValue);
		if (!newValue.Equals(oldValue))
		{
		    HEU_PluginSettings.DefaultTransparentShader = newValue;
		    bChanged = true;
		}
	    }
	    HEU_EditorUI.DrawSeparator();
	    {
		string oldValue = HEU_PluginSettings.DefaultVertexColorShader;
		string newValue = EditorGUILayout.DelayedTextField("Default Vertex Color Shader", oldValue);
		if (!newValue.Equals(oldValue))
		{
		    HEU_PluginSettings.DefaultVertexColorShader = newValue;
		    bChanged = true;
		}
	    }
	    HEU_EditorUI.DrawSeparator();
	    {
		string oldValue = HEU_PluginSettings.DefaultCurveShader;
		string newValue = EditorGUILayout.DelayedTextField("Default Curve Shader", oldValue);
		if (!newValue.Equals(oldValue))
		{
		    HEU_PluginSettings.DefaultCurveShader = newValue;
		    bChanged = true;
		}
	    }

	    HEU_EditorUI.DrawSeparator();

	    EditorGUIUtility.labelWidth = 0;

	    return bChanged;
	}
	/// <summary>
	/// Creates a mesh input node and uploads the mesh data from inputObject.
	/// </summary>
	/// <param name="session">Session that connectNodeID exists in</param>
	/// <param name="connectNodeID">The node to connect the network to. Most likely a SOP/merge node</param>
	/// <param name="inputObject">The gameobject containing the mesh components</param>
	/// <param name="inputNodeID">The created input node ID</param>
	/// <returns>True if created network and uploaded mesh data.</returns>
	public override bool CreateInputNodeWithDataUpload(HEU_SessionBase session, HAPI_NodeId connectNodeID, GameObject inputObject, out HAPI_NodeId inputNodeID)
	{
	    inputNodeID = HEU_Defines.HEU_INVALID_NODE_ID;

	    // Create input node, cook it, then upload the geometry data

	    if (!HEU_HAPIUtility.IsNodeValidInHoudini(session, connectNodeID))
	    {
		HEU_Logger.LogError("Connection node is invalid.");
		return false;
	    }

	    bool bExportColliders = settings != null && settings.ExportColliders == true;

	    // Get upload meshes from input object
	    HEU_InputDataMeshes inputMeshes = GenerateMeshDatasFromGameObject(inputObject, bExportColliders);
	    if (inputMeshes == null || inputMeshes._inputMeshes == null || inputMeshes._inputMeshes.Count == 0)
	    {
		HEU_Logger.LogError("No valid meshes found on input objects.");
		return false;
	    }

	    string inputName = null;
	    HAPI_NodeId newNodeID = HEU_Defines.HEU_INVALID_NODE_ID;
	    session.CreateInputNode(out newNodeID, inputName);
	    if (newNodeID == HEU_Defines.HEU_INVALID_NODE_ID || !HEU_HAPIUtility.IsNodeValidInHoudini(session, newNodeID))
	    {
		HEU_Logger.LogError("Failed to create new input node in Houdini session!");
		return false;
	    }

	    inputNodeID = newNodeID;

	    if (!UploadData(session, inputNodeID, inputMeshes))
	    {
		if (!session.CookNode(inputNodeID, false))
		{
		    HEU_Logger.LogError("New input node failed to cook!");
		    return false;
		}

		return false;
	    }

	    bool createMergeNode = false;
	    HAPI_NodeId mergeNodeId = HEU_Defines.HEU_INVALID_NODE_ID;

	    if (bExportColliders)
	    {
		createMergeNode = true;
	    }

	    if (!createMergeNode)
	    {
		return true;
	    }

	    HAPI_NodeId parentId = HEU_HAPIUtility.GetParentNodeID(session, newNodeID);

	    if (!session.CreateNode(parentId, "merge", null, false, out mergeNodeId))
	    {
		HEU_Logger.LogErrorFormat("Unable to create merge SOP node for connecting input assets.");
		return false;
	    }

	    if (!session.ConnectNodeInput(mergeNodeId, 0, newNodeID))
	    {
		HEU_Logger.LogErrorFormat("Unable to connect to input node!");
		return false;
	    }

	    if (!session.SetNodeDisplay(mergeNodeId, 1))
	    {
		HEU_Logger.LogWarningFormat("Unable to set display flag!");
	    }

	    inputNodeID = mergeNodeId;

	    if (bExportColliders)
	    {
		if (!UploadColliderData(session, mergeNodeId, inputMeshes, parentId))
		{
		    return false;
		}
	    }

	    if (!session.CookNode(inputNodeID, false))
	    {
	        HEU_Logger.LogError("New input node failed to cook!");
	        return false;
	    }
	    return true;
	}
	/// <summary>
	/// Returns HEU_UploadMeshData with mesh data found on meshGameObject.
	/// </summary>
	/// <param name="meshGameObject">The GameObject to query mesh data from</param>
	/// <returns>A valid HEU_UploadMeshData if mesh data found or null</returns>
	public static HEU_InputDataMesh CreateSingleMeshData(GameObject meshGameObject, bool bExportColliders)
	{
	    HEU_InputDataMesh meshData = new HEU_InputDataMesh();

	    if (meshGameObject == null)
	    {
		return null;
	    }

	    Mesh sharedMesh = GetMeshFromObject(meshGameObject);

	    if (sharedMesh == null)
	    {
		return null;
	    }

	    meshData._mesh = sharedMesh;
	    meshData._numVertices = meshData._mesh.vertexCount;
	    meshData._numSubMeshes = meshData._mesh.subMeshCount;

	    meshData._meshName = meshGameObject.name;

	    // Use project path is not saved in scene, otherwise just use name
	    if (HEU_GeneralUtility.IsGameObjectInProject(meshGameObject))
	    {
		meshData._meshPath = HEU_AssetDatabase.GetAssetOrScenePath(meshGameObject);
		if (string.IsNullOrEmpty(meshData._meshPath))
		{
		    meshData._meshPath = meshGameObject.name;
		}
	    }
	    else
	    {
		meshData._meshPath = meshGameObject.name;
	    }
	    //HEU_Logger.Log("Mesh Path: " + meshData._meshPath);

	    MeshRenderer meshRenderer = meshGameObject.GetComponent<MeshRenderer>();
	    if (meshRenderer != null)
	    {
		meshData._materials = meshRenderer.sharedMaterials;
	    }

	    meshData._transform = meshGameObject.transform;

	    if (bExportColliders && meshGameObject != null)
	    {
		meshData._colliders = new List<HEU_InputDataCollider>();

		Collider[] colliders = meshGameObject.GetComponents<Collider>();
		if (colliders != null)
		{
		    for (int i = 0; i < colliders.Length; i++)
		    {
			Collider collider = colliders[i];

			if (collider == null) continue;

			HEU_InputDataCollider newCollider = new HEU_InputDataCollider();
			newCollider._collider = collider;

			if (collider.GetType() == typeof(BoxCollider))
			{
			    newCollider._colliderType = HEU_InputColliderType.BOX;
			}
			else if (collider.GetType() == typeof(SphereCollider))
			{
			    newCollider._colliderType = HEU_InputColliderType.SPHERE;
			}
			else if (collider.GetType() == typeof(CapsuleCollider))
			{
			    newCollider._colliderType = HEU_InputColliderType.CAPSULE;
			}
			else if (collider.GetType() == typeof(MeshCollider))
			{
			    newCollider._colliderType = HEU_InputColliderType.MESH;
			}
			else
			{
			    HEU_Logger.LogWarningFormat("Collider type not supported: {0}", meshGameObject.name);
			    newCollider._collider = null;
			    newCollider._colliderType = HEU_InputColliderType.NONE;
			}

			if (newCollider._colliderType != HEU_InputColliderType.NONE)
			{
			    meshData._colliders.Add(newCollider);
			}
		    }
		}
	    }


	    return meshData;
	}
	public static void LoadShelves()
	{
	    bool bSaveShelf = false;

	    _shelves.Clear();

	    // Always add the default shelf
	    HEU_Shelf defaultShelf = AddShelf(HEU_Defines.HEU_HENGINE_SHIPPED_SHELF, HEU_Defines.HEU_HENGINE_TOOLS_SHIPPED_FOLDER);
	    if (defaultShelf == null)
	    {
		return;
	    }
	    
	    defaultShelf._defaultShelf = true;

	    List<string> shelfEntries = HEU_PluginSettings.HEngineToolsShelves;
	    if (shelfEntries == null || shelfEntries.Count == 0)
	    {
		shelfEntries = new List<string>();
	    }

	    // Convert shelf path + name to actual shelf objects
	    int numShelves = shelfEntries.Count;
	    for (int i = 0; i < numShelves; i++)
	    {
		string shelfName = "";
		string shelfPath = "";

		GetSplitShelfEntry(shelfEntries[i], out shelfName, out shelfPath);

		// Ignore default shelf because we added it already
		if (shelfPath.Equals(HEU_Defines.HEU_HENGINE_TOOLS_SHIPPED_FOLDER))
		{
		    continue;
		}

		if (!string.IsNullOrEmpty(shelfName) && !string.IsNullOrEmpty(shelfPath))
		{
		    HEU_Shelf newShelf = new HEU_Shelf();
		    newShelf._shelfName = shelfName;
		    newShelf._shelfPath = shelfPath;

		    _shelves.Add(newShelf);
		}
		else
		{
		    HEU_Logger.LogWarningFormat("Found invalid shelf with entry: {0}", shelfEntries[i]);
		    shelfEntries.RemoveAt(i);
		    i--;
		    bSaveShelf = true;
		}
	    }

	    foreach (HEU_Shelf shelf in _shelves)
	    {
		string realShelfPath = HEU_HAPIUtility.GetRealPathFromHFSPath(shelf._shelfPath);

		if (!HEU_Platform.DoesPathExist(realShelfPath))
		{
		    HEU_Logger.LogWarningFormat("Shelf path does not exist: {0}", realShelfPath);
		}
		else
		{
		    bool bShelfLoaded = LoadToolsFromDirectory(realShelfPath, out shelf._tools);
		    if (!bShelfLoaded)
		    {
			HEU_Logger.LogWarningFormat("Failed to load shelf {0} at path {1}", shelf._shelfName, realShelfPath);
		    }
		}
	    }

	    _currentSelectedShelf = HEU_PluginSettings.HEngineShelfSelectedIndex;
	    if (_currentSelectedShelf < 0 || _currentSelectedShelf >= _shelves.Count)
	    {
		_currentSelectedShelf = 0;
		HEU_PluginSettings.HEngineShelfSelectedIndex = _currentSelectedShelf;
	    }

	    if (bSaveShelf)
	    {
		SaveShelf();
	    }

	    _shelvesLoaded = true;
	}
示例#20
0
	/// <summary>
	/// Create an input node network and upload the given set of input objects.
	/// This creates a SOP/merge node, and input nodes for each object in inputObjects
	/// which are then connected to the merge node.
	/// It finds the input interface that supports each object in inputObjects for creating
	/// the input node and uploading the data based on the type of data.
	/// </summary>
	/// <param name="session">Session to create the input node in</param>
	/// <param name="assetID">Main asset ID</param>
	/// <param name="connectMergeID">Created SOP/merge node ID</param>
	/// <param name="inputObjects">List of input objects to upload</param>
	/// <param name="inputObjectsConnectedAssetIDs">List of input node IDs for the input nodes created</param>
	/// <param name="inputNode">The specified inputNode to create the node for (used for settings)</param>
	/// <returns>True if successfully uploading input nodes</returns>
	internal static bool CreateInputNodeWithMultiObjects(HEU_SessionBase session, HAPI_NodeId assetID,
		ref HAPI_NodeId connectMergeID, ref List<HEU_InputObjectInfo> inputObjects, ref List<HAPI_NodeId> inputObjectsConnectedAssetIDs, HEU_InputNode inputNode)
	{
	    bool bKeepWorldTransform = inputNode.KeepWorldTransform;
	    // Create the merge SOP node that the input nodes are going to connect to.
	    if (!session.CreateNode(-1, "SOP/merge", null, true, out connectMergeID))
	    {
		HEU_Logger.LogErrorFormat("Unable to create merge SOP node for connecting input assets.");
		return false;
	    }

	    int numObjects = inputObjects.Count;
	    for (int i = 0; i < numObjects; ++i)
	    {
		HAPI_NodeId newConnectInputID = HEU_Defines.HEU_INVALID_NODE_ID;
		inputObjectsConnectedAssetIDs.Add(newConnectInputID);

		// Skipping null gameobjects. Though if this causes issues, can always let it continue
		// to create input node, but not upload mesh data
		if (inputObjects[i]._gameObject == null)
		{
		    continue;
		}

		HEU_InputInterface inputInterface = GetInputInterface(inputObjects[i]);
		if (inputInterface == null)
		{
		    HEU_Logger.LogWarningFormat("No input interface found for gameobject: {0}. Skipping upload!", inputObjects[i]._gameObject.name);
		    continue;
		}

		// Apply settings based on the interface type.
		System.Type inputInterfaceType = inputInterface.GetType();
		if (inputInterfaceType == typeof(HEU_InputInterfaceMesh))
		{
		    HEU_InputInterfaceMesh meshInterface = inputInterface as HEU_InputInterfaceMesh;
		    meshInterface.Initialize(inputNode.MeshSettings);
		}
		if (inputInterfaceType == typeof(HEU_InputInterfaceTilemap))
		{
		    HEU_InputInterfaceTilemap tilemapInterface = inputInterface as HEU_InputInterfaceTilemap;
		    tilemapInterface.Initialize(inputNode.TilemapSettings);
		}

		bool bResult = inputInterface.CreateInputNodeWithDataUpload(session, connectMergeID, inputObjects[i]._gameObject, out newConnectInputID);
		if (!bResult || newConnectInputID == HEU_Defines.HEU_INVALID_NODE_ID)
		{
		    HEU_Logger.LogError("Failed to upload input.");
		    continue;
		}

		inputObjectsConnectedAssetIDs[i] = newConnectInputID;

		if (!session.ConnectNodeInput(connectMergeID, i, newConnectInputID))
		{
		    HEU_Logger.LogErrorFormat("Unable to connect input nodes!");
		    return false;
		}

		UploadInputObjectTransform(session, inputObjects[i], newConnectInputID, bKeepWorldTransform);
	    }

	    return true;
	}
        /// <summary>
        /// Upload the base height layer into heightfield network.
        /// </summary>
        /// <param name="session"></param>
        /// <param name="idt"></param>
        /// <returns></returns>
        public bool UploadHeightValuesWithTransform(HEU_SessionBase session, HEU_InputDataTerrain idt, ref HAPI_VolumeInfo volumeInfo)
        {
            // Get Geo, Part, and Volume infos
            HAPI_GeoInfo geoInfo = new HAPI_GeoInfo();

            if (!session.GetGeoInfo(idt._heightNodeID, ref geoInfo))
            {
                HEU_Logger.LogError("Unable to get geo info from heightfield node!");
                return(false);
            }

            HAPI_PartInfo partInfo = new HAPI_PartInfo();

            if (!session.GetPartInfo(geoInfo.nodeId, 0, ref partInfo))
            {
                HEU_Logger.LogError("Unable to get part info from heightfield node!");
                return(false);
            }

            volumeInfo = new HAPI_VolumeInfo();
            if (!session.GetVolumeInfo(idt._heightNodeID, 0, ref volumeInfo))
            {
                HEU_Logger.LogError("Unable to get volume info from heightfield node!");
                return(false);
            }

            if ((volumeInfo.xLength - 1) != Mathf.RoundToInt(idt._numPointsX / idt._voxelSize) ||
                (volumeInfo.yLength - 1) != Mathf.RoundToInt(idt._numPointsY / idt._voxelSize) ||
                idt._terrainData.heightmapResolution != volumeInfo.xLength ||
                idt._terrainData.heightmapResolution != volumeInfo.yLength)
            {
                HEU_Logger.LogWarning("Created heightfield in Houdini differs in voxel size from input terrain! Terrain may require resampling.");
            }

            // Update volume infos, and set it. This is required.
            volumeInfo.tileSize  = 1;
            volumeInfo.type      = HAPI_VolumeType.HAPI_VOLUMETYPE_HOUDINI;
            volumeInfo.storage   = HAPI_StorageType.HAPI_STORAGETYPE_FLOAT;
            volumeInfo.transform = idt._transform;

            volumeInfo.minX = 0;
            volumeInfo.minY = 0;
            volumeInfo.minZ = 0;

            volumeInfo.tupleSize = 1;
            volumeInfo.tileSize  = 1;

            volumeInfo.hasTaper = false;
            volumeInfo.xTaper   = 0f;
            volumeInfo.yTaper   = 0f;

            if (!session.SetVolumeInfo(idt._heightNodeID, partInfo.id, ref volumeInfo))
            {
                HEU_Logger.LogError("Unable to set volume info on input heightfield node!");
                return(false);
            }

            // Now set the height data
            float[,] heights = idt._terrainData.GetHeights(0, 0, idt._terrainData.heightmapResolution, idt._terrainData.heightmapResolution);
            int sizeX     = heights.GetLength(0);
            int sizeY     = heights.GetLength(1);
            int totalSize = sizeX * sizeY;

            // Convert to single array
            float[] heightsArr = new float[totalSize];
            for (int j = 0; j < sizeY; j++)
            {
                for (int i = 0; i < sizeX; i++)
                {
                    // Flip for coordinate system change
                    float h = heights[i, (sizeY - j - 1)];

                    heightsArr[i + j * sizeX] = h * idt._heightScale;
                }
            }

            if (volumeInfo.xLength != volumeInfo.yLength)
            {
                HEU_Logger.LogError("Error: Houdini heightmap must be square!");
                return(false);
            }

            if (idt._terrainData.heightmapResolution != volumeInfo.xLength)
            {
                // Resize heightsArr to idt._terrainData.heightmapResolution
                HEU_Logger.LogWarningFormat("Attempting to resize landscape from ({0}x{1}) to ({2}x{3})", idt._terrainData.heightmapResolution, idt._terrainData.heightmapResolution, volumeInfo.xLength, volumeInfo.xLength);
                heightsArr = HEU_TerrainUtility.ResampleData(heightsArr, idt._terrainData.heightmapResolution, idt._terrainData.heightmapResolution, volumeInfo.xLength, volumeInfo.xLength);
                sizeX      = volumeInfo.xLength;
                sizeY      = volumeInfo.yLength;
                totalSize  = sizeX * sizeY;
            }

            // Set the base height layer
            if (!session.SetHeightFieldData(idt._heightNodeID, 0, HEU_Defines.HAPI_HEIGHTFIELD_LAYERNAME_HEIGHT, heightsArr, 0, totalSize))
            {
                HEU_Logger.LogError("Unable to set height values on input heightfield node!");
                return(false);
            }

            SetTerrainDataAttributesToHeightField(session, geoInfo.nodeId, 0, idt._terrainData);

            SetTreePrototypes(session, geoInfo.nodeId, 0, idt._terrainData);

            if (!session.CommitGeo(idt._heightNodeID))
            {
                HEU_Logger.LogError("Unable to commit geo on input heightfield node!");
                return(false);
            }

            return(true);
        }