Beispiel #1
0
		/// <summary>
		/// Copy the file of the given srcAsset into the given targetPath, which must be absolute.
		/// If targetPath doesn't have a file name, the srcAsset's file name will be used.
		/// </summary>
		/// <param name="srcAsset">Source asset to copy</param>
		/// <param name="targetPath">Absolute path of destination</param>
		/// <param name="type">Type of the asset</param>
		/// <returns></returns>
		public static Object CopyAndLoadAssetAtGivenPath(Object srcAsset, string targetPath, System.Type type)
		{
#if UNITY_EDITOR
			string srcAssetPath = GetAssetPath(srcAsset);
			if (!string.IsNullOrEmpty(srcAssetPath))
			{
				string targetFolderPath = HEU_Platform.GetFolderPath(targetPath);
				CreatePathWithFolders(targetFolderPath);

				string targetFileName = HEU_Platform.GetFileName(targetPath);
				if (string.IsNullOrEmpty(targetFileName))
				{
					Debug.LogErrorFormat("Copying asset failed. Destination path must end with a file name: {0}!", targetPath);
					return null;
				}

				if (CopyAsset(srcAssetPath, targetPath))
				{
					// Refresh database as otherwise we won't be able to load it in the next line.
					SaveAndRefreshDatabase();

					return LoadAssetAtPath(targetPath, type);
				}
				else
				{
					Debug.LogErrorFormat("Failed to copy and load asset from {0} to {1}!", srcAssetPath, targetPath);
				}
			}
			return null;
#else
			// TODO RUNTIME: AssetDatabase is not supported at runtime. Do we need to support this for runtime?
			Debug.LogWarning(HEU_Defines.HEU_USERMSG_NONEDITOR_NOT_SUPPORTED);
			return null;
#endif
		}
        private void GenerateTerrain(HAPI_NodeId cookNodeId, List <HEU_LoadBufferVolume> terrainBuffers)
        {
            HEU_SessionBase session = GetHoudiniSession(true);
            Transform       parent  = this.gameObject.transform;

            // Directory to store generated terrain files.
            string outputTerrainpath = GetOutputCacheDirectory();

            outputTerrainpath = HEU_Platform.BuildPath(outputTerrainpath, "Terrain");

            int numVolumes = terrainBuffers.Count;

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

                    HAPI_PartId partId = terrainBuffers[t]._id;
                    ApplyAttributeModifiersOnGameObjectOutput(session, cookNodeId, partId, ref newGameObject);

                    Transform newTransform = newGameObject.transform;
                    newTransform.parent = parent;

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

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

#if !HEU_TERRAIN_COLLIDER_DISABLED
                    TerrainCollider collider = HEU_GeneralUtility.GetOrCreateComponent <TerrainCollider>(newGameObject);
#endif
                    // The TerrainData and TerrainLayer files needs to be saved out if we create them.
                    // Try user specified path, otherwise use the cache folder
                    string exportTerrainDataPath = terrainBuffers[t]._terrainDataExportPath;
                    if (string.IsNullOrEmpty(exportTerrainDataPath))
                    {
                        // This creates the relative folder path from the Asset's cache folder: {assetCache}/{geo name}/Terrain/Tile{tileIndex}/...
                        exportTerrainDataPath = HEU_Platform.BuildPath(outputTerrainpath, HEU_Defines.HEU_FOLDER_TERRAIN, HEU_Defines.HEU_FOLDER_TILE + terrainBuffers[t]._tileIndex);
                    }

                    bool bFullExportTerrainDataPath = HEU_Platform.DoesFileExist(exportTerrainDataPath);

                    if (!string.IsNullOrEmpty(terrainBuffers[t]._terrainDataPath))
                    {
                        // Load the source TerrainData, then make a unique copy of it in the cache folder

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

                        if (bFullExportTerrainDataPath)
                        {
                            terrain.terrainData = HEU_AssetDatabase.CopyAndLoadAssetAtGivenPath(sourceTerrainData, exportTerrainDataPath, typeof(TerrainData)) as TerrainData;
                        }
                        else
                        {
                            terrain.terrainData = HEU_AssetDatabase.CopyUniqueAndLoadAssetAtAnyPath(sourceTerrainData, exportTerrainDataPath, typeof(TerrainData)) as TerrainData;
                        }

                        if (terrain.terrainData != null)
                        {
                            // Store path so that it can be deleted on clean up
                            AddGeneratedOutputFilePath(HEU_AssetDatabase.GetAssetPath(terrain.terrainData));
                        }
                    }

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

                        if (bFullExportTerrainDataPath)
                        {
                            string folderPath = HEU_Platform.GetFolderPath(exportTerrainDataPath, true);
                            HEU_AssetDatabase.CreatePathWithFolders(folderPath);
                            HEU_AssetDatabase.CreateAsset(terrain.terrainData, exportTerrainDataPath);
                        }
                        else
                        {
                            string assetPathName = "TerrainData" + HEU_Defines.HEU_EXT_ASSET;
                            HEU_AssetDatabase.CreateObjectInAssetCacheFolder(terrain.terrainData, exportTerrainDataPath, null, assetPathName, typeof(TerrainData));
                        }
                    }
                    TerrainData terrainData = terrain.terrainData;

#if !HEU_TERRAIN_COLLIDER_DISABLED
                    collider.terrainData = terrainData;
#endif

                    HEU_TerrainUtility.SetTerrainMaterial(terrain, terrainBuffers[t]._specifiedTerrainMaterialName);

#if UNITY_2018_3_OR_NEWER
                    terrain.allowAutoConnect = true;
                    // This has to be set after setting material
                    terrain.drawInstanced = true;
#endif

                    int heightMapSize = terrainBuffers[t]._heightMapWidth;

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

                    // The terrainData.baseMapResolution is not set here, but rather left to whatever default Unity uses
                    // The terrainData.alphamapResolution is set later when setting the alphamaps.

                    // 32 is the default for resolutionPerPatch
                    const int detailResolution   = 1024;
                    const int resolutionPerPatch = 32;
                    terrainData.SetDetailResolution(detailResolution, resolutionPerPatch);

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

                    // Note that Unity uses a default height range of 600 when a flat terrain is created.
                    // Without a non-zero value for the height range, user isn't able to draw heights.
                    // Therefore, set 600 as the value if height range is currently 0 (due to flat heightfield).
                    float heightRange = terrainBuffers[t]._heightRange;
                    if (heightRange == 0)
                    {
                        heightRange = 600;
                    }

                    terrainData.size = new Vector3(terrainBuffers[t]._terrainSizeX, heightRange, terrainBuffers[t]._terrainSizeY);

                    terrain.Flush();

                    // Set position
                    HAPI_Transform hapiTransformVolume = new HAPI_Transform(true);
                    hapiTransformVolume.position[0] += terrainBuffers[t]._position[0];
                    hapiTransformVolume.position[1] += terrainBuffers[t]._position[1];
                    hapiTransformVolume.position[2] += terrainBuffers[t]._position[2];
                    HEU_HAPIUtility.ApplyLocalTransfromFromHoudiniToUnity(ref hapiTransformVolume, newTransform);

                    // Set layers
                    Texture2D defaultTexture = HEU_VolumeCache.LoadDefaultSplatTexture();
                    int       numLayers      = terrainBuffers[t]._splatLayers.Count;

#if UNITY_2018_3_OR_NEWER
                    // Create TerrainLayer for each heightfield layer.
                    // Note that height and mask layers are ignored (i.e. not created as TerrainLayers).
                    // Since height layer is first, only process layers from 2nd index onwards.
                    if (numLayers > 1)
                    {
                        // Keep existing TerrainLayers, and either update or append to them
                        TerrainLayer[] existingTerrainLayers = terrainData.terrainLayers;

                        // Total layers are existing layers + new alpha maps
                        List <TerrainLayer> finalTerrainLayers = new List <TerrainLayer>(existingTerrainLayers);

                        for (int m = 1; m < numLayers; ++m)
                        {
                            TerrainLayer terrainlayer = null;

                            int terrainLayerIndex = -1;

                            bool bSetTerrainLayerProperties = true;

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

                            // Look up TerrainLayer file via attribute if user has set it
                            if (!string.IsNullOrEmpty(layer._layerPath))
                            {
                                terrainlayer = HEU_AssetDatabase.LoadAssetAtPath(layer._layerPath, typeof(TerrainLayer)) as TerrainLayer;
                                if (terrainlayer == null)
                                {
                                    Debug.LogWarningFormat("TerrainLayer, set via attribute, not found at: {0}", layer._layerPath);
                                    continue;
                                }
                                else
                                {
                                    // Always check if its part of existing list so as not to add it again
                                    terrainLayerIndex = HEU_TerrainUtility.GetTerrainLayerIndex(terrainlayer, existingTerrainLayers);
                                }
                            }

                            if (terrainlayer == null)
                            {
                                terrainlayer      = new TerrainLayer();
                                terrainLayerIndex = finalTerrainLayers.Count;
                                finalTerrainLayers.Add(terrainlayer);
                            }
                            else
                            {
                                // For existing TerrainLayer, make a copy of it if it has custom layer attributes
                                // because we don't want to change the original TerrainLayer.
                                if (layer._hasLayerAttributes)
                                {
                                    // Copy the TerrainLayer file
                                    TerrainLayer prevTerrainLayer = terrainlayer;
                                    terrainlayer = HEU_AssetDatabase.CopyAndLoadAssetAtAnyPath(terrainlayer, outputTerrainpath, typeof(TerrainLayer), true) as TerrainLayer;
                                    if (terrainlayer != null)
                                    {
                                        if (terrainLayerIndex >= 0)
                                        {
                                            // Update the TerrainLayer reference in the list with this copy
                                            finalTerrainLayers[terrainLayerIndex] = terrainlayer;
                                        }
                                        else
                                        {
                                            // Newly added
                                            terrainLayerIndex = finalTerrainLayers.Count;
                                            finalTerrainLayers.Add(terrainlayer);
                                        }

                                        // Store path for clean up later
                                        AddGeneratedOutputFilePath(HEU_AssetDatabase.GetAssetPath(terrainlayer));
                                    }
                                    else
                                    {
                                        Debug.LogErrorFormat("Unable to copy TerrainLayer '{0}' for generating Terrain. "
                                                             + "Using original TerrainLayer. Will not be able to set any TerrainLayer properties.", layer._layerName);
                                        terrainlayer = prevTerrainLayer;
                                        bSetTerrainLayerProperties = false;
                                        // Again, continuing on to keep proper indexing.
                                    }
                                }
                                else
                                {
                                    // Could be a layer in Assets/ but not part of existing layers in TerrainData
                                    terrainLayerIndex = finalTerrainLayers.Count;
                                    finalTerrainLayers.Add(terrainlayer);
                                    bSetTerrainLayerProperties = false;
                                }
                            }

                            if (bSetTerrainLayerProperties)
                            {
                                if (!string.IsNullOrEmpty(layer._diffuseTexturePath))
                                {
                                    terrainlayer.diffuseTexture = HEU_MaterialFactory.LoadTexture(layer._diffuseTexturePath);
                                }
                                if (terrainlayer.diffuseTexture == null)
                                {
                                    terrainlayer.diffuseTexture = defaultTexture;
                                }

                                terrainlayer.diffuseRemapMin = Vector4.zero;
                                terrainlayer.diffuseRemapMax = Vector4.one;

                                if (!string.IsNullOrEmpty(layer._maskTexturePath))
                                {
                                    terrainlayer.maskMapTexture = HEU_MaterialFactory.LoadTexture(layer._maskTexturePath);
                                }

                                terrainlayer.maskMapRemapMin = Vector4.zero;
                                terrainlayer.maskMapRemapMax = Vector4.one;

                                terrainlayer.metallic = layer._metallic;

                                if (!string.IsNullOrEmpty(layer._normalTexturePath))
                                {
                                    terrainlayer.normalMapTexture = HEU_MaterialFactory.LoadTexture(layer._normalTexturePath);
                                }

                                terrainlayer.normalScale = layer._normalScale;

                                terrainlayer.smoothness = layer._smoothness;
                                terrainlayer.specular   = layer._specularColor;
                                terrainlayer.tileOffset = layer._tileOffset;

                                if (layer._tileSize.magnitude == 0f && terrainlayer.diffuseTexture != null)
                                {
                                    // Use texture size if tile size is 0
                                    layer._tileSize = new Vector2(terrainlayer.diffuseTexture.width, terrainlayer.diffuseTexture.height);
                                }
                                terrainlayer.tileSize = layer._tileSize;
                            }
                        }
                        terrainData.terrainLayers = finalTerrainLayers.ToArray();
                    }
#else
                    // Need to create SplatPrototype for each layer in heightfield, representing the textures.
                    SplatPrototype[] splatPrototypes = new SplatPrototype[numLayers];
                    for (int m = 0; m < numLayers; ++m)
                    {
                        splatPrototypes[m] = new SplatPrototype();

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

                        Texture2D diffuseTexture = null;
                        if (!string.IsNullOrEmpty(layer._diffuseTexturePath))
                        {
                            diffuseTexture = HEU_MaterialFactory.LoadTexture(layer._diffuseTexturePath);
                        }
                        if (diffuseTexture == null)
                        {
                            diffuseTexture = defaultTexture;
                        }
                        splatPrototypes[m].texture = diffuseTexture;

                        splatPrototypes[m].tileOffset = layer._tileOffset;
                        if (layer._tileSize.magnitude == 0f && diffuseTexture != null)
                        {
                            // Use texture size if tile size is 0
                            layer._tileSize = new Vector2(diffuseTexture.width, diffuseTexture.height);
                        }
                        splatPrototypes[m].tileSize = layer._tileSize;

                        splatPrototypes[m].metallic   = layer._metallic;
                        splatPrototypes[m].smoothness = layer._smoothness;

                        if (!string.IsNullOrEmpty(layer._normalTexturePath))
                        {
                            splatPrototypes[m].normalMap = HEU_MaterialFactory.LoadTexture(layer._normalTexturePath);
                        }
                    }
                    terrainData.splatPrototypes = splatPrototypes;
#endif

                    // Set the splatmaps
                    if (terrainBuffers[t]._splatMaps != null)
                    {
                        // Set the alphamap size before setting the alphamaps to get correct scaling
                        // The alphamap size comes from the first alphamap layer
                        int alphamapResolution = terrainBuffers[t]._heightMapWidth;
                        if (numLayers > 1)
                        {
                            alphamapResolution = terrainBuffers[t]._splatLayers[1]._heightMapWidth;
                        }
                        terrainData.alphamapResolution = alphamapResolution;

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

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

                    // Set the detail layers
                    if (terrainBuffers[t]._detailPrototypes != null)
                    {
                        HEU_TerrainUtility.ApplyDetailLayers(terrain, terrainData, terrainBuffers[t]._detailProperties,
                                                             terrainBuffers[t]._detailPrototypes, terrainBuffers[t]._detailMaps);
                    }

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

                    SetOutputVisiblity(terrainBuffers[t]);
                }
            }
        }