Example #1
0
        public void DestroyVolumeCache()
        {
            if (_volumeCache != null)
            {
                ParentAsset.RemoveVolumeCache(_volumeCache);

                HEU_GeneralUtility.DestroyImmediate(_volumeCache);
                _volumeCache = null;
            }
        }
 public void OnAfterDeserialize()
 {
     // _volumeCaches replaces _volumeCache, and _volumeCache has been deprecated.
     // This takes care of moving in the old _volumeCache into _volumeCaches.
     if (_volumeCache != null && (_volumeCaches == null || _volumeCaches.Count == 0))
     {
         _volumeCaches = new List <HEU_VolumeCache>();
         _volumeCaches.Add(_volumeCache);
         _volumeCache = null;
     }
 }
Example #3
0
		public void CopyValuesTo(HEU_VolumeCache destCache)
		{
			destCache.UIExpanded = UIExpanded;

			foreach(HEU_VolumeLayer srcLayer in _layers)
			{
				HEU_VolumeLayer destLayer = destCache.GetLayer(srcLayer._layerName);
				if(destLayer != null)
				{
					CopyLayer(srcLayer, destLayer);
				}
			}
		}
		public void CopyValuesTo(HEU_VolumeCache destCache)
		{
			destCache.UIExpanded = UIExpanded;

			destCache._terrainData = Object.Instantiate(_terrainData);

			foreach (HEU_VolumeLayer srcLayer in _layers)
			{
				HEU_VolumeLayer destLayer = destCache.GetLayer(srcLayer._layerName);
				if(destLayer != null)
				{
					CopyLayer(srcLayer, destLayer);
				}
			}
		}
Example #5
0
		public void CopyValuesTo(HEU_VolumeCache destCache)
		{
			destCache.UIExpanded = UIExpanded;

			foreach(HEU_VolumeLayer srcLayer in _layers)
			{
				HEU_VolumeLayer destLayer = destCache.GetLayer(srcLayer._layerName);
				if(destLayer != null)
				{
					destLayer._strength = srcLayer._strength;
					destLayer._splatTexture = srcLayer._splatTexture;
					destLayer._normalTexture = srcLayer._normalTexture;
					destLayer._tileSize = srcLayer._tileSize;
					destLayer._tileOffset = srcLayer._tileOffset;
					destLayer._metallic = srcLayer._metallic;
					destLayer._smoothness = srcLayer._smoothness;
					destLayer._uiExpanded = srcLayer._uiExpanded;
				}
			}
		}
Example #6
0
        public void ProcessVolumeParts(HEU_SessionBase session, List <HEU_PartData> volumeParts)
        {
            int numVolumeParts = volumeParts.Count;

            if (numVolumeParts == 0)
            {
                DestroyVolumeCache();
            }
            else if (_volumeCaches == null)
            {
                _volumeCaches = new List <HEU_VolumeCache>();
            }

            // First update volume caches. Each volume cache represents a set of terrain layers grouped by tile index.
            _volumeCaches = HEU_VolumeCache.UpdateVolumeCachesFromParts(session, this, volumeParts, _volumeCaches);

            // Now generate the terrain for each volume cache
            foreach (HEU_VolumeCache cache in _volumeCaches)
            {
                cache.GenerateTerrainWithAlphamaps(session, ParentAsset);
            }
        }
Example #7
0
        public void ProcessVolumeParts(HEU_SessionBase session, List <HEU_PartData> volumeParts)
        {
            int numVolumeParts = volumeParts.Count;

            if (_volumeCache == null)
            {
                if (numVolumeParts == 0)
                {
                    return;
                }

                _volumeCache = ScriptableObject.CreateInstance <HEU_VolumeCache>();
                _volumeCache.Initialize(this);

                ParentAsset.AddVolumeCache(_volumeCache);
            }
            else if (numVolumeParts == 0)
            {
                DestroyVolumeCache();
                return;
            }

            _volumeCache.GenerateFromParts(session, ParentAsset, volumeParts);
        }
		//	LOGIC -----------------------------------------------------------------------------------------------------

		public static List<HEU_VolumeCache> UpdateVolumeCachesFromParts(HEU_SessionBase session, HEU_GeoNode ownerNode, List<HEU_PartData> volumeParts, List<HEU_VolumeCache> volumeCaches)
		{
			HEU_HoudiniAsset parentAsset = ownerNode.ParentAsset;

			foreach (HEU_VolumeCache cache in volumeCaches)
			{
				// Remove current volume caches from parent asset.
				// These get added back in below.
				parentAsset.RemoveVolumeCache(cache);

				// Mark the cache for updating
				cache.StartUpdateLayers();
			}

			// This will keep track of volume caches still in use
			List<HEU_VolumeCache> updatedCaches = new List<HEU_VolumeCache>();

			int numParts = volumeParts.Count;
			for (int i = 0; i < numParts; ++i)
			{
				// Get the tile index, if it exists, for this part
				HAPI_AttributeInfo tileAttrInfo = new HAPI_AttributeInfo();
				int[] tileAttrData = new int[0];
				HEU_GeneralUtility.GetAttribute(session, ownerNode.GeoID, volumeParts[i].PartID, HEU_Defines.HAPI_HEIGHTFIELD_TILE_ATTR, ref tileAttrInfo, ref tileAttrData, session.GetAttributeIntData);
				if (tileAttrData != null && tileAttrData.Length > 0)
				{
					//Debug.LogFormat("Tile: {0}", tileAttrData[0]);

					int tile = tileAttrData[0];
					HEU_VolumeCache volumeCache = null;

					// Find cache in updated list
					for (int j = 0; j < updatedCaches.Count; ++j)
					{
						if (updatedCaches[j] != null && updatedCaches[j].TileIndex == tile)
						{
							volumeCache = updatedCaches[j];
							break;
						}
					}

					if (volumeCache != null)
					{
						volumeCache.UpdateLayerFromPart(session, volumeParts[i]);

						// Skip adding new cache since already found in updated list
						continue;
					}

					// Find existing cache in old list
					if (volumeCaches != null && volumeCaches.Count > 0)
					{
						for(int j = 0; j < volumeCaches.Count; ++j)
						{
							if (volumeCaches[j] != null && volumeCaches[j].TileIndex == tile)
							{
								volumeCache = volumeCaches[j];
								break;
							}
						}
					}

					// Create new cache for this tile if not found
					if (volumeCache == null)
					{
						volumeCache = ScriptableObject.CreateInstance<HEU_VolumeCache>();
						volumeCache.Initialize(ownerNode, tile);
						volumeCache.StartUpdateLayers();
					}

					volumeCache.UpdateLayerFromPart(session, volumeParts[i]);

					if (!updatedCaches.Contains(volumeCache))
					{
						updatedCaches.Add(volumeCache);
					}
				}
				else
				{
					// No tile index. Most likely a single terrain tile.

					HEU_VolumeCache volumeCache = null;

					if (updatedCaches.Count == 0)
					{
						// Create a single volume cache, or use existing if it was just 1.
						// If more than 1 volume cache exists, this will recreate a single one

						if (volumeCaches == null || volumeCaches.Count != 1)
						{
							volumeCache = ScriptableObject.CreateInstance<HEU_VolumeCache>();
							volumeCache.Initialize(ownerNode, 0);
							volumeCache.StartUpdateLayers();
						}
						else if (volumeCaches.Count == 1)
						{
							// Keep the single volumecache
							volumeCache = volumeCaches[0];
						}

						if (!updatedCaches.Contains(volumeCache))
						{
							updatedCaches.Add(volumeCache);
						}
					}
					else
					{
						// Reuse the updated cache
						volumeCache = updatedCaches[0];
					}

					volumeCache.UpdateLayerFromPart(session, volumeParts[i]);
				}
			}

			foreach (HEU_VolumeCache cache in updatedCaches)
			{
				// Add to parent for UI and preset
				parentAsset.AddVolumeCache(cache);

				// Finish update by keeping just the layers in use for each volume cache.
				cache.FinishUpdateLayers();
			}

			return updatedCaches;
		}
Example #9
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]);
				}
			}
		}
Example #11
0
		public void GenerateGeometry(HEU_SessionBase session)
		{
			// Volumes could come in as a geonode + part for each heightfield layer.
			// Otherwise the other geo types can be done individually.

			bool bResult = false;

			List<HEU_PartData> meshParts = new List<HEU_PartData>();
			List<HEU_PartData> volumeParts = new List<HEU_PartData>();

			List<HEU_PartData> partsToDestroy = new List<HEU_PartData>();

			HEU_HoudiniAsset parentAsset = ParentAsset;

			foreach (HEU_GeoNode geoNode in _geoNodes)
			{
				geoNode.GetPartsByOutputType(meshParts, volumeParts);
			}

			// Meshes
			foreach (HEU_PartData part in meshParts)
			{
				bResult = part.GenerateMesh(session, parentAsset.GenerateUVs, parentAsset.GenerateTangents, parentAsset.GenerateNormals, parentAsset.UseLODGroups);
				if (!bResult)
				{
					partsToDestroy.Add(part);
				}
			}

#if TERRAIN_SUPPORTED
			// Volumes
			// Each layer in the volume is retrieved as a volume part, in the display geo node. 
			// But we need to handle all layers as 1 terrain output in Unity, with 1 height layer and 
			// other layers as alphamaps.
			if (volumeParts.Count > 0)
			{
				HEU_PartData heightLayerPart = null;
				HEU_VolumeCache volumeCache = new HEU_VolumeCache();
				volumeCache.GenerateTerrainFromParts(session, volumeParts, ParentAsset, out heightLayerPart);

				// Remove volume parts that are not the height layer (even if heightLayerPart is null)
				foreach (HEU_PartData part in volumeParts)
				{
					if (part != heightLayerPart)
					{
						partsToDestroy.Add(part);
					}
				}
			}
#endif

			int numPartsToDestroy = partsToDestroy.Count;
			for(int i = 0; i < numPartsToDestroy; ++i)
			{
				HEU_GeoNode parentNode = partsToDestroy[i].ParentGeoNode;
				if (parentNode != null)
				{
					parentNode.RemoveAndDestroyPart(partsToDestroy[i]);
				}
				else
				{
					HEU_PartData.DestroyPart(partsToDestroy[i]);
				}
			}
			partsToDestroy.Clear();

			ApplyObjectTransformToGeoNodes();

			// Set visibility
			bool bIsVisible = IsVisible();
			foreach (HEU_GeoNode geoNode in _geoNodes)
			{
				geoNode.CalculateVisiblity(bIsVisible);
			}

			// Create editable attributes.
			// This should happen after visibility has been calculated above
			// since we need to show/hide the intermediate geometry during painting.
			foreach (HEU_PartData part in meshParts)
			{
				if (part.ParentGeoNode.IsIntermediateOrEditable())
				{
					part.SetupAttributeGeometry(session);
				}
			}
		}
Example #12
0
		private void GenerateTerrain(List<HEU_LoadBufferVolume> terrainBuffers)
		{
			Transform parent = this.gameObject.transform;

			int numVolues = terrainBuffers.Count;
			for(int t = 0; t < numVolues; ++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);

					terrain.terrainData = new TerrainData();
					TerrainData terrainData = terrain.terrainData;
					collider.terrainData = terrainData;

					int heightMapSize = terrainBuffers[t]._heightMapSize;

					terrainData.heightmapResolution = heightMapSize;
					if (terrainData.heightmapResolution != heightMapSize)
					{
						Debug.LogErrorFormat("Unsupported terrain size: {0}", heightMapSize);
						continue;
					}

					terrainData.baseMapResolution = heightMapSize;
					terrainData.alphamapResolution = heightMapSize;

					const int resolutionPerPatch = 128;
					terrainData.SetDetailResolution(resolutionPerPatch, resolutionPerPatch);

					terrainData.SetHeights(0, 0, terrainBuffers[t]._heightMap);

					terrainData.size = new Vector3(terrainBuffers[t]._terrainSizeX, terrainBuffers[t]._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 at time of this implementation the new Unity terrain
					// is still in beta. Therefore, the following layer creation is subject
					// to change.

					TerrainLayer[] terrainLayers = new TerrainLayer[numLayers];
					for (int m = 0; m < numLayers; ++m)
					{
						terrainLayers[m] = new TerrainLayer();

						HEU_LoadBufferVolumeLayer layer = terrainBuffers[t]._layers[m];

						if (!string.IsNullOrEmpty(layer._diffuseTexturePath))
						{
							// Using Resources.Load is much faster than AssetDatabase.Load
							//terrainLayers[m].diffuseTexture = HEU_MaterialFactory.LoadTexture(layer._diffuseTexturePath);
							terrainLayers[m].diffuseTexture = Resources.Load<Texture2D>(layer._diffuseTexturePath);
						}
						if (terrainLayers[m].diffuseTexture == null)
						{
							terrainLayers[m].diffuseTexture = defaultTexture;
						}

						terrainLayers[m].diffuseRemapMin = Vector4.zero;
						terrainLayers[m].diffuseRemapMax = Vector4.one;

						if (!string.IsNullOrEmpty(layer._maskTexturePath))
						{
							// Using Resources.Load is much faster than AssetDatabase.Load
							//terrainLayers[m].maskMapTexture = HEU_MaterialFactory.LoadTexture(layer._maskTexturePath);
							terrainLayers[m].maskMapTexture = Resources.Load<Texture2D>(layer._maskTexturePath);
						}

						terrainLayers[m].maskMapRemapMin = Vector4.zero;
						terrainLayers[m].maskMapRemapMax = Vector4.one;

						terrainLayers[m].metallic = layer._metallic;

						if (!string.IsNullOrEmpty(layer._normalTexturePath))
						{
							terrainLayers[m].normalMapTexture = HEU_MaterialFactory.LoadTexture(layer._normalTexturePath);
						}

						terrainLayers[m].normalScale = layer._normalScale;

						terrainLayers[m].smoothness = layer._smoothness;
						terrainLayers[m].specular = layer._specularColor;
						terrainLayers[m].tileOffset = layer._tileOffset;

						if (layer._tileSize.magnitude == 0f && terrainLayers[m].diffuseTexture != null)
						{
							// Use texture size if tile size is 0
							layer._tileSize = new Vector2(terrainLayers[m].diffuseTexture.width, terrainLayers[m].diffuseTexture.height);
						}
						terrainLayers[m].tileSize = layer._tileSize;
					}
					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

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

					//string assetPath = HEU_AssetDatabase.CreateAssetCacheFolder("terrainData");
					//AssetDatabase.CreateAsset(terrainData, assetPath);
					//Debug.Log("Created asset data at " + assetPath);

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

					SetOutputVisiblity(terrainBuffers[t]);
				}
			}
		}
        public void ProcessVolumeParts(HEU_SessionBase session, List <HEU_PartData> volumeParts, bool bRebuild)
        {
            int numVolumeParts = volumeParts.Count;

            if (numVolumeParts == 0)
            {
                DestroyVolumeCache();
            }
            else if (_volumeCaches == null)
            {
                _volumeCaches = new List <HEU_VolumeCache>();
            }

            // First update volume caches. Each volume cache represents a set of terrain layers grouped by tile index.
            // Therefore each volume cache represents a potential Unity Terrain (containing layers)
            _volumeCaches = HEU_VolumeCache.UpdateVolumeCachesFromParts(session, this, volumeParts, _volumeCaches);

            // Heightfield scatter nodes come in as mesh-type parts with attribute instancing.
            // So process them here to get all the tree/detail instance scatter information.
            int numParts = _parts.Count;

            for (int i = 0; i < numParts; ++i)
            {
                // Find the terrain tile (use primitive attr). Assume 0 tile if not set (i.e. not split into tiles)
                int terrainTile = 0;
                HAPI_AttributeInfo tileAttrInfo = new HAPI_AttributeInfo();
                int[] tileAttrData = new int[0];
                if (HEU_GeneralUtility.GetAttribute(session, GeoID, _parts[i].PartID, HEU_Defines.HAPI_HEIGHTFIELD_TILE_ATTR, ref tileAttrInfo, ref tileAttrData, session.GetAttributeIntData))
                {
                    if (tileAttrData != null && tileAttrData.Length > 0)
                    {
                        terrainTile = tileAttrData[0];
                    }
                }

                // Find the volumecache associated with this part using the terrain tile index
                HEU_VolumeCache volumeCache = GetVolumeCacheByTileIndex(terrainTile);
                if (volumeCache == null)
                {
                    continue;
                }

                HEU_VolumeLayer volumeLayer = volumeCache.GetLayer(_parts[i].GetVolumeLayerName());
                if (volumeLayer != null && volumeLayer._layerType == HFLayerType.DETAIL)
                {
                    // Clear out outputs since it might have been created when the part was created.
                    _parts[i].DestroyAllData();

                    volumeCache.PopulateDetailPrototype(session, GeoID, _parts[i].PartID, volumeLayer);
                }
                else if (_parts[i].IsAttribInstancer())
                {
                    HAPI_AttributeInfo treeInstAttrInfo = new HAPI_AttributeInfo();
                    if (HEU_GeneralUtility.GetAttributeInfo(session, GeoID, _parts[i].PartID, HEU_Defines.HEIGHTFIELD_TREEINSTANCE_PROTOTYPEINDEX, ref treeInstAttrInfo))
                    {
                        if (treeInstAttrInfo.exists && treeInstAttrInfo.count > 0)
                        {
                            // Clear out outputs since it might have been created when the part was created.
                            _parts[i].DestroyAllData();

                            // Mark the instancers as having been created so that the object instancer step skips this.
                            _parts[i].ObjectInstancesBeenGenerated = true;

                            // Now populate scatter trees based on attributes on this part
                            volumeCache.PopulateScatterTrees(session, GeoID, _parts[i].PartID, treeInstAttrInfo.count);
                        }
                    }
                }
            }

            // Now generate the terrain for each volume cache
            foreach (HEU_VolumeCache cache in _volumeCaches)
            {
                cache.GenerateTerrainWithAlphamaps(session, ParentAsset, bRebuild);

                cache.IsDirty = false;
            }
        }