public bool ApplyPreset(HEU_VolumeCachePreset volumeCachePreset)
		{
			UIExpanded = volumeCachePreset._uiExpanded;

			// Load the TerrainData if the path is given
			//Debug.Log("Get terraindata path: " + volumeCachePreset._terrainDataPath);
			if (!string.IsNullOrEmpty(volumeCachePreset._terrainDataPath))
			{
				_terrainData = HEU_AssetDatabase.LoadAssetAtPath(volumeCachePreset._terrainDataPath, typeof(TerrainData)) as TerrainData;
				//Debug.Log("Loaded terrain? " + (_terrainData != null ? "yes" : "no"));
			}

			foreach (HEU_VolumeLayerPreset layerPreset in volumeCachePreset._volumeLayersPresets)
			{
				HEU_VolumeLayer layer = GetLayer(layerPreset._layerName);
				if (layer == null)
				{
					Debug.LogWarningFormat("Volume layer with name {0} not found! Unable to set heightfield layer preset.", layerPreset._layerName);
					return false;
				}

				layer._strength = layerPreset._strength;
				layer._tile = layerPreset._tile;
				layer._uiExpanded = layerPreset._uiExpanded;
			}
			
			IsDirty = true;

			return true;
		}
		/// <summary>
		/// Loads texture at path which should be under a Resources/ folder.
		/// </summary>
		/// <param name="path">Path to texture, must be relative to a Resources/ folder.</param>
		/// <returns>Loaded texture or null if failed.</returns>
		public static Texture2D LoadTexture(string path)
		{
			if(HEU_AssetDatabase.IsPathRelativeToAssets(path) || System.IO.Path.IsPathRooted(path))
			{
				HEU_AssetDatabase.ImportAsset(path, HEU_AssetDatabase.HEU_ImportAssetOptions.Default);
				return HEU_AssetDatabase.LoadAssetAtPath(path, typeof(Texture2D)) as Texture2D;
			}
			else
			{
				// Try as relative path to Resources
				return Resources.Load<Texture2D>(path);
			}
		}
		public static Texture2D RenderAndExtractImageToTexture(HEU_SessionBase session, HAPI_MaterialInfo materialInfo, HAPI_ParmId textureParmID, string textureName, string assetCacheFolderPath)
		{
			//Debug.LogFormat("Rendering texture {0} with name {1} for material {2} at path {3}", textureParmID, textureName, materialInfo.nodeId, assetCacheFolderPath);

			Texture2D texture = null;

			// First we get Houdini to render the texture to an image buffer, then query the buffer over HAPI
			// Next we convert to PNG, and write out to file in our Assets directory
			// The reason for querying as a buffer is to workaround a bug with ExtractHoudiniImageToTextureFile 
			// Note: intentionly ignoring any errors as sometimes there aren't any textures
			if (session.RenderTextureToImage(materialInfo.nodeId, textureParmID, false))
			{
				texture = HEU_MaterialFactory.ExtractHoudiniImageToTextureRaw(session, materialInfo, "C A");
				if(texture != null)
				{
					texture.name = textureName;

					// Get the Textures folder in the assetCacheFolderPath. Make sure it exists.
					assetCacheFolderPath = HEU_AssetDatabase.AppendTexturesPathToAssetFolder(assetCacheFolderPath);
					HEU_AssetDatabase.CreatePathWithFolders(assetCacheFolderPath);

					// We are defaulting to PNG here if no extension already set. This forces it to use PNG format below.
					if (!textureName.EndsWith(".png") && !textureName.EndsWith(".jpg"))
					{
						textureName = textureName + ".png";
					}

					string textureFileName = HEU_Platform.BuildPath(assetCacheFolderPath, string.Format("{0}", textureName));

					byte[] encodedBytes;
					if(textureName.EndsWith(".jpg"))
					{
						encodedBytes = texture.EncodeToJPG();
					}
					else // Use PNG otherwise
					{
						encodedBytes = texture.EncodeToPNG();
					}
					HEU_Platform.WriteBytes(textureFileName, encodedBytes);

					// Re-import for project to recognize the new texture file
					HEU_AssetDatabase.ImportAsset(textureFileName, HEU_AssetDatabase.HEU_ImportAssetOptions.Default);

					// Load the new texture file
					texture = HEU_AssetDatabase.LoadAssetAtPath(textureFileName, typeof(Texture2D)) as Texture2D;
				}
				
				//texture = HEU_MaterialFactory.ExtractHoudiniImageToTextureFile(session, materialInfo, "C A", assetCacheFolderPath);
			}
			return texture;
		}
		/// <summary>
		/// Apply the cached scatter prototypes and instances to the given TerrainData.
		/// </summary>
		public static void ApplyScatterTrees(TerrainData terrainData, HEU_VolumeScatterTrees scatterTrees)
		{
#if UNITY_2019_1_OR_NEWER
			if (scatterTrees == null || scatterTrees._treePrototypInfos == null || scatterTrees._treePrototypInfos.Count == 0)
			{
				return;
			}

			// Load and set TreePrototypes
			GameObject prefabGO;
			List<TreePrototype> treePrototypes = new List<TreePrototype>();
			for (int i = 0; i < scatterTrees._treePrototypInfos.Count; ++i)
			{
				prefabGO = HEU_AssetDatabase.LoadAssetAtPath(scatterTrees._treePrototypInfos[i]._prefabPath, typeof(GameObject)) as GameObject;
				if (prefabGO != null)
				{
					TreePrototype prototype = new TreePrototype();
					prototype.prefab = prefabGO;
					prototype.bendFactor = scatterTrees._treePrototypInfos[i]._bendfactor;
					treePrototypes.Add(prototype);

					//Debug.LogFormat("Added Tree Prototype: {0} - {1}", scatterTrees._treePrototypInfos[i]._prefabPath, scatterTrees._treePrototypInfos[i]._bendfactor);
				}
			}
			terrainData.treePrototypes = treePrototypes.ToArray();
			terrainData.RefreshPrototypes();

			if (scatterTrees._positions != null && scatterTrees._positions.Length > 0
				&& scatterTrees._prototypeIndices != null && scatterTrees._prototypeIndices.Length == scatterTrees._positions.Length)
			{
				TreeInstance[] treeInstances = new TreeInstance[scatterTrees._positions.Length];

				for (int i = 0; i < scatterTrees._positions.Length; ++i)
				{
					treeInstances[i] = new TreeInstance();
					treeInstances[i].color = scatterTrees._colors != null ? scatterTrees._colors[i] : new Color32(255, 255, 255, 255);
					treeInstances[i].heightScale = scatterTrees._heightScales != null ? scatterTrees._heightScales[i] : 1f;
					treeInstances[i].lightmapColor = scatterTrees._lightmapColors != null ? scatterTrees._lightmapColors[i] : new Color32(255, 255, 255, 255);
					treeInstances[i].position = scatterTrees._positions[i];
					treeInstances[i].prototypeIndex = scatterTrees._prototypeIndices[i];
					treeInstances[i].rotation = scatterTrees._rotations[i];
					treeInstances[i].widthScale = scatterTrees._widthScales != null ? scatterTrees._widthScales[i] : 1f;
				}

				terrainData.SetTreeInstances(treeInstances, true);
			}
#endif
		}
		public static Material LoadUnityMaterial(string materialPath)
		{
			if(materialPath.StartsWith(HEU_Defines.DEFAULT_UNITY_BUILTIN_RESOURCES))
			{
				return HEU_AssetDatabase.LoadUnityAssetFromUniqueAssetPath<Material>(materialPath);
			}
			else if (materialPath.StartsWith("Packages/"))
			{
				return HEU_AssetDatabase.LoadAssetAtPath(materialPath, typeof(Material)) as Material;
			}

			string relativePath = materialPath;
			if (relativePath.StartsWith(Application.dataPath))
			{
				// If absolute path, change to relative path
				relativePath = HEU_AssetDatabase.GetAssetRelativePath(materialPath);
			}

			Material material = null;

			string mainPath = null;
			string subPath = null;
			HEU_AssetDatabase.GetSubAssetPathFromPath(relativePath, out mainPath, out subPath);
			if(subPath != null)
			{
				// This is a subasset. Need to find it by first loading the main asset.
				Object subObject = HEU_AssetDatabase.LoadSubAssetAtPath(mainPath, subPath);
				if(subObject != null)
				{
					material = subObject as Material;
				}
			}
			else
			{
				// Try loading from Resources first
				material = Resources.Load<Material>(relativePath) as Material;
				if (material == null)
				{
					// If not in Resources, try loading from project
					HEU_AssetDatabase.ImportAsset(relativePath, HEU_AssetDatabase.HEU_ImportAssetOptions.Default);
					material = HEU_AssetDatabase.LoadAssetAtPath(relativePath, typeof(Material)) as Material;
				}
			}

			return material;
		}
		public static Texture2D ExtractHoudiniImageToTextureFile(HEU_SessionBase session, HAPI_MaterialInfo materialInfo, string imagePlanes, string assetCacheFolderPath)
		{
			Texture2D textureResult = null;

			// Get the Textures folder in the assetCacheFolderPath. Make sure it exists.
			assetCacheFolderPath = HEU_AssetDatabase.AppendTexturesPathToAssetFolder(assetCacheFolderPath);
			HEU_AssetDatabase.CreatePathWithFolders(assetCacheFolderPath);

			// Need to pass in full path to Houdini to write out the file
			assetCacheFolderPath = HEU_AssetDatabase.GetAssetFullPath(assetCacheFolderPath);
			if (assetCacheFolderPath == null)
			{
				return textureResult;
			}

			HAPI_ImageInfo imageInfo = new HAPI_ImageInfo();
			if (!session.GetImageInfo(materialInfo.nodeId, ref imageInfo))
			{
				return textureResult;
			}

			// This will return null if the current imageInfo file format is supported by Unity, otherwise
			// returns a Unity supported file format.
			string desiredFileFormatName = HEU_MaterialData.GetSupportedFileFormat(session, ref imageInfo);

			// Extract image to file
			string writtenFilePath = null;
			if (!session.ExtractImageToFile(materialInfo.nodeId, desiredFileFormatName, imagePlanes, assetCacheFolderPath, out writtenFilePath))
			{
				return textureResult;
			}
			

			HEU_AssetDatabase.SaveAndRefreshDatabase();

			// Convert full path back to relative in order to work with AssetDatabase
			string assetRelativePath = HEU_AssetDatabase.GetAssetRelativePath(writtenFilePath);

			// Re-import to refresh the project
			HEU_AssetDatabase.ImportAsset(assetRelativePath, HEU_AssetDatabase.HEU_ImportAssetOptions.Default);

			textureResult = HEU_AssetDatabase.LoadAssetAtPath(assetRelativePath, typeof(Texture2D)) as Texture2D;
			//Debug.LogFormat("Loaded texture to file {0} with format {1}", writtenFilePath, textureResult != null ? textureResult.format.ToString() : "none");

			return textureResult;
		}
Exemple #7
0
		public static Material LoadUnityMaterial(string materialPath)
		{
			if(materialPath.StartsWith(HEU_Defines.DEFAULT_UNITY_BUILTIN_RESOURCES))
			{
				return HEU_AssetDatabase.LoadUnityAssetFromUniqueAssetPath<Material>(materialPath);
			}

			string relativePath = materialPath;
			if (relativePath.StartsWith(Application.dataPath))
			{
				// If absolute path, change to relative path
				relativePath = HEU_AssetDatabase.GetAssetRelativePath(materialPath);
			}

			// Try loading from Resources first
			Material material = Resources.Load<Material>(relativePath) as Material;
			if(material == null)
			{
				// If not in Resources, try loading from project
				HEU_AssetDatabase.ImportAsset(relativePath, HEU_AssetDatabase.HEU_ImportAssetOptions.Default);
				material = HEU_AssetDatabase.LoadAssetAtPath(relativePath, typeof(Material)) as Material;
			}
			return material;
		}
	public void LoadPreset(HEU_SessionBase session, HEU_InputPreset inputPreset)
	{
	    ResetInputNode(session);

	    ChangeInputType(session, inputPreset._inputObjectType);

	    if (inputPreset._inputObjectType == InputObjectType.UNITY_MESH)
	    {
		bool bSet = false;
		int numObjects = inputPreset._inputObjectPresets.Count;
		for (int i = 0; i < numObjects; ++i)
		{
		    bSet = false;

		    if (!string.IsNullOrEmpty(inputPreset._inputObjectPresets[i]._gameObjectName))
		    {
			GameObject inputGO = null;
			if (inputPreset._inputObjectPresets[i]._isSceneObject)
			{
			    inputGO = HEU_GeneralUtility.GetGameObjectByNameInScene(inputPreset._inputObjectPresets[i]._gameObjectName);
			}
			else
			{
			    // Use the _gameObjectName as path to find in scene
			    inputGO = HEU_AssetDatabase.LoadAssetAtPath(inputPreset._inputObjectPresets[i]._gameObjectName, typeof(GameObject)) as GameObject;
			    if (inputGO == null)
			    {
				Debug.LogErrorFormat("Unable to find input at {0}", inputPreset._inputObjectPresets[i]._gameObjectName);
			    }
			}

			if (inputGO != null)
			{
			    HEU_InputObjectInfo inputObject = InternalAddInputObjectAtEnd(inputGO);
			    bSet = true;

			    inputObject._useTransformOffset = inputPreset._inputObjectPresets[i]._useTransformOffset;
			    inputObject._translateOffset = inputPreset._inputObjectPresets[i]._translateOffset;
			    inputObject._rotateOffset = inputPreset._inputObjectPresets[i]._rotateOffset;
			    inputObject._scaleOffset = inputPreset._inputObjectPresets[i]._scaleOffset;
			}
			else
			{
			    Debug.LogWarningFormat("Gameobject with name {0} not found. Unable to set input object.", inputPreset._inputAssetName);
			}
		    }

		    if (!bSet)
		    {
			// Add dummy spot (user can replace it manually)
			InternalAddInputObjectAtEnd(null);
		    }
		}
	    }
	    else if (inputPreset._inputObjectType == HEU_InputNode.InputObjectType.HDA)
	    {
		bool bSet = false;
		int numInptus = inputPreset._inputAssetPresets.Count;
		for (int i = 0; i < numInptus; ++i)
		{
		    bSet = false;
		    if (!string.IsNullOrEmpty(inputPreset._inputAssetPresets[i]._gameObjectName))
		    {
			bSet = FindAddToInputHDA(inputPreset._inputAssetPresets[i]._gameObjectName);
		    }

		    if (!bSet)
		    {
			// Couldn't add for some reason, so just add dummy spot (user can replace it manually)
			InternalAddInputHDAAtEnd(null);
		    }
		}

		if (numInptus == 0 && !string.IsNullOrEmpty(inputPreset._inputAssetName))
		{
		    // Old preset. Add it to input
		    FindAddToInputHDA(inputPreset._inputAssetName);
		}
	    }

	    KeepWorldTransform = inputPreset._keepWorldTransform;
	    PackGeometryBeforeMerging = inputPreset._packGeometryBeforeMerging;

	    RequiresUpload = true;

	    ClearUICache();
	}
		public void GenerateTerrainWithAlphamaps(HEU_SessionBase session, HEU_HoudiniAsset houdiniAsset, bool bRebuild)
		{
			if(_layers == null || _layers.Count == 0)
			{
				Debug.LogError("Unable to generate terrain due to lack of heightfield layers!");
				return;
			}

			HEU_VolumeLayer heightLayer = _layers[0];

			HAPI_VolumeInfo heightVolumeInfo = new HAPI_VolumeInfo();
			bool bResult = session.GetVolumeInfo(_ownerNode.GeoID, heightLayer._part.PartID, ref heightVolumeInfo);
			if (!bResult)
			{
				Debug.LogErrorFormat("Unable to get volume info for height layer: {0}!", heightLayer._layerName);
				return;
			}

			// Special handling of volume cache presets. It is applied here (if exists) because it might pertain to TerrainData that exists
			// in the AssetDatabase. If we don't apply here but rather create a new one, the existing file will get overwritten.
			// Applying the preset here for terrain ensures the TerrainData is reused.
			// Get the volume preset for this part
			HEU_VolumeCachePreset volumeCachePreset = houdiniAsset.GetVolumeCachePreset(_ownerNode.ObjectNode.ObjectName, _ownerNode.GeoName, TileIndex);
			if (volumeCachePreset != null)
			{
				ApplyPreset(volumeCachePreset);

				// Remove it so that it doesn't get applied when doing the recook step
				houdiniAsset.RemoveVolumeCachePreset(volumeCachePreset);
			}

			// The TerrainData and TerrainLayer files needs to be saved out if we create them. This creates the relative folder
			// path from the Asset's cache folder: {assetCache}/{geo name}/Terrain/Tile{tileIndex}/...
			string relativeFolderPath = HEU_Platform.BuildPath(_ownerNode.GeoName, HEU_Defines.HEU_FOLDER_TERRAIN, HEU_Defines.HEU_FOLDER_TILE + TileIndex);

			if (bRebuild)
			{
				// For full rebuild, re-create the TerrainData instead of using previous
				_terrainData = null;
			}

			//Debug.Log("Generating Terrain with AlphaMaps: " + (_terrainData != null ? _terrainData.name : "NONE"));
			TerrainData terrainData = _terrainData;
			Vector3 terrainOffsetPosition = Vector3.zero;

			// Look up TerrainData file via attribute if user has set it
			string terrainDataFile = HEU_GeneralUtility.GetAttributeStringValueSingle(session, _ownerNode.GeoID, heightLayer._part.PartID,
				HEU_Defines.DEFAULT_UNITY_HEIGHTFIELD_TERRAINDATA_FILE_ATTR, HAPI_AttributeOwner.HAPI_ATTROWNER_PRIM);
			if (!string.IsNullOrEmpty(terrainDataFile))
			{
				TerrainData loadedTerrainData = HEU_AssetDatabase.LoadAssetAtPath(terrainDataFile, typeof(TerrainData)) as TerrainData;
				if (loadedTerrainData == null)
				{
					Debug.LogWarningFormat("TerrainData, set via attribute, not found at: {0}", terrainDataFile);
				}
				else
				{
					// In the case that the specified TerrainData belongs to another Terrain (i.e. input Terrain), 
					// make a copy of it and store it in our cache. Note that this overwrites existing TerrainData in our cache
					// because the workflow is such that attributes will always override local setting.
					string bakedTerrainPath = houdiniAsset.GetValidAssetCacheFolderPath();
					bakedTerrainPath = HEU_Platform.BuildPath(bakedTerrainPath, relativeFolderPath);
					terrainData = HEU_AssetDatabase.CopyAndLoadAssetAtAnyPath(loadedTerrainData, bakedTerrainPath, typeof(TerrainData), true) as TerrainData;
					if (terrainData == null)
					{
						Debug.LogErrorFormat("Unable to copy TerrainData from {0} for generating Terrain.", terrainDataFile);
					}
				}
			}

			// Generate the terrain and terrain data from the height layer. This applies height values.
			bResult = HEU_TerrainUtility.GenerateTerrainFromVolume(session, ref heightVolumeInfo, heightLayer._part.ParentGeoNode.GeoID,
				heightLayer._part.PartID, heightLayer._part.OutputGameObject, ref terrainData, out terrainOffsetPosition);
			if (!bResult || terrainData == null)
			{
				return;
			}

			if (_terrainData != terrainData)
			{
				_terrainData = terrainData;
				heightLayer._part.SetTerrainData(terrainData, relativeFolderPath);
			}

			heightLayer._part.SetTerrainOffsetPosition(terrainOffsetPosition);

			int terrainSize = terrainData.heightmapResolution;

			// Now process TerrainLayers and alpha maps

			// First, preprocess all layers to get heightfield arrays, converted to proper size
			List<float[]> heightFields = new List<float[]>();
			// Corresponding list of HF volume layers to process as splatmaps
			List<HEU_VolumeLayer> volumeLayersToProcess = new List<HEU_VolumeLayer>();

			int numLayers = _layers.Count;
			float minHeight = 0;
			float maxHeight = 0;
			float  heightRange = 0;
			// This skips the height layer, and processes all other layers.
			// Note that mask shouldn't be part of _layers at this point.
			for(int i = 1; i < numLayers; ++i)
			{
				float[] normalizedHF = HEU_TerrainUtility.GetNormalizedHeightmapFromPartWithMinMax(session, _ownerNode.GeoID, _layers[i]._part.PartID, 
					_layers[i]._xLength, _layers[i]._yLength, ref minHeight, ref maxHeight, ref heightRange);
				if (normalizedHF != null && normalizedHF.Length > 0)
				{
					heightFields.Add(normalizedHF);
					volumeLayersToProcess.Add(_layers[i]);
				}
			}

			int numVolumeLayers = volumeLayersToProcess.Count;

			HAPI_NodeId geoID;
			HAPI_PartId partID;

			Texture2D defaultTexture = LoadDefaultSplatTexture();

#if UNITY_2018_3_OR_NEWER

			// Create or update the terrain layers based on heightfield layers.

			// 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);

			// This holds the alpha map indices for each layer that will be added to the TerrainData.
			// The alpha maps could be a mix of existing and new values, so need to know which to use
			// Initially set to use existing alpha maps, then override later on if specified via HF layers
			List<int> alphaMapIndices = new List<int>();
			for (int a = 0; a < existingTerrainLayers.Length; ++a)
			{
				// Negative indices for existing alpha map (offset by -1)
				alphaMapIndices.Add(-a - 1);
			}

			bool bNewTerrainLayer = false;
			HEU_VolumeLayer layer = null;
			TerrainLayer terrainLayer = null;
			bool bSetTerrainLayerProperties = true;
			for (int m = 0; m < numVolumeLayers; ++m)
			{
				bNewTerrainLayer = false;
				bSetTerrainLayerProperties = true;

				layer = volumeLayersToProcess[m];

				geoID = _ownerNode.GeoID;
				partID = layer._part.PartID;

				terrainLayer = null;

				int terrainLayerIndex = -1;

				// The TerrainLayer attribute overrides existing TerrainLayer. So if its set, load and use it.
				string terrainLayerFile = HEU_GeneralUtility.GetAttributeStringValueSingle(session, geoID, partID,
						HEU_Defines.DEFAULT_UNITY_HEIGHTFIELD_TERRAINLAYER_FILE_ATTR, HAPI_AttributeOwner.HAPI_ATTROWNER_PRIM);
				if (!string.IsNullOrEmpty(terrainLayerFile))
				{
					terrainLayer = HEU_AssetDatabase.LoadAssetAtPath(terrainLayerFile, typeof(TerrainLayer)) as TerrainLayer;
					if (terrainLayer == null)
					{
						Debug.LogWarningFormat("TerrainLayer, set via attribute, not found at: {0}", terrainLayerFile);
						// Not earlying out or skipping this layer due to error because we want to keep proper indexing
						// by creating a new TerrainLayer.
					}
					else
					{
						// TerrainLayer loaded from attribute. 
						// It could be an existing TerrainLayer that is already part of finalTerrainLayers 
						// or could be a new one which needs to be added.

						// If its a different TerrainLayer than existing, update the finalTerrainLayers, and index.
						if (layer._terrainLayer != null && layer._terrainLayer != terrainLayer)
						{
							terrainLayerIndex = HEU_TerrainUtility.GetTerrainLayerIndex(layer._terrainLayer, existingTerrainLayers);
							if (terrainLayerIndex >= 0)
							{
								finalTerrainLayers[terrainLayerIndex] = terrainLayer;
							}
						}

						if (terrainLayerIndex == -1)
						{
							// Always check if its part of existing list so as not to add it again
							terrainLayerIndex = HEU_TerrainUtility.GetTerrainLayerIndex(terrainLayer, existingTerrainLayers);
						}
					}
				}

				// No terrain layer specified, so try using existing if we have it
				if (terrainLayer == null)
				{
					terrainLayerIndex = HEU_TerrainUtility.GetTerrainLayerIndex(layer._terrainLayer, existingTerrainLayers);
					if (terrainLayerIndex >= 0)
					{
						// Note the terrainLayerIndex is same for finalTerrainLayers as existingTerrainLayers
						terrainLayer = existingTerrainLayers[terrainLayerIndex];
					}
				}

				// Still not found, so just create a new one
				if (terrainLayer == null)
				{
					terrainLayer = new TerrainLayer();
					terrainLayer.name = layer._layerName;
					//Debug.LogFormat("Created new TerrainLayer with name: {0} ", terrainLayer.name);
					bNewTerrainLayer = true;
				}

				if (terrainLayerIndex == -1)
				{
					// Adding to the finalTerrainLayers if this is indeed a newly created or loaded TerrainLayer
					// (i.e. isn't already part of the TerrainLayers for this Terrain).
					// Save this layer's index for later on if we make a copy.
					terrainLayerIndex = finalTerrainLayers.Count;
					finalTerrainLayers.Add(terrainLayer);

					// Positive index for alpha map from heightfield (starting at 1)
					alphaMapIndices.Add(m + 1);
				}
				else
				{
					// Positive index for alpha map from heightfield (starting at 1)
					alphaMapIndices[terrainLayerIndex] = m + 1;
				}

				// 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 (!bNewTerrainLayer && layer._hasLayerAttributes)
				{
					string bakedTerrainPath = houdiniAsset.GetValidAssetCacheFolderPath();
					bakedTerrainPath = HEU_Platform.BuildPath(bakedTerrainPath, relativeFolderPath);
					TerrainLayer prevTerrainLayer = terrainLayer;
					terrainLayer = HEU_AssetDatabase.CopyAndLoadAssetAtAnyPath(terrainLayer, bakedTerrainPath, typeof(TerrainLayer), true) as TerrainLayer;
					if (terrainLayer != null)
					{
						// Update the TerrainLayer reference in the list with this copy
						finalTerrainLayers[terrainLayerIndex] = 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.
					}
				}

				// Now override layer properties if they have been set via attributes
				if (bSetTerrainLayerProperties)
				{
					LoadLayerPropertiesFromAttributes(session, geoID, partID, terrainLayer, bNewTerrainLayer, defaultTexture);
				}

				if (bNewTerrainLayer)
				{
					// In order to retain the new TerrainLayer, it must be saved to the AssetDatabase.
					Object savedObject = null;
					string layerFileNameWithExt = terrainLayer.name;
					if (!layerFileNameWithExt.EndsWith(HEU_Defines.HEU_EXT_TERRAINLAYER))
					{
						layerFileNameWithExt += HEU_Defines.HEU_EXT_TERRAINLAYER;
					}
					houdiniAsset.AddToAssetDBCache(layerFileNameWithExt, terrainLayer, relativeFolderPath, ref savedObject);
				}

				// Store reference
				layer._terrainLayer = terrainLayer;
			}

			// Get existing alpha maps so we can reuse the values if needed
			float[,,] existingAlphaMaps = terrainData.GetAlphamaps(0, 0, terrainData.alphamapWidth, terrainData.alphamapHeight);

			terrainData.terrainLayers = finalTerrainLayers.ToArray();

			int numTotalAlphaMaps = finalTerrainLayers.Count;

#else
			// Create or update the SplatPrototype based on heightfield layers.

			// Need to create or reuse SplatPrototype for each layer in heightfield, representing the textures.
			SplatPrototype[] existingSplats = terrainData.splatPrototypes;

			// A full rebuild clears out existing splats, but a regular cook keeps them.
			List<SplatPrototype> finalSplats = new List<SplatPrototype>(existingSplats);

			// This holds the alpha map indices for each layer that will be added to the TerrainData
			// The alpha maps could be a mix of existing and new values, so need to know which to use
			List<int> alphaMapIndices = new List<int>();

			// Initially set to use existing alpha maps, then override later on if specified via HF layers.
			for (int a = 0; a < existingSplats.Length; ++a)
			{
				// Negative indices for existing alpha map (offset by -1)
				alphaMapIndices.Add(-a - 1);
			}

			bool bNewSplat = false;
			HEU_VolumeLayer layer = null;
			SplatPrototype splatPrototype = null;

			for (int m = 0; m < numVolumeLayers; ++m)
			{
				bNewSplat = false;

				layer = volumeLayersToProcess[m];

				geoID = _ownerNode.GeoID;
				partID = layer._part.PartID;

				// Try to find existing SplatPrototype for reuse. But not for full rebuild.
				splatPrototype = null;
				if (layer._splatPrototypeIndex >= 0 && layer._splatPrototypeIndex < existingSplats.Length)
				{
					splatPrototype = existingSplats[layer._splatPrototypeIndex];

					// Positive index for alpha map from heightfield (starting at 1)
					alphaMapIndices[layer._splatPrototypeIndex] = m + 1;
				}

				if (splatPrototype == null)
				{
					splatPrototype = new SplatPrototype();
					layer._splatPrototypeIndex = finalSplats.Count;
					finalSplats.Add(splatPrototype);

					// Positive index for alpha map from heightfield (starting at 1)
					alphaMapIndices.Add(m + 1);
				}

				// Now override splat properties if they have been set via attributes
				LoadLayerPropertiesFromAttributes(session, geoID, partID, splatPrototype, bNewSplat, defaultTexture);
			}

			// On regular cook, get existing alpha maps so we can reuse the values if needed.
			float[,,] existingAlphaMaps = terrainData.GetAlphamaps(0, 0, terrainData.alphamapWidth, terrainData.alphamapHeight);

			terrainData.splatPrototypes = finalSplats.ToArray();

			int numTotalAlphaMaps = finalSplats.Count;
#endif

			// Set alpha maps by combining with existing alpha maps, and appending new heightfields

			float[,,] alphamap = null;
			if (numTotalAlphaMaps > 0 && volumeLayersToProcess.Count > 0)
			{
				// Convert the heightfields into alpha maps with layer strengths
				float[] strengths = new float[volumeLayersToProcess.Count];
				for (int m = 0; m < volumeLayersToProcess.Count; ++m)
				{
					strengths[m] = volumeLayersToProcess[m]._strength;
				}

				alphamap = HEU_TerrainUtility.AppendConvertedHeightFieldToAlphaMap(
					volumeLayersToProcess[0]._xLength, volumeLayersToProcess[0]._yLength, existingAlphaMaps,
					heightFields, strengths, alphaMapIndices);

				// Update the alphamap resolution to the actual size of the first 
				// heightfield layer used for the alphamaps.
				// Setting the size before setting the alphamas applies proper scaling.
				int alphamapResolution = volumeLayersToProcess[0]._xLength;
				terrainData.alphamapResolution = alphamapResolution;

				terrainData.SetAlphamaps(0, 0, alphamap);
			}

			// Tree instances for scattering
			HEU_TerrainUtility.ApplyScatter(terrainData, _scatterTrees);

			// If the layers were writen out, this saves the asset DB. Otherwise user has to save it themselves.
			// Not 100% sure this is needed, but without this the editor doesn't know the terrain asset has been updated
			// and therefore doesn't import and show the terrain layer.
			HEU_AssetDatabase.SaveAssetDatabase();
		}
Exemple #10
0
		private void GenerateInstancesFromAssetPaths(HEU_LoadBufferInstancer instancerBuffer, Transform instanceRootTransform)
	{
			// For single asset, this is set when its impoted
			GameObject singleAssetGO = null;

			// For multi assets, keep track of loaded objects so we only need to load once for each object
			Dictionary<string, GameObject> loadedUnityObjectMap = new Dictionary<string, GameObject>();

			// Temporary empty gameobject in case the specified Unity asset is not found
			GameObject tempGO = null;

			if (instancerBuffer._assetPaths.Length == 1)
			{
				// Single asset path
				if (!string.IsNullOrEmpty(instancerBuffer._assetPaths[0]))
				{
					HEU_AssetDatabase.ImportAsset(instancerBuffer._assetPaths[0], HEU_AssetDatabase.HEU_ImportAssetOptions.Default);
					singleAssetGO = HEU_AssetDatabase.LoadAssetAtPath(instancerBuffer._assetPaths[0], typeof(GameObject)) as GameObject;
				}

				if (singleAssetGO == null)
				{
					Debug.LogErrorFormat("Asset at path {0} not found. Unable to create instances for {1}.", instancerBuffer._assetPaths[0], instancerBuffer._name);
					return;
				}
			}

			int numInstancesCreated = 0;
			int numInstances = instancerBuffer._instanceTransforms.Length;
			for (int i = 0; i < numInstances; ++i)
			{
				// Reset to the single asset for each instance allows which is null if using multi asset
				// therefore forcing the instance asset to be found
				GameObject unitySrcGO = singleAssetGO;

				if (unitySrcGO == null)
				{
					// If not using single asset, then there must be an asset path for each instance

					if (string.IsNullOrEmpty(instancerBuffer._assetPaths[i]))
					{
						continue;
					}

					if (!loadedUnityObjectMap.TryGetValue(instancerBuffer._assetPaths[i], out unitySrcGO))
					{
						// Try loading it
						//HEU_AssetDatabase.ImportAsset(instancerBuffer._assetPaths[i], HEU_AssetDatabase.HEU_ImportAssetOptions.Default);
						unitySrcGO = HEU_AssetDatabase.LoadAssetAtPath(instancerBuffer._assetPaths[i], typeof(GameObject)) as GameObject;

						if (unitySrcGO == null)
						{
							Debug.LogErrorFormat("Unable to load asset at {0} for instancing!", instancerBuffer._assetPaths[i]);

							// Even though the source Unity object is not found, we should create an object instance info to track it
							if (tempGO == null)
							{
								tempGO = new GameObject();
							}
							unitySrcGO = tempGO;
						}

						// Adding to map even if not found so we don't flood the log with the same error message
						loadedUnityObjectMap.Add(instancerBuffer._assetPaths[i], unitySrcGO);
					}
				}

				CreateNewInstanceFromObject(unitySrcGO, (numInstancesCreated + 1), instanceRootTransform, ref instancerBuffer._instanceTransforms[i],
					instancerBuffer._instancePrefixes, instancerBuffer._name);

				numInstancesCreated++;
			}

			if (tempGO != null)
			{
				HEU_GeneralUtility.DestroyImmediate(tempGO, bRegisterUndo: false);
			}
		}
Exemple #11
0
		private void GenerateTerrain(List<HEU_LoadBufferVolume> terrainBuffers)
		{
			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);
					Transform newTransform = newGameObject.transform;
					newTransform.parent = parent;

					HEU_GeneratedOutput generatedOutput = new HEU_GeneratedOutput();
					generatedOutput._outputData._gameObject = newGameObject;

					Terrain terrain = HEU_GeneralUtility.GetOrCreateComponent<Terrain>(newGameObject);
					TerrainCollider collider = HEU_GeneralUtility.GetOrCreateComponent<TerrainCollider>(newGameObject);

					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);
						}

						terrain.terrainData = HEU_AssetDatabase.CopyUniqueAndLoadAssetAtAnyPath(sourceTerrainData, outputTerrainpath, 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();
					}
					TerrainData terrainData = terrain.terrainData;
					collider.terrainData = terrainData;

					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 && terrainLayerIndex >= 0)
								{
									// Copy the TerrainLayer file
									TerrainLayer prevTerrainLayer = terrainlayer;
									terrainlayer = HEU_AssetDatabase.CopyAndLoadAssetAtAnyPath(terrainlayer, outputTerrainpath, typeof(TerrainLayer), true) as TerrainLayer;
									if (terrainlayer != null)
									{
										// Update the TerrainLayer reference in the list with this copy
										finalTerrainLayers[terrainLayerIndex] = 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.
									}
								}
							}

							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]);
				}
			}
		}
		private void GenerateTerrain(List<HEU_LoadBufferVolume> terrainBuffers)
		{
			Transform parent = this.gameObject.transform;

			int numVolumes = terrainBuffers.Count;
			for(int t = 0; t < numVolumes; ++t)
			{
				if (terrainBuffers[t]._heightMap != null)
				{
					GameObject newGameObject = new GameObject("heightfield_" + terrainBuffers[t]._tileIndex);
					Transform newTransform = newGameObject.transform;
					newTransform.parent = parent;

					HEU_GeneratedOutput generatedOutput = new HEU_GeneratedOutput();
					generatedOutput._outputData._gameObject = newGameObject;

					Terrain terrain = HEU_GeneralUtility.GetOrCreateComponent<Terrain>(newGameObject);
					TerrainCollider collider = HEU_GeneralUtility.GetOrCreateComponent<TerrainCollider>(newGameObject);

					if (!string.IsNullOrEmpty(terrainBuffers[t]._terrainDataPath))
					{
						terrain.terrainData = HEU_AssetDatabase.LoadAssetAtPath(terrainBuffers[t]._terrainDataPath, typeof(TerrainData)) as TerrainData;
						if (terrain.terrainData == null)
						{
							Debug.LogWarningFormat("TerrainData, set via attribute, not found at: {0}", terrainBuffers[t]._terrainDataPath);
						}
					}

					if (terrain.terrainData == null)
					{
						terrain.terrainData = new TerrainData();
					}
					TerrainData terrainData = terrain.terrainData;
					collider.terrainData = terrainData;

					HEU_TerrainUtility.SetTerrainMaterial(terrain);

#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]._layers.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)
					{
						TerrainLayer[] terrainLayers = new TerrainLayer[numLayers - 1];
						for (int m = 1; m < numLayers; ++m)
						{
							TerrainLayer terrainlayer = null;

							HEU_LoadBufferVolumeLayer layer = terrainBuffers[t]._layers[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;
								}
							}

							if (terrainlayer == null)
							{
								terrainlayer = new TerrainLayer();
							}

							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;

							// Note index is m - 1 due to skipping height layer
							terrainLayers[m - 1] = terrainlayer;
						}
						terrainData.terrainLayers = terrainLayers;
					}

#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]._layers[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]._layers[1]._heightMapWidth;
						}
						terrainData.alphamapResolution = alphamapResolution;

						terrainData.SetAlphamaps(0, 0, terrainBuffers[t]._splatMaps);
					}

					// Set the tree scattering
					if (terrainBuffers[t]._scatterTrees != null)
					{
						HEU_TerrainUtility.ApplyScatter(terrainData, terrainBuffers[t]._scatterTrees);
					}

					terrainBuffers[t]._generatedOutput = generatedOutput;
					_generatedOutputs.Add(generatedOutput);

					SetOutputVisiblity(terrainBuffers[t]);
				}
			}
		}
		/// <summary>
		/// Apply the given detail layers and properties to the given terrain.
		/// The detail distance and resolution will be set, along with detail prototypes, and layers.
		/// </summary>
		/// <param name="terrain">The Terrain to set the detail properies on</param>
		/// <param name="terrainData">The TerrainData to apply the layers to</param>
		/// <param name="detailProperties">Container for detail distance and resolution</param>
		/// <param name="heuDetailPrototypes">Data for creating DetailPrototypes</param>
		/// <param name="convertedDetailMaps">The detail maps to set for the detail layers</param>
		public static void ApplyDetailLayers(Terrain terrain, TerrainData terrainData, HEU_DetailProperties detailProperties,
			List<HEU_DetailPrototype> heuDetailPrototypes, List<int[,]> convertedDetailMaps)
		{
#if UNITY_2018_3_OR_NEWER

			if (detailProperties != null)
			{
				if (detailProperties._detailDistance >= 0)
				{
					terrain.detailObjectDistance = detailProperties._detailDistance;
				}

				if (detailProperties._detailDensity >= 0)
				{
					terrain.detailObjectDensity = detailProperties._detailDensity;
				}

				int resPerPath = detailProperties._detailResolutionPerPatch > 0 ?
						detailProperties._detailResolutionPerPatch : terrainData.detailResolutionPerPatch;

				int detailRes = detailProperties._detailResolution > 0 ?
					detailProperties._detailResolution : terrainData.detailResolutionPerPatch;

				if (resPerPath > 0 && detailRes > 0)
				{
					// This should match with half the terrain size
					terrainData.SetDetailResolution(detailRes, resPerPath);
				}
			}

			if (heuDetailPrototypes.Count != convertedDetailMaps.Count)
			{
				Debug.LogError("Number of volume detail layers differs from converted detail maps. Unable to apply detail layers.");
				return;
			}

			// For now, just override existing detail prototypes and layers
			// If user asks for appending/overwriting them, then can use a new index attribute to map them

			List<DetailPrototype> detailPrototypes = new List<DetailPrototype>();

			int numDetailLayers = heuDetailPrototypes.Count;
			for(int i = 0; i < numDetailLayers; ++i)
			{
				DetailPrototype detailPrototype = new DetailPrototype();

				HEU_DetailPrototype heuDetail = heuDetailPrototypes[i];

				if (!string.IsNullOrEmpty(heuDetail._prototypePrefab))
				{
					detailPrototype.prototype = HEU_AssetDatabase.LoadAssetAtPath(heuDetail._prototypePrefab, typeof(GameObject)) as GameObject;
					detailPrototype.usePrototypeMesh = true;
				}
				else if (!string.IsNullOrEmpty(heuDetail._prototypeTexture))
				{
					detailPrototype.prototypeTexture = HEU_MaterialFactory.LoadTexture(heuDetail._prototypeTexture);
					detailPrototype.usePrototypeMesh = false;
				}

				detailPrototype.bendFactor = heuDetail._bendFactor;
				detailPrototype.dryColor = heuDetail._dryColor;
				detailPrototype.healthyColor = heuDetail._healthyColor;
				detailPrototype.maxHeight = heuDetail._maxHeight;
				detailPrototype.maxWidth = heuDetail._maxWidth;
				detailPrototype.minHeight = heuDetail._minHeight;
				detailPrototype.minWidth = heuDetail._minWidth;
				detailPrototype.noiseSpread = heuDetail._noiseSpread;

				detailPrototype.renderMode = (DetailRenderMode)heuDetail._renderMode;

				detailPrototypes.Add(detailPrototype);
			}

			// Set the DetailPrototypes

			if (detailPrototypes.Count > 0)
			{
				terrainData.detailPrototypes = detailPrototypes.ToArray();
			}

			// Set the DetailLayers
			for(int i = 0; i < numDetailLayers; ++i)
			{
				terrainData.SetDetailLayer(0, 0, i, convertedDetailMaps[i]);
			}
#endif
		}
Exemple #14
0
		public void LoadPreset(HEU_SessionBase session, HEU_InputPreset inputPreset)
		{
			ResetInputNode(session);

			ChangeInputType(session, inputPreset._inputObjectType);

			if (inputPreset._inputObjectType == HEU_InputNode.InputObjectType.UNITY_MESH)
			{
				int numObjects = inputPreset._inputObjectPresets.Count;
				for (int i = 0; i < numObjects; ++i)
				{
					if (!string.IsNullOrEmpty(inputPreset._inputObjectPresets[i]._gameObjectName))
					{
						GameObject inputGO = null;
						if (inputPreset._inputObjectPresets[i]._isSceneObject)
						{
							inputGO = HEU_GeneralUtility.GetGameObjectByNameInScene(inputPreset._inputObjectPresets[i]._gameObjectName);
						}
						else
						{
							// Use the _gameObjectName as path to find in scene
							inputGO = HEU_AssetDatabase.LoadAssetAtPath(inputPreset._inputObjectPresets[i]._gameObjectName, typeof(GameObject)) as GameObject;
							if(inputGO == null)
							{
								Debug.LogErrorFormat("Unable to find input at {0}", inputPreset._inputObjectPresets[i]._gameObjectName);
							}
						}

						if (inputGO != null)
						{
							HEU_InputObjectInfo inputObject = AddInputObjectAtEnd(inputGO);
							inputObject._useTransformOffset = inputPreset._inputObjectPresets[i]._useTransformOffset;
							inputObject._translateOffset = inputPreset._inputObjectPresets[i]._translateOffset;
							inputObject._rotateOffset = inputPreset._inputObjectPresets[i]._rotateOffset;
							inputObject._scaleOffset = inputPreset._inputObjectPresets[i]._scaleOffset;
						}
						else
						{
							Debug.LogWarningFormat("Gameobject with name {0} not found. Unable to set input object.", inputPreset._inputAssetName);
						}
					}
				}
			}
			else if (inputPreset._inputObjectType == HEU_InputNode.InputObjectType.HDA)
			{
				if (!string.IsNullOrEmpty(inputPreset._inputAssetName))
				{
					GameObject inputAsset = GameObject.Find(inputPreset._inputAssetName);
					if (inputAsset != null)
					{
						HEU_HoudiniAssetRoot inputAssetRoot = inputAsset != null ? inputAsset.GetComponent<HEU_HoudiniAssetRoot>() : null;
						if (inputAssetRoot != null && inputAssetRoot._houdiniAsset != null)
						{
							// Need to reconnect and make sure connected asset is in this session

							_inputAsset = inputAsset;

							if (!inputAssetRoot._houdiniAsset.IsAssetValidInHoudini(session))
							{
								inputAssetRoot._houdiniAsset.RequestCook(true, false, true, true);
							}

							_connectedNodeID = inputAssetRoot._houdiniAsset.AssetID;

							_parentAsset.ConnectToUpstream(inputAssetRoot._houdiniAsset);

							_connectedInputAsset = _inputAsset;
						}
						else
						{
							Debug.LogErrorFormat("Input HDA with name {0} is not a valid asset (missing components). Unable to set input asset.", inputPreset._inputAssetName);
						}
					}
					else
					{
						Debug.LogWarningFormat("Game with name {0} not found. Unable to set input asset.", inputPreset._inputAssetName);
					}
				}
			}

			KeepWorldTransform = inputPreset._keepWorldTransform;
			PackGeometryBeforeMerging = inputPreset._packGeometryBeforeMerging;

			RequiresUpload = true;

			ClearUICache();
		}
        private void GenerateInstancesFromNodeIDs(HAPI_NodeId cookNodeId, HEU_LoadBufferInstancer instancerBuffer, Dictionary <HAPI_NodeId, HEU_LoadBufferBase> idBuffersMap,
                                                  Transform instanceRootTransform)
        {
            // For single collision geo override
            GameObject singleCollisionGO = null;

            // For multi collision geo overrides, keep track of loaded objects
            Dictionary <string, GameObject> loadedCollisionObjectMap = new Dictionary <string, GameObject>();

            if (instancerBuffer._collisionAssetPaths != null && instancerBuffer._collisionAssetPaths.Length == 1)
            {
                // Single collision override
                if (!string.IsNullOrEmpty(instancerBuffer._collisionAssetPaths[0]))
                {
                    HEU_AssetDatabase.ImportAsset(instancerBuffer._collisionAssetPaths[0], HEU_AssetDatabase.HEU_ImportAssetOptions.Default);
                    singleCollisionGO = HEU_AssetDatabase.LoadAssetAtPath(instancerBuffer._collisionAssetPaths[0], typeof(GameObject)) as GameObject;
                }

                if (singleCollisionGO == null)
                {
                    // Continue on but log error
                    Debug.LogErrorFormat("Collision asset at path {0} not found for instance {1}.", instancerBuffer._collisionAssetPaths[0], instancerBuffer._name);
                }
            }

            int numInstances = instancerBuffer._instanceNodeIDs.Length;

            for (int i = 0; i < numInstances; ++i)
            {
                HEU_LoadBufferBase sourceBuffer = null;
                if (!idBuffersMap.TryGetValue(instancerBuffer._instanceNodeIDs[i], out sourceBuffer) || sourceBuffer == null)
                {
                    Debug.LogErrorFormat("Part with id {0} is missing. Unable to setup instancer!", instancerBuffer._instanceNodeIDs[i]);
                    return;
                }

                // If the part we're instancing is itself an instancer, make sure it has generated its instances
                if (sourceBuffer._bInstanced && sourceBuffer._generatedOutput == null)
                {
                    HEU_LoadBufferInstancer sourceBufferInstancer = instancerBuffer as HEU_LoadBufferInstancer;
                    if (sourceBufferInstancer != null)
                    {
                        GenerateInstancer(cookNodeId, sourceBufferInstancer, idBuffersMap);
                    }
                }

                GameObject sourceGameObject = sourceBuffer._generatedOutput._outputData._gameObject;
                if (sourceGameObject == null)
                {
                    Debug.LogErrorFormat("Output gameobject is null for source {0}. Unable to instance for {1}.", sourceBuffer._name, instancerBuffer._name);
                    continue;
                }

                GameObject collisionSrcGO = null;
                if (singleCollisionGO != null)
                {
                    // Single collision geo
                    collisionSrcGO = singleCollisionGO;
                }
                else if (instancerBuffer._collisionAssetPaths != null &&
                         (i < instancerBuffer._collisionAssetPaths.Length) &&
                         !string.IsNullOrEmpty(instancerBuffer._collisionAssetPaths[i]))
                {
                    // Mutliple collision geo (one per instance).
                    if (!loadedCollisionObjectMap.TryGetValue(instancerBuffer._collisionAssetPaths[i], out collisionSrcGO))
                    {
                        collisionSrcGO = HEU_AssetDatabase.LoadAssetAtPath(instancerBuffer._collisionAssetPaths[i], typeof(GameObject)) as GameObject;
                        if (collisionSrcGO == null)
                        {
                            Debug.LogErrorFormat("Unable to load collision asset at {0} for instancing!", instancerBuffer._collisionAssetPaths[i]);
                        }
                        else
                        {
                            loadedCollisionObjectMap.Add(instancerBuffer._collisionAssetPaths[i], collisionSrcGO);
                        }
                    }
                }

                int numTransforms = instancerBuffer._instanceTransforms.Length;
                for (int j = 0; j < numTransforms; ++j)
                {
                    CreateNewInstanceFromObject(sourceGameObject, (j + 1), instanceRootTransform, ref instancerBuffer._instanceTransforms[j],
                                                instancerBuffer._instancePrefixes, instancerBuffer._name, collisionSrcGO);
                }
            }
        }