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