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