/// <summary> /// Loads a copy of the srcAsset at copyPath. Creates a copy if not found. /// </summary> /// <param name="srcAsset">The source asset object</param> /// <param name="copyPath">The full path to the copy</param> /// <param name="type">The type of source asset</param> /// <param name="bOverwriteExisting">Whether to overwrite existing copy if found</param> /// <returns>Returns loaded copy if exists or created, otherwise null</returns> public static Object CopyAndLoadAssetAtAnyPath(Object srcAsset, string copyPath, System.Type type, bool bOverwriteExisting) { #if UNITY_EDITOR string srcAssetPath = GetAssetPath(srcAsset); if (!string.IsNullOrEmpty(srcAssetPath)) { CreatePathWithFolders(copyPath); string fileName = HEU_Platform.GetFileName(srcAssetPath); string fullCopyPath = HEU_Platform.BuildPath(copyPath, fileName); if ((!bOverwriteExisting && HEU_Platform.DoesFileExist(fullCopyPath)) || CopyAsset(srcAssetPath, fullCopyPath)) { // Refresh database as otherwise we won't be able to load it in the next line. SaveAndRefreshDatabase(); return LoadAssetAtPath(fullCopyPath, type); } else { Debug.LogErrorFormat("Failed to copy and load asset from {0} to {1}!", srcAssetPath, fullCopyPath); } } return null; #else // TODO RUNTIME: AssetDatabase is not supported at runtime. Do we need to support this for runtime? Debug.LogWarning(HEU_Defines.HEU_USERMSG_NONEDITOR_NOT_SUPPORTED); return null; #endif }
/// <summary> /// Build up the asset environment paths set in unity_houdini.env. /// The paths must have key prefixes start with HEU_Defines.HEU_ENVPATH_PREFIX. /// When assets are loaded, these mappings are used to find real paths. /// </summary> public void LoadAssetEnvironmentPaths() { string envPath = HEU_Platform.GetHoudiniEngineEnvironmentFilePathFull(); if (!string.IsNullOrEmpty(envPath) && HEU_Platform.DoesFileExist(envPath)) { _envPathMap = new Dictionary<string, string>(); char[] delimiter = new char[] { '=' }; char[] trimEnd = new char[] { '\\', '/' }; using (var file = new System.IO.StreamReader(envPath)) { string line; while((line = file.ReadLine()) != null) { if (line.StartsWith(HEU_Defines.HEU_ENVPATH_PREFIX)) { string[] split = line.Split(delimiter, 2, System.StringSplitOptions.RemoveEmptyEntries); if(split != null && split.Length == 2) { string value = split[1].Replace("\\", "/").TrimEnd(trimEnd); _envPathMap.Add(split[0], value); } } } } } }
/// <summary> /// For the file path, returns a valid location if exists. /// If inFilePath is not valid, it uses the file name to search the asset database to /// find the actual valid location (in case it was moved). /// </summary> /// <param name="gameObjectName">Name of the asset for which to find the path.</param> /// <param name="inFilePath">Current path of the asset to validate. Could be null or invalid.</param> /// <returns>Valid path or null if none found.</returns> public static string LocateValidFilePath(string assetName, string inFilePath) { #if UNITY_EDITOR // Convert in path to real path if it was environment mapped previously (ie. has $key/blah.hda) inFilePath = HEU_PluginStorage.Instance.ConvertEnvKeyedPathToReal(inFilePath); // Find asset if its not at given path if (!HEU_Platform.DoesFileExist(inFilePath)) { string fileName = HEU_Platform.GetFileNameWithoutExtension(inFilePath); string[] guids = AssetDatabase.FindAssets(fileName); if (guids.Length > 0) { foreach (string guid in guids) { string newPath = AssetDatabase.GUIDToAssetPath(guid); if (newPath != null && newPath.Length > 0) { Debug.Log(string.Format("Note: changing asset path for {0} to {1}.", assetName, newPath)); return(newPath); } } } // No valid path throw new HEU_HoudiniEngineError(string.Format("Houdini Asset file has moved from last location: {0}", inFilePath)); } #endif return(inFilePath); }
/// <summary> /// For the file path, returns a valid location if exists. /// If inFilePath is not valid, it uses the file name to search the asset database to /// find the actual valid location (in case it was moved). /// </summary> /// <param name="gameObjectName">Name of the asset for which to find the path.</param> /// <param name="inFilePath">Current path of the asset to validate. Could be null or invalid.</param> /// <returns>Valid path or null if none found.</returns> public static string LocateValidFilePath(string assetName, string inFilePath) { #if UNITY_EDITOR // Find asset if its not at given path if (!HEU_Platform.DoesFileExist(inFilePath)) { string fileName = HEU_Platform.GetFileNameWithoutExtension(inFilePath); string[] guids = AssetDatabase.FindAssets(fileName); if (guids.Length > 0) { foreach (string guid in guids) { string newPath = AssetDatabase.GUIDToAssetPath(guid); if (newPath != null && newPath.Length > 0) { Debug.Log(string.Format("Note: changing asset path for {0} to {1}.", assetName, newPath)); return(newPath); } } } // No valid path throw new HEU_HoudiniEngineError(string.Format("Houdini Asset file has moved from last location: {0}", inFilePath)); } #endif return(inFilePath); }
private void SelectShelf(int index) { int numShelves = HEU_ShelfTools.GetNumShelves(); if(index >= 0 && index < numShelves) { HEU_Shelf shelf = HEU_ShelfTools.GetShelf(index); if (shelf != null) { int numTools = shelf._tools.Count; _guiContents = new GUIContent[numTools]; for (int i = 0; i < numTools; ++i) { _guiContents[i] = new GUIContent(); _guiContents[i].text = shelf._tools[i]._name; if (HEU_Platform.DoesFileExist(shelf._tools[i]._iconPath)) { _guiContents[i].image = HEU_GeneralUtility.LoadTextureFromFile(shelf._tools[i]._iconPath); } _guiContents[i].tooltip = shelf._tools[i]._toolTip; } } } }
public virtual bool DoAssetLoad() { string assetPath = _filePath; if (!HEU_Platform.DoesFileExist(assetPath)) { assetPath = HEU_AssetDatabase.GetValidAssetPath(assetPath); } HAPI_NodeId libraryID = -1; HAPI_NodeId newNodeID = -1; byte[] buffer = null; bool bResult = HEU_Platform.LoadFileIntoMemory(assetPath, out buffer); if (bResult) { if (!_session.LoadAssetLibraryFromMemory(buffer, true, out libraryID)) { HEU_Logger.LogErrorFormat("Unable to load asset library."); return false; } //HEU_Logger.Log("Loaded asset"); int assetCount = 0; bResult = _session.GetAvailableAssetCount(libraryID, out assetCount); if (!bResult) { return false; } int[] assetNameLengths = new int[assetCount]; bResult = _session.GetAvailableAssets(libraryID, ref assetNameLengths, assetCount); if (!bResult) { return false; } string[] assetNames = new string[assetCount]; for (int i = 0; i < assetCount; ++i) { assetNames[i] = HEU_SessionManager.GetString(assetNameLengths[i], _session); } // Create top level node. Note that CreateNode will cook the node if HAPI was initialized with threaded cook setting on. string topNodeName = assetNames[0]; bResult = _session.CreateNode(-1, topNodeName, "", false, out newNodeID); if (!bResult) { return false; } //HEU_Logger.Log("Created asset node"); _loadData._cookNodeID = newNodeID; } return true; }
public static string GetHoudiniEngineEnvironmentFilePathFull() { string envPath = HEU_PluginSettings.HoudiniEngineEnvFilePath; if (!HEU_Platform.IsPathRooted(envPath)) { envPath = HEU_AssetDatabase.GetAssetFullPath(envPath); } return HEU_Platform.DoesFileExist(envPath) ? envPath : ""; }
/// <summary> /// Create the given object inside the asset cache folder path, with relative folder path. /// Depending on type, it might store in a subfolder for organizational purposes. /// </summary> /// <param name="objectToCreate">The object to create inside the asset cache</param> /// <param name="assetCacheRoot">The target path in the asset cache</param> /// <param name="relativeFolderPath">If not null or empty, the relative path to append to the assetCacheRoot. /// Otherwise uses type of asset to get subfolder name.</param> /// <param name="assetFileName">The asset's file name</param> /// <param name="type">The type of asset</param> /// <param name="bOverwriteExisting">Whether or not to overwrite if there is an existing file</param> public static void CreateObjectInAssetCacheFolder(Object objectToCreate, string assetCacheRoot, string relativeFolderPath, string assetFileName, System.Type type, bool bOverwriteExisting) { #if UNITY_EDITOR Debug.Assert(!string.IsNullOrEmpty(assetCacheRoot), "Must give valid assetCacheFolderPath to create object at"); string subFolderPath = assetCacheRoot; if (!string.IsNullOrEmpty(relativeFolderPath)) { subFolderPath = HEU_Platform.BuildPath(subFolderPath, relativeFolderPath); } else { if (type == typeof(Mesh)) { subFolderPath = AppendMeshesPathToAssetFolder(assetCacheRoot); } else if (type == typeof(Material)) { subFolderPath = AppendMaterialsPathToAssetFolder(assetCacheRoot); } else if (type == typeof(TerrainData) #if UNITY_2018_3_OR_NEWER || (type == typeof(TerrainLayer)) #else || (type == typeof(SplatPrototype)) #endif ) { subFolderPath = AppendTerrainPathToAssetFolder(assetCacheRoot); } } // Make sure subfolders exist HEU_AssetDatabase.CreatePathWithFolders(subFolderPath); // Add file name string finalAssetPath = HEU_Platform.BuildPath(subFolderPath, assetFileName); if (HEU_Platform.DoesFileExist(finalAssetPath) && !bOverwriteExisting) { finalAssetPath = AssetDatabase.GenerateUniqueAssetPath(finalAssetPath); } AssetDatabase.CreateAsset(objectToCreate, finalAssetPath); // Commented out AssetDatabase.Refresh() below because its slow and seems to be unnecessary. // Leaving it commented in case need to revisit due to problems with asset creation. //RefreshAssetDatabase(); #else // TODO RUNTIME: AssetDatabase is not supported at runtime. Do we need to support this for runtime? Debug.LogWarning(HEU_Defines.HEU_USERMSG_NONEDITOR_NOT_SUPPORTED); #endif }
/// <summary> /// Finds Houdini asset at given file path by matching potential extensions. /// </summary> /// <param name="filePath">Path of file without extension</param> /// <returns>Valid path with extension or null of no asset found</returns> public static string FindHoudiniAssetFileInPathWithExt(string filePath) { string[] extensions = new string[] { ".otl", ".otllc", ".otlnc", ".hda", ".hdalc", ".hdanc" }; foreach (string ext in extensions) { string newPath = filePath + ext; if (HEU_Platform.DoesFileExist(newPath)) { return(newPath); } } return(null); }
/// <summary> /// Loads a copy of the given asset. Creates the copy if not found. /// </summary> /// <param name="srcAsset">Source asset whose copy will be loaded (and created if no copy exists).</param> /// <param name="newAssetFolderPath">Folder of to look for copy or create in</param> /// <param name="type">Type of asset</param> /// <returns>Loaded copy of the asset</returns> public static Object LoadAssetCopy(Object srcAsset, string newAssetFolderPath, System.Type type, bool bOverwriteExisting) { #if UNITY_EDITOR string srcAssetPath = GetAssetPath(srcAsset); if (!string.IsNullOrEmpty(srcAssetPath) && IsPathInAssetCache(srcAssetPath)) { string subFolderPath = newAssetFolderPath; if(type == typeof(Material)) { subFolderPath = AppendMaterialsPathToAssetFolder(newAssetFolderPath); } else if(type == typeof(Texture)) { subFolderPath = AppendTexturesPathToAssetFolder(newAssetFolderPath); } else if (type == typeof(Mesh)) { subFolderPath = AppendMeshesPathToAssetFolder(newAssetFolderPath); } else if (type == typeof(TerrainData)) { subFolderPath = AppendTerrainPathToAssetFolder(newAssetFolderPath); } CreatePathWithFolders(subFolderPath); string fileName = HEU_Platform.GetFileName(srcAssetPath); string newAssetPath = HEU_Platform.BuildPath(subFolderPath, fileName); if ((!bOverwriteExisting && HEU_Platform.DoesFileExist(newAssetPath)) || CopyAsset(srcAssetPath, newAssetPath)) { // Refresh database as otherwise we won't be able to load it in the next line. SaveAndRefreshDatabase(); return LoadAssetAtPath(newAssetPath, type); } else { Debug.LogErrorFormat("Failed to copy and load asset from {0} to {1}!", srcAssetPath, newAssetPath); } } return null; #else // TODO RUNTIME: AssetDatabase is not supported at runtime. Do we need to support this for runtime? Debug.LogWarning(HEU_Defines.HEU_USERMSG_NONEDITOR_NOT_SUPPORTED); return null; #endif }
/// <summary> /// Load and instantiate an HDA asset in Unity and Houdini, for the asset located at given path. /// </summary> /// <param name="filePath">Full path to the HDA in Unity project</param> /// <param name="initialPosition">Initial location to create the instance in Unity.</param> /// <returns>Returns the newly created gameobject for the asset in the scene, or null if creation failed.</returns> public static GameObject InstantiateHDA(string filePath, Vector3 initialPosition, HEU_SessionBase session, bool bBuildAsync) { if (filePath == null || !HEU_Platform.DoesFileExist(filePath)) { return(null); } // This will be the root GameObject for the HDA. Adding HEU_HoudiniAssetRoot // allows to use a custom Inspector. GameObject rootGO = new GameObject(HEU_Defines.HEU_DEFAULT_ASSET_NAME); HEU_HoudiniAssetRoot assetRoot = rootGO.AddComponent <HEU_HoudiniAssetRoot>(); // Under the root, we'll add the HEU_HoudiniAsset onto another GameObject // This will be marked as EditorOnly to strip out for builds GameObject hdaGEO = new GameObject(HEU_PluginSettings.HDAData_Name); hdaGEO.transform.parent = rootGO.transform; // This holds all Houdini Engine data HEU_HoudiniAsset asset = hdaGEO.AddComponent <HEU_HoudiniAsset>(); // Marking as EditorOnly to be excluded from builds if (HEU_GeneralUtility.DoesUnityTagExist(HEU_PluginSettings.EditorOnly_Tag)) { hdaGEO.tag = HEU_PluginSettings.EditorOnly_Tag; } // Bind the root to the asset assetRoot._houdiniAsset = asset; // Populate asset with what we know asset.SetupAsset(HEU_HoudiniAsset.HEU_AssetType.TYPE_HDA, filePath, rootGO, session); // Build it in Houdini Engine asset.RequestReload(bBuildAsync); // Apply Unity transform and possibly upload to Houdini Engine rootGO.transform.position = initialPosition; Debug.LogFormat("{0}: Created new HDA asset from {1} of type {2}.", HEU_Defines.HEU_NAME, filePath, asset.AssetType); return(rootGO); }
/// <summary> /// Loads image file and return as Texture. /// Presumes image file is PNG or JPG format (i.e. supported by Texture2D.LoadImage). /// </summary> /// <param name="filePath">Path to image file</param> /// <returns>Loaded texture or null if failed</returns> public static Texture LoadTextureFromFile(string filePath) { Texture2D newTexture = null; if (HEU_Platform.DoesFileExist(filePath)) { try { byte[] imageData = System.IO.File.ReadAllBytes(filePath); newTexture = new Texture2D(2, 2); newTexture.LoadImage(imageData); newTexture.Apply(); return newTexture; } catch (Exception ex) { Debug.LogErrorFormat("Loading image at {0} triggered exception: {1}", filePath, ex); } } return newTexture; }
public static HEU_ShelfToolData LoadToolFromJsonString(string json, string jsonFilePath) { //Debug.Log("Loading json: " + jsonFilePath); // Get environment variable for tool path string envValue = HEU_Platform.GetEnvironmentValue(HEU_Defines.HEU_PATH_KEY_TOOL); string envKey = string.Format("<{0}>", HEU_Defines.HEU_PATH_KEY_TOOL); HEU_ShelfToolData toolData = null; if (!string.IsNullOrEmpty(json)) { try { JSONNode jsonShelfNode = JSON.Parse(json); if (jsonShelfNode != null) { bool isObject = jsonShelfNode.IsObject; bool isArray = jsonShelfNode.IsArray; toolData = new HEU_ShelfToolData(); toolData._name = jsonShelfNode["name"]; toolData._toolType = (HEU_ShelfToolData.ToolType)System.Enum.Parse(typeof(HEU_ShelfToolData.ToolType), jsonShelfNode["toolType"]); toolData._toolTip = jsonShelfNode["toolTip"]; toolData._iconPath = jsonShelfNode["iconPath"]; toolData._assetPath = jsonShelfNode["assetPath"]; toolData._helpURL = jsonShelfNode["helpURL"]; JSONArray targetArray = jsonShelfNode["target"].AsArray; if(targetArray != null) { int targetCount = targetArray.Count; toolData._targets = new string[targetCount]; for(int j = 0; j < targetCount; ++j) { toolData._targets[j] = targetArray[j]; } } } } catch (System.Exception ex) { Debug.LogErrorFormat("Exception when trying to parse shelf json file at path: {0}. Exception: {1}", jsonFilePath, ex.ToString()); return null; } toolData._jsonPath = jsonFilePath; if (toolData != null && !string.IsNullOrEmpty(toolData._name)) { // Make sure this tool targets Unity (must have "all" or "unity" set in target field) bool bCompatiple = false; if(toolData._targets != null) { int numTargets = toolData._targets.Length; for(int i = 0; i < numTargets; ++i) { if (toolData._targets[i].Equals(TARGET_ALL) || toolData._targets[i].Equals(TARGET_UNITY)) { bCompatiple = true; break; } } } if (bCompatiple) { if (!string.IsNullOrEmpty(toolData._assetPath)) { toolData._assetPath = toolData._assetPath.Replace(HEU_Defines.HEU_PATH_KEY_PROJECT + "/", ""); if (toolData._assetPath.Contains(envKey)) { if (string.IsNullOrEmpty(envValue)) { Debug.LogErrorFormat("Environment value {0} used but not set in environment.", HEU_Defines.HEU_PATH_KEY_TOOL); } else { toolData._assetPath = toolData._assetPath.Replace(envKey, envValue); } } } else { toolData._assetPath = GetToolAssetPath(toolData, toolData._assetPath); } string realPath = HEU_PluginStorage.Instance.ConvertEnvKeyedPathToReal(toolData._assetPath); if (!HEU_Platform.DoesFileExist(realPath)) { Debug.LogErrorFormat("Houdini Engine shelf tool at {0} does not exist!", realPath); return null; } if (!string.IsNullOrEmpty(toolData._iconPath)) { toolData._iconPath = toolData._iconPath.Replace(HEU_Defines.HEU_PATH_KEY_PROJECT + "/", ""); if (toolData._iconPath.Contains(envKey)) { if (string.IsNullOrEmpty(envValue)) { Debug.LogErrorFormat("Environment value {0} used but not set in environment.", HEU_Defines.HEU_PATH_KEY_TOOL); } else { toolData._iconPath = toolData._iconPath.Replace(envKey, envValue); } } } else { toolData._iconPath = GetToolIconPath(toolData, toolData._iconPath); } return toolData; } } } return null; }
/// <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)) { Debug.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)) { Debug.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) { Debug.LogErrorFormat("Invalid data type found in settings: {0}. Exception: {1}", typeStr, ex.ToString()); } } } } _dataMap = storeMap; } return true; }
private void GenerateTerrain(HAPI_NodeId cookNodeId, List <HEU_LoadBufferVolume> terrainBuffers) { HEU_SessionBase session = GetHoudiniSession(true); Transform parent = this.gameObject.transform; // Directory to store generated terrain files. string outputTerrainpath = GetOutputCacheDirectory(); outputTerrainpath = HEU_Platform.BuildPath(outputTerrainpath, "Terrain"); int numVolumes = terrainBuffers.Count; for (int t = 0; t < numVolumes; ++t) { if (terrainBuffers[t]._heightMap != null) { GameObject newGameObject = new GameObject("heightfield_" + terrainBuffers[t]._tileIndex); HAPI_PartId partId = terrainBuffers[t]._id; ApplyAttributeModifiersOnGameObjectOutput(session, cookNodeId, partId, ref newGameObject); Transform newTransform = newGameObject.transform; newTransform.parent = parent; HEU_GeneratedOutput generatedOutput = new HEU_GeneratedOutput(); generatedOutput._outputData._gameObject = newGameObject; Terrain terrain = HEU_GeneralUtility.GetOrCreateComponent <Terrain>(newGameObject); #if !HEU_TERRAIN_COLLIDER_DISABLED TerrainCollider collider = HEU_GeneralUtility.GetOrCreateComponent <TerrainCollider>(newGameObject); #endif // The TerrainData and TerrainLayer files needs to be saved out if we create them. // Try user specified path, otherwise use the cache folder string exportTerrainDataPath = terrainBuffers[t]._terrainDataExportPath; if (string.IsNullOrEmpty(exportTerrainDataPath)) { // This creates the relative folder path from the Asset's cache folder: {assetCache}/{geo name}/Terrain/Tile{tileIndex}/... exportTerrainDataPath = HEU_Platform.BuildPath(outputTerrainpath, HEU_Defines.HEU_FOLDER_TERRAIN, HEU_Defines.HEU_FOLDER_TILE + terrainBuffers[t]._tileIndex); } bool bFullExportTerrainDataPath = HEU_Platform.DoesFileExist(exportTerrainDataPath); if (!string.IsNullOrEmpty(terrainBuffers[t]._terrainDataPath)) { // Load the source TerrainData, then make a unique copy of it in the cache folder TerrainData sourceTerrainData = HEU_AssetDatabase.LoadAssetAtPath(terrainBuffers[t]._terrainDataPath, typeof(TerrainData)) as TerrainData; if (sourceTerrainData == null) { Debug.LogWarningFormat("TerrainData, set via attribute, not found at: {0}", terrainBuffers[t]._terrainDataPath); } if (bFullExportTerrainDataPath) { terrain.terrainData = HEU_AssetDatabase.CopyAndLoadAssetAtGivenPath(sourceTerrainData, exportTerrainDataPath, typeof(TerrainData)) as TerrainData; } else { terrain.terrainData = HEU_AssetDatabase.CopyUniqueAndLoadAssetAtAnyPath(sourceTerrainData, exportTerrainDataPath, typeof(TerrainData)) as TerrainData; } if (terrain.terrainData != null) { // Store path so that it can be deleted on clean up AddGeneratedOutputFilePath(HEU_AssetDatabase.GetAssetPath(terrain.terrainData)); } } if (terrain.terrainData == null) { terrain.terrainData = new TerrainData(); if (bFullExportTerrainDataPath) { string folderPath = HEU_Platform.GetFolderPath(exportTerrainDataPath, true); HEU_AssetDatabase.CreatePathWithFolders(folderPath); HEU_AssetDatabase.CreateAsset(terrain.terrainData, exportTerrainDataPath); } else { string assetPathName = "TerrainData" + HEU_Defines.HEU_EXT_ASSET; HEU_AssetDatabase.CreateObjectInAssetCacheFolder(terrain.terrainData, exportTerrainDataPath, null, assetPathName, typeof(TerrainData)); } } TerrainData terrainData = terrain.terrainData; #if !HEU_TERRAIN_COLLIDER_DISABLED collider.terrainData = terrainData; #endif HEU_TerrainUtility.SetTerrainMaterial(terrain, terrainBuffers[t]._specifiedTerrainMaterialName); #if UNITY_2018_3_OR_NEWER terrain.allowAutoConnect = true; // This has to be set after setting material terrain.drawInstanced = true; #endif int heightMapSize = terrainBuffers[t]._heightMapWidth; terrainData.heightmapResolution = heightMapSize; if (terrainData.heightmapResolution != heightMapSize) { Debug.LogErrorFormat("Unsupported terrain size: {0}", heightMapSize); continue; } // The terrainData.baseMapResolution is not set here, but rather left to whatever default Unity uses // The terrainData.alphamapResolution is set later when setting the alphamaps. // 32 is the default for resolutionPerPatch const int detailResolution = 1024; const int resolutionPerPatch = 32; terrainData.SetDetailResolution(detailResolution, resolutionPerPatch); terrainData.SetHeights(0, 0, terrainBuffers[t]._heightMap); // Note that Unity uses a default height range of 600 when a flat terrain is created. // Without a non-zero value for the height range, user isn't able to draw heights. // Therefore, set 600 as the value if height range is currently 0 (due to flat heightfield). float heightRange = terrainBuffers[t]._heightRange; if (heightRange == 0) { heightRange = 600; } terrainData.size = new Vector3(terrainBuffers[t]._terrainSizeX, heightRange, terrainBuffers[t]._terrainSizeY); terrain.Flush(); // Set position HAPI_Transform hapiTransformVolume = new HAPI_Transform(true); hapiTransformVolume.position[0] += terrainBuffers[t]._position[0]; hapiTransformVolume.position[1] += terrainBuffers[t]._position[1]; hapiTransformVolume.position[2] += terrainBuffers[t]._position[2]; HEU_HAPIUtility.ApplyLocalTransfromFromHoudiniToUnity(ref hapiTransformVolume, newTransform); // Set layers Texture2D defaultTexture = HEU_VolumeCache.LoadDefaultSplatTexture(); int numLayers = terrainBuffers[t]._splatLayers.Count; #if UNITY_2018_3_OR_NEWER // Create TerrainLayer for each heightfield layer. // Note that height and mask layers are ignored (i.e. not created as TerrainLayers). // Since height layer is first, only process layers from 2nd index onwards. if (numLayers > 1) { // Keep existing TerrainLayers, and either update or append to them TerrainLayer[] existingTerrainLayers = terrainData.terrainLayers; // Total layers are existing layers + new alpha maps List <TerrainLayer> finalTerrainLayers = new List <TerrainLayer>(existingTerrainLayers); for (int m = 1; m < numLayers; ++m) { TerrainLayer terrainlayer = null; int terrainLayerIndex = -1; bool bSetTerrainLayerProperties = true; HEU_LoadBufferVolumeLayer layer = terrainBuffers[t]._splatLayers[m]; // Look up TerrainLayer file via attribute if user has set it if (!string.IsNullOrEmpty(layer._layerPath)) { terrainlayer = HEU_AssetDatabase.LoadAssetAtPath(layer._layerPath, typeof(TerrainLayer)) as TerrainLayer; if (terrainlayer == null) { Debug.LogWarningFormat("TerrainLayer, set via attribute, not found at: {0}", layer._layerPath); continue; } else { // Always check if its part of existing list so as not to add it again terrainLayerIndex = HEU_TerrainUtility.GetTerrainLayerIndex(terrainlayer, existingTerrainLayers); } } if (terrainlayer == null) { terrainlayer = new TerrainLayer(); terrainLayerIndex = finalTerrainLayers.Count; finalTerrainLayers.Add(terrainlayer); } else { // For existing TerrainLayer, make a copy of it if it has custom layer attributes // because we don't want to change the original TerrainLayer. if (layer._hasLayerAttributes) { // Copy the TerrainLayer file TerrainLayer prevTerrainLayer = terrainlayer; terrainlayer = HEU_AssetDatabase.CopyAndLoadAssetAtAnyPath(terrainlayer, outputTerrainpath, typeof(TerrainLayer), true) as TerrainLayer; if (terrainlayer != null) { if (terrainLayerIndex >= 0) { // Update the TerrainLayer reference in the list with this copy finalTerrainLayers[terrainLayerIndex] = terrainlayer; } else { // Newly added terrainLayerIndex = finalTerrainLayers.Count; finalTerrainLayers.Add(terrainlayer); } // Store path for clean up later AddGeneratedOutputFilePath(HEU_AssetDatabase.GetAssetPath(terrainlayer)); } else { Debug.LogErrorFormat("Unable to copy TerrainLayer '{0}' for generating Terrain. " + "Using original TerrainLayer. Will not be able to set any TerrainLayer properties.", layer._layerName); terrainlayer = prevTerrainLayer; bSetTerrainLayerProperties = false; // Again, continuing on to keep proper indexing. } } else { // Could be a layer in Assets/ but not part of existing layers in TerrainData terrainLayerIndex = finalTerrainLayers.Count; finalTerrainLayers.Add(terrainlayer); bSetTerrainLayerProperties = false; } } if (bSetTerrainLayerProperties) { if (!string.IsNullOrEmpty(layer._diffuseTexturePath)) { terrainlayer.diffuseTexture = HEU_MaterialFactory.LoadTexture(layer._diffuseTexturePath); } if (terrainlayer.diffuseTexture == null) { terrainlayer.diffuseTexture = defaultTexture; } terrainlayer.diffuseRemapMin = Vector4.zero; terrainlayer.diffuseRemapMax = Vector4.one; if (!string.IsNullOrEmpty(layer._maskTexturePath)) { terrainlayer.maskMapTexture = HEU_MaterialFactory.LoadTexture(layer._maskTexturePath); } terrainlayer.maskMapRemapMin = Vector4.zero; terrainlayer.maskMapRemapMax = Vector4.one; terrainlayer.metallic = layer._metallic; if (!string.IsNullOrEmpty(layer._normalTexturePath)) { terrainlayer.normalMapTexture = HEU_MaterialFactory.LoadTexture(layer._normalTexturePath); } terrainlayer.normalScale = layer._normalScale; terrainlayer.smoothness = layer._smoothness; terrainlayer.specular = layer._specularColor; terrainlayer.tileOffset = layer._tileOffset; if (layer._tileSize.magnitude == 0f && terrainlayer.diffuseTexture != null) { // Use texture size if tile size is 0 layer._tileSize = new Vector2(terrainlayer.diffuseTexture.width, terrainlayer.diffuseTexture.height); } terrainlayer.tileSize = layer._tileSize; } } terrainData.terrainLayers = finalTerrainLayers.ToArray(); } #else // Need to create SplatPrototype for each layer in heightfield, representing the textures. SplatPrototype[] splatPrototypes = new SplatPrototype[numLayers]; for (int m = 0; m < numLayers; ++m) { splatPrototypes[m] = new SplatPrototype(); HEU_LoadBufferVolumeLayer layer = terrainBuffers[t]._splatLayers[m]; Texture2D diffuseTexture = null; if (!string.IsNullOrEmpty(layer._diffuseTexturePath)) { diffuseTexture = HEU_MaterialFactory.LoadTexture(layer._diffuseTexturePath); } if (diffuseTexture == null) { diffuseTexture = defaultTexture; } splatPrototypes[m].texture = diffuseTexture; splatPrototypes[m].tileOffset = layer._tileOffset; if (layer._tileSize.magnitude == 0f && diffuseTexture != null) { // Use texture size if tile size is 0 layer._tileSize = new Vector2(diffuseTexture.width, diffuseTexture.height); } splatPrototypes[m].tileSize = layer._tileSize; splatPrototypes[m].metallic = layer._metallic; splatPrototypes[m].smoothness = layer._smoothness; if (!string.IsNullOrEmpty(layer._normalTexturePath)) { splatPrototypes[m].normalMap = HEU_MaterialFactory.LoadTexture(layer._normalTexturePath); } } terrainData.splatPrototypes = splatPrototypes; #endif // Set the splatmaps if (terrainBuffers[t]._splatMaps != null) { // Set the alphamap size before setting the alphamaps to get correct scaling // The alphamap size comes from the first alphamap layer int alphamapResolution = terrainBuffers[t]._heightMapWidth; if (numLayers > 1) { alphamapResolution = terrainBuffers[t]._splatLayers[1]._heightMapWidth; } terrainData.alphamapResolution = alphamapResolution; terrainData.SetAlphamaps(0, 0, terrainBuffers[t]._splatMaps); } // Set the tree scattering if (terrainBuffers[t]._scatterTrees != null) { HEU_TerrainUtility.ApplyScatterTrees(terrainData, terrainBuffers[t]._scatterTrees); } // Set the detail layers if (terrainBuffers[t]._detailPrototypes != null) { HEU_TerrainUtility.ApplyDetailLayers(terrain, terrainData, terrainBuffers[t]._detailProperties, terrainBuffers[t]._detailPrototypes, terrainBuffers[t]._detailMaps); } terrainBuffers[t]._generatedOutput = generatedOutput; _generatedOutputs.Add(generatedOutput); SetOutputVisiblity(terrainBuffers[t]); } } }
/// <summary> /// Returns true if file at inPath exists. Supports inPath with environment mapped values /// such as <HFS> or $. /// </summary> /// <param name="inPath">Path to file</param> /// <returns>True if file exists</returns> public static bool DoesMappedFileAtPathExist(string inPath) { string realPath = HEU_PluginStorage.Instance.ConvertEnvKeyedPathToReal(inPath); return(HEU_Platform.DoesFileExist(realPath)); }